MongoDB与Tokyo Tyrant性能比较Word文档下载推荐.docx
- 文档编号:16616932
- 上传时间:2022-11-24
- 格式:DOCX
- 页数:7
- 大小:23.34KB
MongoDB与Tokyo Tyrant性能比较Word文档下载推荐.docx
《MongoDB与Tokyo Tyrant性能比较Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《MongoDB与Tokyo Tyrant性能比较Word文档下载推荐.docx(7页珍藏版)》请在冰豆网上搜索。
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上测试,而这至少会带来两个问题。
首先,真实环境下客户端和服务器是通过内网连接的,它的性能比本地回环要慢不少,一些和网络传输性能有关的问题可能会体现不出。
其次,由于无法进行并发测试(并发测试的客户端资源占用较高,放在同一台机器上准确性较差),这又和生产环境有很大区别了。
因此,我前两天向同事借了台性能测试用的机器,希望可以得到更可靠的结果。
测试环境与数据
这次我使用了新的环境进行性能测试:
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:
如有侵权,请告知,立即删除。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- MongoDB与Tokyo Tyrant性能比较 MongoDB Tokyo Tyrant 性能 比较