本篇要评测的NoSQL产品是MongoDB,它是现在开源社区里越来越受到关注的一个NoSQL产品,按照官方的说法,是一个可扩展的、高性能 的、开源的、面向文档的数据库。Craigslist、foursquare、国内的淘宝网等知名互联网公司都有在他们的生产环境部署了MongoDB。
系列文章:
一、MongoDB简介
mongodb是用C++开发的面向文档的数据库,也就是反传统的数据库范式来设计的,把相关的对象都记录到一个文档里,每个文档内是schema- free的,也就是列名可以自由定义,比较灵活,特别是面对业务逻辑多变的应用场景十分给力。数据以BSON(类似JSON)的格式二进制存储。不好的地 方就是可能带来一定的数据冗余和存储开销。
很明显,MongoDB这种面向文档的数据库和传统的关系型数据库的设计思路是差别很大的, 因为每个文档都包含了所有信息,和其他文档是没有关联的,这样传统的Join操作就完全没必要了,也正是因为去除了这种“关系”,使得MongoDB的水 平拆分更加容易,这也是面对海量数据的一个很好的处理思路。另外,MongoDB的索引机制和MySQL等数据库是一样的,可以利用传统的关系型数据库的 经验来使用MongoDB的索引。
不像其他很多NoSQL产品由个别工程师根据应用场景开发出来,MongoDB是有一个专门的公司10gen来维护。有一点要注意的是,MongoDB自己是不管理内存的,无法指定内存大小,完全交给操作系统来管理,因此有时候是不可控的,在生产环境使用必须在OS层面监控内存使用情况。
二、测试说明
1、测试环境
MongoDB部署在一台PC 服务器上,配置如下:
CPU为Xeon 2.80GHz *4
内存为4G
硬盘为一块400G SATA盘
操作系统为64位CentOS 5.3版本
2、测试方法
这里仍然采用PHP客户端进行测试,MongoDB官方为PHP开发了一个扩展包可以操作MongoDB,网址为http://pecl.php.net/package/mongo,可以编译到PHP运行环境中来使用。
为了不对测试服务器产生额外的影响,测试客户端部署在另外一台独立的服务器上,运行的PHP的版本是5.3.5,web server是Nginx 0.8.54,通过fastcgi的方式调用PHP服务。使用apache ab工具实现多个请求和并发操作。
测试过程中就使用上文提到的已经启动的数据库实例,首先是进行写操作,通过500个请求,每个请求写入10000条记录,并发度为2来共写入500万条 数据,MongoDB的数据格式是BSON方式,不同于其他的NoSQL是key value的方式,因此这里写入的数据格式为:{id,data}的形式,ID为数字1到5000000,data大小为100个字节。然后是读操作,也 是用500个请求,每个请求随机根据ID值读出10000条记录,并发度为10共读出500万条记录,评测的重点是写入和读出数据的时间,以及在此过程中 服务器的资源使用情况。
需要说明的是,MongoDB默认会为每个记录建立一个名字为_id的索引,在没有索引的情况下MongoDB读数据都要进行全表扫描,效率还是很低的,因此在写完500万条记录后,我在id字段上建立了一个索引来加快读的过程。
三、安装和使用
mongodb目前最新的版本是.8.2-rc3,其源码安装用了很多第三方的东西,比如JS引擎(目前官方推荐的是mozilla的Spider Monkey,以后可能改成google的V8,和node.js一样,呵呵)、正则表达式引擎(pcre)、安装构建工具scons(这东西还要用 python来安装)、boost C++库等等。下面是安装过程:
1、下载需要的源文件和相关软件包:
2、安装scons:
3、安装pcre:
4、安装Spider Monkey:
5、安装boost,yum方式比较偷懒:
6、安装mongodb:
这样就安装完毕了,可以简单的启动mongod进程来验证一下:
可见mongod默认在27017端口监听,而28017端口是web管理的端口,可通过http方式来访问。为了规范,我们用以下命令启动一个mongod进程:
这样一个mongod进程就启动了,它监听27017端口来提供服务,可以在应用程序中进行建立数据库等操作,它不像传统的Oracle等关系数据库那样,建库是个很慎重的工作。要了解更详细的使用MongoDB的信息,读者可以参看官方文档,这里就不提及了。
四、测试结果
1、写操作
成功写入416万条记录,写入失败84万条记录,共耗时525秒,平均每秒写入数据7924笔。数据文件大小近4G。写入过程中,服务器内存、CPU和磁盘等资源使用情况如下图所示:
可见,内存使用呈阶梯状上升,最后占用了近3.5个G,主要用来缓存数据,对比数据文件的大小可以设想,在操作系统内存可用的情况下,内存的分配和数据文件的大小是大致相当的。CPU和磁盘IO都表现出周期性的上下波动,估计和操作系统mmap缓存数据和刷新到磁盘的实现机制有关。从图表可见本次测试的瓶颈同样出现在磁盘IO上,磁盘的使用率最后达到100%,导致无法成功写入数据。
2、读操作
成功读出500万条记录,共耗时432秒,平均每秒读出数据11574笔。
读数据过程中没有发生磁盘IO。CPU较繁忙,Idle值稳定在27左右,等待CPU资源的进程一直在5到10个之间。内存表现平稳没有波动。
五、总结
通过以上测试结果可以看出,MongoDB占用的磁盘空间很大,这是因为其占用的磁盘空间是预分配的,每次以上一个数据文件的两倍大小来预分配空间,并 以0来填充,以避免在繁忙时期分配磁盘空间导致性能下降,因此我们看到的数据文件大小并不是实际占用的空间大小。另外其内存是由操作系统管理的,自身并不 管理内存使用。从功能角度看MongoDB提供的查询等操作接口是最为丰富的,在面对海量数据的拆分等可扩展方面也有很好的设计思路,是一个很好的将数据 模型从面向关系转向面向文档的NoSQL产品,相信将来会看到更多的线上产品选用MongoDB。