MongoDB与Tokyo Tyrant性能比较.docx

上传人:b****6 文档编号:3712103 上传时间:2022-11-24 格式:DOCX 页数:7 大小:23.34KB
下载 相关 举报
MongoDB与Tokyo Tyrant性能比较.docx_第1页
第1页 / 共7页
MongoDB与Tokyo Tyrant性能比较.docx_第2页
第2页 / 共7页
MongoDB与Tokyo Tyrant性能比较.docx_第3页
第3页 / 共7页
MongoDB与Tokyo Tyrant性能比较.docx_第4页
第4页 / 共7页
MongoDB与Tokyo Tyrant性能比较.docx_第5页
第5页 / 共7页
点击查看更多>>
下载资源
资源描述

MongoDB与Tokyo Tyrant性能比较.docx

《MongoDB与Tokyo Tyrant性能比较.docx》由会员分享,可在线阅读,更多相关《MongoDB与Tokyo Tyrant性能比较.docx(7页珍藏版)》请在冰豆网上搜索。

MongoDB与Tokyo Tyrant性能比较.docx

MongoDB与TokyoTyrant性能比较

MongoDB与TokyoTyrant性能比较

MongoDB与TokyoTyrant性能比较2010年11月15日星期一下午11:

10

(1):

基础CRU操作

以前的项目大都把数据存放在关系型数据库中,关系型数据库的优势在于使用普及,资料丰富,且有大量辅助类库来简化开发。

当然它们的问题比较明显的,一是在数据量上升的情况下伸缩性比较差,且进行结构调整的代价比较高。

因此现在有个所谓NoSQL的"运动"也逐渐普遍起来了,它便是借助一些非关系型存储方式来开发项目(个人认为其实将它解释为NotOnlySQL更为合适)。

因此在新项目里,我也想尝试一下使用之前一直只是"听说"的存储方式。

在和同事的交流过程中,我了解到他们的项目正在尝试使用TokyoTyrant(后称TT)进行存储,并且据说效果不错,因此我一开始也打算尝试使用TT进行主要存储,为此也花了一定时间为其编写.NET平台下的驱动程序。

不过在驱动程序的开发过程中,我逐渐意识到TT的功能有着严重的限制,似乎并不适合作为接下来项目的主要存储方式。

因此,我又将眼光转向了之前关注过的MongoDB上。

MongoDB也是NoSQL的代表之一,是一个面向文档的,架构灵活(Schema-less)的存储方式,在仔细阅读相关资料之后,我发现它的功能与TT相比可谓天上地下,非常适合许搭建各类项目(关于这点以后有机会再谈)。

不过,既然选择NoSQL的原因是性能,那么他们的性能表现究竟如何呢?

TT的性能表现在业界非常出名,而MongoDB的使用便相对较少了(当然,官网列举了不少案例,最近著名的开源网站SourceForge也打算使用MongoDB重新设计他们的网站)。

为此,我决定亲手比较一下两者的性能表现。

测试环境及数据

由于缺乏合适的环境,因此我不得不在我的MBP上进行这次性能比较,参数如下:

OS:

MacOSXv10.6.2(SnowLeopard)RAM:

4GB/1067MHz/DDR3CPU:

2.53GHzIntelCore2Duo64-bitKernelandExtensions:

YesTT在64bit环境下编译,MongoDB使用64bit版本。

在测试执行时,我尽量关闭多余的应用程序,避免其它因素造成影响。

同样,由于条件限制,我只得把客户端和服务器跑在同一台机器上。

测试代码使用Ruby编写,这是由于两者都有官方提供的驱动程序。

此外,由于我对于两者的优化都不太熟悉,因此它们都使用了默认的配置。

关于测试数据,我将存入110万条"新闻"数据,包含以下字段:

ID:

标识,32位整数,带索引Title:

标题,字符串CategoryID:

分类ID,32位整数,带索引CreateTime:

日期,保存为32位整数,带索引UserID:

用户ID,32位整数,带索引Tags:

标签集合,字符串数组,带索引Source:

来源,字符串SourceUrl:

来源URL,字符串Status:

状态,32位整数为了相对接近真实的环境的数据分布特征(便于以后进行查询操作比较),我设计了这样的测试数据(具体可阅读代码):

2万个分类,分别拥有10个至100条新闻,总共110万条记录。

1万个用户,根据分类id取模得到其归属。

创建时间从2010年1月1日起递增,每条记录增加1秒。

每条记录拥有2到6个Tag,除了其中一个之外,都从一个1.7万个Tag库中获取。

每条记录的字符串字段都不长(20-30字符)由于TT只支持字符串的值(但可以建立数字索引,会将字符串当作数字来识别),因此事实上所有的值都会转化为字符串进行保存。

此外,由于存在"根据Tag查找新闻"的业务,因此对于Tags字段也建立了索引,其中MongoDB直接支持对字符串数组的索引(索引其中每个元素),而在存入TT时则转化为空格分隔的字符串,并为其建立倒排索引(TokenInvertedIndex)以便进行全文查找。

在存储方式上,所有数据将放入MongoDB的同一个集合内,而TT则选用TableDatabase存储结构。

在使用TT时,另一种做法是完全使用键值对来保存一条记录的各个字段,不过这样做会大大限制TT的功能,或是会为系统编写带来额外的复杂度,便不考虑Hash/B+Tree/Fixed-length等存储方式了。

插入操作性能比较

具体代码在tt-insert.rb及mdb-insert.rb文件中。

两段代码均使用一个连接,使用循环每次插入一条:

由于如果每次都建立连接,会在TCP/IP连接的打开关闭上消耗大部分时间,由于实际项目中基本都会使用连接池等机制来复用连接,因此这方面便不多做考虑;再者,由于实际插入时几乎不可能批量操作,因此这里并不使用两者提供的批量插入功能。

脚本每插入10万条记录便打印出所耗时间,结果如下:

从结果上看,MongoDB大约有10%的领先,不过总体来说两者的差距不大。

值得一提的是,TT在数据量越大的情况下,每插入10万条记录的耗时越长(也从同事的使用过程中确认了这一点)。

因此,一开始两者插入速度几乎没有差距,但是慢慢地TT便落后于MongoDB了。

目前推测这可能是TT的TableDatabase存储结构特有的问题,不知道随着数据量的增长TT表现如何,因为对于一个大型系统来说,100多万条记录实际上只是一个很小的数目。

有同事推测,TT插入性能低是因为建立了Tags字段的倒排索引,于是我也测试了不在Tags字段上建索引的情况。

令人惊讶的是,同样去除Tags字段的索引之后,MongoDB的性能提升超过20%,而TT的性能提升却微乎其微。

值得一提的是,放入相同的记录之后,TT的文件为400多M,但MongoDB则为整整2G。

因此推测这是MongoDB进行空间预分配的结果,邮件列表上的这个讨论也证实了这一点。

此外,上面每次测试都是从零开始的,经测试如果在插入前为MongoDB预分配文件空间,则性能还会有些许提高。

通过主键获取记录性能比较

具体代码在tt-get-by-key.rb及mdb-get-by-key.rb文件中。

两段代码同样均使用一个连接,使用循环进行100万次Get操作,每次都随机获取一个110万以内的数字,并作为ID进行Get操作。

同样,每10万次Get操作后打印出所耗时间,结果如下:

在Get操作方面,MongoDB有大约20%的领先。

不过从实际情况分析,这方面的差距也不是太大,因为在项目中根据主键获取记录的操作8成以上都是落在缓存上的,因此在这方面对存储的要求并不高。

通过主键更新记录性能比较

具体代码在tt-update-by-key.rb及mdb-update-by-key.rb文件中。

两段代码各自使用同一个连接,使用循环进行大量的更新操作。

每次随机获取一个110万以内的数字,并作为ID更新其CreateTime、Title、Source、SourceUrl、Status五个字段。

结果如下:

首先是MongoDB的三次测试结果,每次更新100万条数据。

从数据上看,三次查询的性能越来越高,这个现象在重启服务器之后可以重现(三次测试之间并没有重启服务器)。

请注意,TT的三次测试均只更新了10万条记录(因为100万条记录耗时太长)。

和MongoDB类似,一开始查询性能较差,但是会慢慢提高,这个现象在重启服务器后也能重现,于是猜测是缓存的结果。

即便如此,TT的更新时的最高速度只有大约没秒1500次,而MongoDB却超过了每秒5000次。

这是因为TT在功能上有硬伤:

它无法像SQL的UPDATE语句那样更新某条记录的部分字段,因此必须全部取出,修改后再整体写入。

而MongoDB支持高效的直接修改--这也成为MongoDB放在首页上的"招牌功能"。

因此,TT对于"更新某个分类下所有新闻的状态"这样的操作会很不适应,而它的这个限制导致我们很难实现如"乐观并发控制"这样的手段。

此外,在实际应用中客户端与服务器不会使用本地连接,因此在生产环境中TT和MongoDB在这方面的差距可能会更明显一些。

总结

到目前为止,我们测试了TT和MongoDB在CRU三种基本操作下的性能,似乎MongoDB全面胜过TokyoTyrant。

不过需要强调的是,这个测试还很不全面:

它没有使用合适的环境,也没有对两者进行适当的优化。

此外,两者在并发情况下,或是同时读写下的表现如何也是值得进一步考察的,我也会设计更多的测试用例。

因此,这里的数据仅供参考,如果有合适的环境我也会重新进行测试。

(2):

并发写入操作

在上一次的测试中我们比较了MongoDB与TokyoTyrant的TableDatabase两种存储方式的性能。

不过由于条件限制,我只能在自己的MBP上测试,而这至少会带来两个问题。

首先,真实环境下客户端和服务器是通过内网连接的,它的性能比本地回环要慢不少,一些和网络传输性能有关的问题可能会体现不出。

其次,由于无法进行并发测试(并发测试的客户端资源占用较高,放在同一台机器上准确性较差),这又和生产环境有很大区别了。

因此,我前两天向同事借了台性能测试用的机器,希望可以得到更可靠的结果。

测试环境与数据

这次我使用了新的环境进行性能测试:

OS:

CentOSrelease5.3(Final)RAM:

4GBCPU:

Intel(R)Xeon(R)CPUE5405@2.00GHz(64bit,4cores*2)其他:

SCSI硬盘,ext3文件系统客户端与服务器端配置相同,两台机器使用百兆网相连,测试时服务器保持空闲。

测试数据的结构与之前相同(包括索引),数据分布同样保持一致,每个线程插入的数量较少,但每次测试的总数均不低于上次(110万条)。

为了测试并发插入的性能,我稍微改写了测试脚本。

首先,我为它增加init参数,它的作用是初始化存储结构(清除数据,建立索引),拿MongoDB的测试脚本为例:

#rubymdb-insert.rbinitindexforCreateTimecreated.

indexforCategoryIDcreated.

indexforUserIDcreated.

indexforTagscreated.

initializecompleted.此外,脚本还支持"分类范围"的指定,例如:

#rubymdb-insert.rb101200这表示我们将插入CategoryID为101至200的新闻,由于每个分类中均匀分布10至100条记录,因此只要范围的上下限保持10的倍数,这样平均每个分类有55条新闻,于是新闻ID也可以此计算出来。

例如分类101至200的新闻,其ID便为5501至11000。

您可以通过阅读代码了解这些细节。

为了并行测试,每次我就将同时执行多个脚本进行插入,每个脚本提供不同的参数。

我使用类似这样的shell脚本来启动并行任务:

#!

/bin/bash

#mdb-insert.shecho"===initialize==="

rubymdb-insert.rbinitfor((i=1;i=5;i++))

doletbegin=$((4000*($i-1)+1))

letend=$((4000*$i))

echo===starttask$i===

rubymdb-insert.rb$begin$endlogs/mdb-insert-$begin-$end.log&

done这段脚本将启动5个任务,每个任务将插入4000个分类,即22万条记录。

5个任务总共插入110万条记录,与前次持平。

接下来的测试中,我在增加任务数量的同时也会适当降低每个任务插入的记录数目。

最多我将启用100个任务,每个任务插入1000个分类,即所有任务共计插入550万条记录,是之前的5倍。

在所有的测试中,无论多少个任务都是同时启动,且几乎同时结束(与总耗时相比很小)。

因此,在接下来的数据中我不会列出每个任务的开始及结束时间,如果您关心这部分数据,可以在文章结尾处可以获得本次测试生成的所有记录文件。

TokyoTyrant性能测试

第1次测试启动5个任务,每个任务4000个分类,共计插入110万条记录。

结果如下(第1行粗体表示"万条记录",每个数字的单位为"秒",下同):

与之前的现象类似,当数据库中的数据越多时,插入速度也会随之减慢:

在每个任务插入前1万条记录时,耗时大约为5、6秒。

但是到了中后期,每插入1万条数据则需要等待15至20,甚至30秒的时间。

值得注意的是,虽然使用了较好的服务器,但是并行插入110万条记录的时间却比上次要来的多(这次耗时340秒,而之前是)。

原因可能是客户端与服务器端的分离导致网络速度的下降。

另一种可能我猜测是,根据TokyoCabinet的文档中提到文件读写锁的使用,因此每次只能插入一条记录,且插入(或更新)时无法读取数据,因而在并发环境下TokyoTyrant(它其实是TokyoCabinet上层的TCP服务器)的表现并不会有所提高。

不过据读过TokyoCabinet代码的同事说,TokyoCabint在使用TableDatabase的时候锁粒度不会那么大,因此关于这点还需要寻找进一步的资料。

第2次测试启动10个任务,每个任务还是4000个分类,因此共计插入220万条记录。

结果如下:

第2次测试的总数据量为第1次的2倍,而耗时却是第1次的3.5倍,这应该还是由于数据量增大而导致的插入性能降低。

但是,我们目前还不能排除这和并发连接数有关的可能--虽然我们有理由相信这个性能问题只和数据量相关(稍后再说)。

为了查明并发程度和性能是否有关系,我们再进行第3次测试。

第3次测试启动20个任务,每个任务2000个分类,因此共计仍旧是220万条记录。

结果如下:

这个结果实在是非常能够说明问题:

第3次的耗时与上一次几乎完全相同,这意味着加大并发量并不会影响TT的性能。

这是因为TT在服务器端维护了一个线程池(现在的测试,也是默认情况下为8个线程),因此请求再多,同时进行的任务也是有限的,而累积的任务会排在队列中。

这也是使用队列和固定数量工作线程的好处:

即使压力再大,服务器端的吞吐量也能够一直保持较高水准,而客户端请求的响应时间随着请求数量增大而线性增长。

如果没有队列,随着压力增大,服务器端吞吐量会剧烈下降(一般至少也是线性的),而客户端请求的响应时间增长更快,直至超时。

为此,我们也没有必要继续测试更多的并发数量了,因为即便是再多并发,TT的吞吐量(即插入记录的数目)也只是和数据库中记录数量相关。

根据测试,我们可以总结出:

插入110万条记录的平均吞吐量为:

大约3225条/秒插入220万条记录的平均吞吐量为:

大约1833条/秒当数据库包含100万条数据时吞吐量为:

1700~1800条/秒当数据库包含200万条数据时吞吐量为:

150~160条/秒似乎随着数据量的增加,TT的吞吐量下降得也非常明显。

这其中可能有索引的因素在里面,因此如果您想要得到适合自己的结果,最好可以亲自进行试验。

MongoDB性能测试

与TT相同,第1次测试启动5个任务,每个任务4000个分类,共计插入110万条记录。

结果如下:

在5个并发任务的情况下,MongoDB的表现较TT要出彩不少。

首先,随着数据库中已有记录的增加,插入速度并没有降低的迹象,可以说十分平稳。

此外,在同样的客户端和服务器环境下,MongoDB插入110万条数据的耗时比TT的一半还要略少一些。

而且,虽然网速带来的一定负面影响,但可能是由于服务器配置的提高,再加上并发写入的性能优势,此次测试比上次单机环境下的表现也要好上许多。

那么在数据量和并发继续增大的情况下MongoDB表现如何呢?

于是第2次测试启动10个任务,每个任务还是4000个分类,共计插入220万条记录。

结果如下:

第2次的数据量为第1次的2倍,而耗时则大约为2.08倍,两者基本保持一致,这说明了MongoDB在数据量和并发量增加的情况下,吞吐量几乎没有改变。

第3次测试依旧与TT相同,启用20个任务,每个任务2000个分类,共计插入220万条记录。

结果如下:

在总数据量不变的情况下,我们又将并发量提高了一倍,但是MongoDB依旧表现出的稳定的吞吐量,总耗时与第2次测试几乎完全相同。

这样看来,似乎在MongoDB在内部也有个类似于TT的队列机制以保证一定的吞吐量。

为了验证这个看法,我再次加大了数据量和并发量。

在第4次测试中我启用了50个任务,每个任务还是2000个分类,这样插入的记录数据则达到了550万。

结果如下:

在50个并发任务下,MongoDB终于略显疲态。

第4次测试的数据量为第3次的2.5倍,但耗时却接近3.5倍。

为了验证这是由于数据量增加,还是并发量提高引起的问题,我又进行了第最后一次测试。

第5个测试中启用了100个任务,但每个任务只写入1000个分类,则总条目数还是和第4次相同,为550万。

结果如下:

请注意,由于每个任务插入1000个分类,即5.5万条记录,因此上表中最后一栏为5.5而不是6。

随着并发量的增大,MongoDB的耗时继续增加了。

由于这个表现和之前的预测不同,我又把第4次和第5次测试各执行了一遍,结果并没有太大区别,基本可以排除"环境异常"这样的可能。

经过5次测试的结果,我们可以得出MongoDB的性能指标:

5个并发,插入110万条记录的平均吞吐量:

大约6600条/秒10个并发,插入220万条记录的平均吞吐量:

大约6300条/秒20个并发,插入220万条记录的平均吞吐量:

大约6300条/秒50个并发,插入550万条记录的平均吞吐量:

大约4500条/秒100个并发,插入550万条记录的平均吞吐量:

大约4100条/秒总体来说,虽然在数据量和并发量增大的情况下MongoDB的吞吐量有所下降,但是MongoDB的表现比TT还是要抢眼不少,而且在绝对数值上还是相当出彩的。

其他信息

其他还有一些信息可能值得参考。

在进行测试时,我发现TT进程的CPU占有率比较低,除了少量时候出现80~150%以外(top命令的结果,8核服务器),绝大部分时间CPU占有率只有20~40%。

MongoDB的CPU占有率比TT要高出不少,基本上保持在80~110%之间(数据量和并发量在这里影响不大)。

但是总体来说CPU的占有率都很低,毕竟现在的测试属于IO密集型操作。

不过在内存占有率方面,两者的区别很大。

在测试过程中(服务器内存4G),TT进程的内存占有率一直保持在20%一下,而MongoDB会缓步增加,最后保持在80%上下。

此外,在插入了550万条数据之后,MongoDB的数据文件增长到了6G。

这个数字比上次测试的2G/110万稍有缓解,但还是比TT要大上许多。

最后再来谈谈为什么仅仅测试了"并发插入"而没有"更新"和"删除":

其实这也是通过使用场景而设计出来的测试用例。

因为对于此类存储来说,大量并发插入的场景比较多,例如日志记录,用户行为记录,或是SNS应用中常见的NewsFeed等等。

这些场景的特点就是需要数据的不断增长,而大量密集的更新则很少会出现──删除就更不用说了。

至于并行的更新,我接下来也会进行测试的,只是可能会模拟一些实际的场景,例如在更新的同时进行不断地读取和插入吧。

特别声明:

1:

资料来源于互联网,版权归属原作者

2:

资料内容属于网络意见,与本账号立场无关

3:

如有侵权,请告知,立即删除。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1