couchDB是这两年很受geek追捧的数据库,作者曾是lotus开发人员。与传统的关系型数据库不同, 它号称自己是文档数据库。所谓文档数据库,并不是说它只能存储文本,事实上因为它是一种schemal-less的概念。用过关系型数据库的同学都知道, 数据表里定义的每一个字段都定义为一种类型:无论是int,char,datetime。但couchDB的字段只有三个:文档ID、文档版本号和内容。 内容字段可以看到是一个text类型的文本,里面可以随意定义数据,而不用关注数据类型,但数据必须以json的形式表示并存放。例如一个表述用户的文档 可以表示为:[_id:1001, _rev:1-32443289, {'name':'wentrue', 'location':'beijing'}]。couchDB的底层是erlang语言,以RESTful API的格式提供服务,couchDB所有的读写能力都可以通过简单的调用它的HTTP请求来实现。正因为采用那么一种统一且简洁的服务接口,可以很方便地开发各种语言的客户端,以方便不同程序员的使用。
couchDB的文档不多,基本上主体都在它网站的overview和wiki了。这里按照我的理解组织一遍,不敢冒”大全“之名,借”小全“一用尚可。 以下以几个关键词为标签简要叙述。
优点:
couchDB的主要特点在于易用性及并发性。后者我的认识主要是来自erlang,因为erlang是以易并行实现而著称的,我自己并没有测试 过。但对于易用性我是有着深刻体会。只要一搭好服务,你不但拥有了一个听任你调遣的数据服务端,还拥有一个简洁web server,如果你是在本地部署的,在浏览器上访问http://localhost:5984/_utils/,你就可以看到一个管理与查询的后台, 在那个后台,你基本能实现用其它客户端能实现的所有事情。也就是说,即便你不懂编程语言,你可以在这个管理平台自由发挥,当然如果你懂一些 javascript,那你就可以把couchDB玩转了。
这个易用性意味着什么?让我们作个假设,你是一个网站开发人员,你有大量的数据需要存储,但你又不想跟复杂的后台逻辑打交道,或许你还不想过多地进 行后台维护,那么用couchDB,你可以直接用js调用数据,然后结合html+css把数据展现出来,再通过js把数据写回去,这就实现了一个简单的内容发布系统,没有任何后台架构。实际上已经有很多用couchDB实现的网站。
技术概述:
couchDB的底层是一个B-tree的存储结构,为提高效率,所有的数据的插入或更新都是直接在树的叶子节点添加,不删除旧节点,通过版本号来 确定最新的数据--版本号还能用来解决并发写的冲突。所以数据文件会越来越大,可以在适当地时间运行compact过程或replication过程,会 删除旧文件,使得数据文件得到压缩。
与mysql的对比(是什么原因促使我把眼光暂时离开mysql):
1、couchDB的属性可以灵活增删,要增加一个新属性只需要往数据字段多写入一个属性即可。mysql在数据量大了之后,再增删字段会比较耗费 时间,在线操作更是让人难以忍受的(视数据量大小有可能要锁表几十分钟到一天);
2、文档间属性的不一致,如有些记录可能有A属性而有一些没有,用mysql则只能把没有该属性的用户的值置为0或空,影响存储与查询;
3、 查询效率,经常会需要对某个字段进行查询,得到某个满足条件的子集,用mysql要对每个字段的查询都达到高效只能采用对该字段建索引的办法,使得索引文 件变大,如果新增字段又要新建索引,建立索引也是一个锁表又冗长的过程。couchDB应用map-reduce的方法使得计算量可以分散(注意:跟 google的那个不太一样,这里的map-reduce实际上还是在一台机器完成,且没有发现多个进程,没有看到线程个数的配置,这是我感到最难解的, 难道还是单线程流水处理的?),虽然也是像没有建索引的mysql一样需要扫全表,但可以对常用的一些查询建立永久索引,索引是随数据的增长增量更新的, 减少查询时间。
数据格式:
couchDB以json格式存储数据,返回的数据也默认为json格式,这对于前端的javascript处理是非常方便的。然而如果你用其它的 语言,比如python,获取回来的数据量很大,用simplejson包去把这个庞大的json字符串解释为dict,这就有点费时间了。解决方法之一 是升级你的simplejson到最新版本,这样速度可以提升几倍,或者你用cjson,这样格式转换的时间就基本可以忽略不计。但cjson的接口与处 理跟simplejson有点不太一样,如果你用couchdb-python作为客户端,需要对客户端代码作修改。另一个方法是要求服务端直接返回 list格式的数据,然后直接在python解释,避过了json解释一关,速度应该保证。list格式请求的API可以看这里。
缓存:
应该是有缓存的,因为同样的查询,第二次再查时会比第一次快不少,在couchDB的数据目录也能看到查询生成的临时文件。不过我估计主要的数据还 是在硬盘,因为couchDB服务占内存不多,数据不太可能都在里面,而且依据第二次查询的速度来看,不像是直接从内存取出来的,倒像是从硬盘现成拿数据 的速度。
更新机制(如何保持数据一致性):
上面说到couchDB每个文档有三个字段,其中_rev代表该文档的版本号,数据每更新一次,文档的版本号也会更新一次。这个版本号对于保持数据 一致性有很重大的作用。上面谈到couchDB把所有的属性忽略schema都统一放在一个字段里,那么当有两个程序同时修改这个字段时,就有可能造成先 写入的数据被后写入的数据覆盖的现象,导致数据不一致。couchDB利用版本号来解决这个问题,当有程序需要修改一条数据时,它必须先把这个数据的版本 号读出来,写入的时候,连版本号一并写入,此时couchDB会检查该版本号是否与原数据的一致,如果一致则写入,如果不一致,则说明数据在该程序读出后 已经被修改过,couchDB会写入不成功,返回一个冲突的信号,待客户端程序处理。
分布式:
现在couchDB(<1.0)并没有内置分布式处理机制。所以,官网中提倡的分布式并保持数据一致性的解决方法是:你设置一个写的 couchDB服务,然后把这份数据用replication过程同步拷贝到其它的机器,作为读服务。这样的分布式听起来有点傻,但确实就是如此。所以, 信息的一致性其实是难以保证的,也即是说,你刚在网站上发布了一个信息,刷新之后可能并不会马上就能看到它。不知道将来couchDB的开发者会不会就这 方面进行努力,至少现在看到的计划是还没有包含更多的分布式支持。
稳定性:
在网上的介绍中,稳定性是作为它的一个feature来介绍的,但我在gentoo上直接用portage装的couchDB0.9服务一周之内莫 名其妙地消失了三次,且在日志里没有留下任何蜘丝马迹。所以我对此持保留态度。
python客户端:
因为提供了简易的RESTful接口,为couchDB写各种语言的客户端可就容易多了,这里列出了大量的客户端。python客户端主要有 couchdb-python和couchdbkit,我试验中主要是使用了前者,使用中的问题是json的解释效率。如果使用python自带的 simplejson或json(>2.5)模块来解释,碰上一个大的字符串或dict,你就只能痛苦地等待了。我最初就是以为couchDB极 慢,谁想其实是json解释占了大部分的时间。要解决这个问题,可以装cjson,很快,但需要对couchdb-python的源代码作改动;另一个选 择是升级simplejson到最新版,速度会有极大的提升。
couchDB要做什么(它的能与不能):
即使解决了json解释的问题,纯粹归究到couchDB的问题时,你可不能对它的大数据量读写抱有太大的信心,毕竟它设计的初衷是前台的并发应 用,并不是要让你一次读出或更新几百万条数据。我的试验结果是,读200W的数据(每条记录并不大),第一次查询大概几分钟,第二次一分钟左右,更新 200W条记录,你需要等待大于20分钟。所以,目前为止,如果你要作后台批量读写,并且不能忍受这个速率,它可不是一个最好的选择。同时在你更新数据的 过程中,数据文件的体积会逐渐变大,因为数据都是追加到文件末尾的,旧数据并没有删除,所以用couchDB必须预备较大的硬盘空间,并且要定时运行 compact或replication过程,通过压缩或拷贝来清除旧数据。
前景:
这两年couchDB备受追捧,社区非常活跃,通常社区的活跃程度是影响一个开源软件成败的关键因素。couchDB吸引人的关键之处当然在于它提 出了一些对web数据存储与索引的很好的方案,如果把关系型数据库看作是一批有固定格式的电子表格的集合,那么文档型数据库就是一批各色各样的文档的集 合。相对于关系型数据库而言,文档数据库显然更适合用于多样而灵活的web数据。而couchDB的简易入门,体系的简单化,又很符合geeks追求简洁 的够用的想法。couchDB的宣传中说它“like a porn star”也是挺传神的。所以我比较看好他的发展,看到1.0稳定版会是个什么样子吧,这注定是一个跟web联系紧密的数据库。
我个人比较企盼它能在分布式处理方面有更多的改进,还有就是服务的配置、查询的效率,都是有待提高的。至于大数据量的处理,我不太难期待,因为看来 它应该是个网站前台的产品,而不太适合用于后台的分析。
参考文档
1、couchDB官方网站:http://couchdb.apache.org/
2、couchDB wiki:http://wiki.apache.org/couchdb/
3、couchDB上手指南:http://erlang-china.org/study/couchdb-guide.html