使用数据库存图片

作者:八神 | 分类: 大话技术 | 标签: | 日期:2010-03-11

图片是网站上很重要的资源,用户发布的产品图片,用户的logo,AV男,兽兽女,犀利哥等等等等,一个稍具规模的网站,图片的数量可能是千万级,这种资源的特点就是文件小,数量大,每个文件在几字节到几K不等,所以针对图片的访问,基本是非常离散的IO,考验的是系统的磁盘并发和CPU处理能力

一般网站,图片都是存放专门的图片服务器,可集中也可以分布式,比如有条件的可以购买昂贵的NAS存储,由主机拖着,以NFS或者HTTP的方式,供前面的应用访问,或者使用多台廉价PC,图片分布打散到每个机器,前台应用解决图片存取和访问策略,以便充分利用所有资源,在应用与图片服务器中间还可能加一层cache,来缓冲前台的访问压力

上面所说的方法,弊端是有很多的
1.文件系统一定是要使用的,为了管理数千万的图片,必须进行目录分层,因为一个目录下不可能存放太多的文件,前期的目录规划要考虑后期的扩展,还有图片分布均匀,这样做下来,往往目录的深度会达到5层甚至7层
2.数据迁移,备份怎么做?高级的NAS存储,有自己的卷复制,但这个粒度太粗,如果要细分到底层或中间层,会有点力不从心,对于这种大数据量的小文件拷贝,PC也是非常吃力
3.每一个图片的访问,基本会做5-7次的目录跳转,转换到磁盘,也可能有10次物理IO了,在并发量上来的时候,磁盘会是个瓶颈,当然,分布式是个方向

这里想到了另外一种方法,利用数据库来存放图片,存储的方式就是现在最流行的key-value

create table mypic
(
key number not null,
pic blob
);

create index ind_picid on mypic(key);

key是图片名称,事先最好统一规划一下,使用number数字来命名,并针对key建立索引
VALUE就是图片内容,用blob来保存
访问一个图片的方式就是:
获取图片名称  数据key
走key上的索引,定位到记录表记录
根据表记录,定位到图片的blob,并读取

这个方法的优点:
1.单个图片的访问路径缩短,数字索引比较小,分区做的好的话可能小到两层,从索引到表,到blob段,大概是4-5跳
并且KEY是区分度非常高的数据类型,在索引每层的横向检索中,不会超过1个数据块,而文件目录结构中,子目录繁多,
要遍历这层的inode后,才知道具体跳转的下层位置
2.备份方式比较灵活,可以基于整个数据库,或者单独的表,数据的迁移,删除,都是基于表级别的,比较直观,方便
3.可以在数据库层面,考虑图片的水平拆分,垂直拆分,分表,分库,都不错
4.数据库的复制技术可以派上用场,读写分离

这里数据库完全是当成一个KEY-VALUE的存储在用,我们可以考虑将一些廉价的PC堆在一起,做成一个picdb的群集,
大致画了一个草图,当然在WEB与picdb间应该还有层cache的,这个方法是YY出来的,可能很多地方不成熟,但SY强身,YY强国,没有想法,哪来的动力?欢迎各位专业人士拍砖

ppp1

14人发表了评论  ↓发表评论↓
  • 检测到非法字符。(⊙ˍ⊙)

    Euy @ March 12, 2010 |

  • 学习了,感谢八神

    谭理想 @ March 12, 2010 |

  • 这么访问一次数据库,从索引读到文件,又该有多少次io?用了数据库,显然不可能用web服务器直接访问,还得通过程序来读取输出,这又多了一层,从效率上来说不会有优势。

    文件备份的问题其实有不少方案,比如mogilefs这类分布式文件系统,或者自己做一个增量的复制也不算太麻烦。

    神仙 @ March 12, 2010 |

  • 索引到文件,IO次数看索引的层次,还有最终这个图片的大小,计算下来大概在5次左右,程序读取图片,确实需要由数据库来处理blob信息来返回,这个没经过测试,损耗究竟有多少?现在PC的CPU运算能力已经比较强了,相信处理起来不会有太大的问题

    其实对于小图片,也有做法是N多的图片合成一个大的文件,然后用文件里面的偏移量寻址来访问大文件里的图片,这个思路和我想的方式是一样的,只不过我是用数据库自己的存储,解析方式完成了这个功能而已

    八神 @ March 13, 2010 |

  • (─.─||)(─.─||)
    精华帖!!文字是如此的诙谐油墨,还来张手绘稿,还有非法关键字。

    这文章8精华,谁是精华?

    vogts @ March 15, 2010 |

  • 图片存在数据库中会有效率的问题吧,还浏览器不能缓存图片吧?

    liriugang @ March 23, 2010 |

  • 用数据库存放图片文件确不是很靠谱,中间通过程序中转始终没有现存的图片服务器如:lighthttpd或nginx来得高效,正如楼上说的一样,没有有效利用浏览器的客户端缓存,另外进行图片转储的时候还需要程序调用重新生成图片文件。这样做没有任何优势!

    Yong @ March 25, 2010 |

  • 这篇帖子说的是图片的存储与管理的问题,性能上面,还需要cache的配合,浏览器的客户端缓存,这个不能做为最终的存储来使用,因为总会失效,或者被击穿,lighthttpd,nginx最终也是需要将压力推给底层的文件系统,到磁盘的,大家不要拿一个完善的图片系统来跟他比,要裸奔,当然我不大懂前台图片CACHE那层的技术,呵呵

    八神 @ March 29, 2010 |

  • Yong说得和斑竹说的是两回事,斑竹是说可以把图片放到数据库中,前面肯定还有一些图片apache等一些中间的缓冲,而数据库存图片是为了做图片的持久化和高可用性方案。这个想法,前面我也想过,也与一些同事交流过。当图片的数量很多时,就需要建多级目录对这些图片进行管理,当图片的数量上亿后,而图片又很小时,如果放在文件系统中,就会发生访问这样的/dir1/dir2/dir3/dir4/pic000xxxx.jpg的过程中,经过目录的访问代价就会高过实际文件内容的访问代价,同时如果想调整目录结构和把文件拷贝出来做备份也会很慢。而通过数据库存储这些图片则不会存在这些问题,同时数据库一般都提供了很好的备份高可用方案,可以保证数据的零丢失,所以使用数据库是一种简单解决问题的一个方法。对于使用blob字段存数据,如果图片很小时,可以直接使用raw字段存,每个raw字段大小可以为4000个字节,对于几十k的小图片,可以分成多条存储:
    create table mypic
    (
    key number not null,
    piece int,
    pic raw(4000)
    );

    其实最理想的方案是使用基于key-value的分布式系统存图片,不过这需要考虑学习key-value系统的代价,对于已经有了数据库经验的团队来说,这个数据库方法不失是一个好办法。

    osdba @ April 4, 2010 |

  • 把非结构化的图片转化为结构化存储,最重要的其实是应用上的改变和适应。传统方式还是有他自身的优势的,短期内还是很强势。kv固然好,但是冗余度没有传统那么好做,快照和复制上也有问题。另外,kv存储的性能波动非常大,而传统存储非常稳定。从目前的情况来看,kv前途还是很光明。

    qqeyes @ May 24, 2010 |

  • 有没有哪位大侠有过这类经验的啊?

    memo @ June 15, 2010 |

  • 正在考虑用mogodb来存储文件,实现出来的效果跟LZ描述的基本一样

    夜雨 @ July 15, 2010 |

  • pi飘过,学习。。。>﹏<

    网购商城 @ October 8, 2010 |

  • 根绝我的经验,图片存在数据库里面,客户端浏览器也是一样缓存的,FIREFOX和IE6是这样的,没有专门做过实验,以前做项目的时候遇到过。

    nangoxin @ October 10, 2010 |

表情:<( ̄︶ ̄)> | (⊙ˍ⊙) | >﹏< | b( ̄▽ ̄)d | (─.─||) | (^_-)

[ Ctrl+Enter提交 ]

DBA