mongodb使用javascript做shell, mongodb的db.eval可以提供给数据驱动与这种javascript shell类似的js接口. 这算是一种移动代码风格(Mobile Code Sytles)的架构设计吧. 我期望可以利用这个接口, 将一些处理逻辑放在mongodb的节点上运行. 避免在PHP里面多次获取和操作mongodb的数据. (这个需求类似传统数据库的存储过程)
但是测试却发现, 在mongodb里面跑javascript性能很不理想. 我写了一段测试代码, 跑10000次循环:
<?php $mongo = new Mongo("mongodb://localhost:20237/"); $db = $mongo->selectDB("attl"); $echo_func = <<<JAVASCRIPT function() { var str = "xxxxxxxxxxxxxxxxx0000000000"; var data = str + str + str + str; var data = data + data + data + data; var max = 10000; var arr = []; var total = 0; for(var a=0; a<100; a++) { for(var i=0; i<max; i++) { arr.push( data + " . " + data); } for(var i=0; i<arr.length; i++) { total += arr[i].length; } arr = []; } return total; } JAVASCRIPT; $bgtime = microtime(true); $echo_code = new MongoCode($echo_func); $obj = (object)array("name"=>"dzg", "values"=>array(1,2,3), "bool"=>true) ; $arr = array(1,2,3,4,5,6,7,8); $map = array("a"=>1, "b"=>2); $response = $db->execute($echo_code, array($obj, $arr, $map)); var_dump($response); $endtime = microtime(true); echo "\n time : ".($endtime - $bgtime)."\n";
执行 :
php ab-mongo.php array(2) { ["retval"]=> float(867000000) ["ok"]=> float(1) } time : 6.0353651046753
这段js居然执行6秒之久! 在其他环境下测试同样功能代码:
显然相比以上测试, mongodb的javascript性能差太大了.
根据mongodb官方文档 Server-side Code Execution : Limitations of eval > Write locks 一节, 我怀疑也许是Write locks导致的. 但这种怀疑和本例关系不大, locks应该只影响并发执行, 现在的问题是一次执行都这么慢.
另外, 我还担心从PHP到mongodb的js代码传递环节慢.
于是花了两种手段排除这两个因素:
使用 db.system.js.save({_id: “mytestfunc”, value: function () { … }}); 的方式, 将测试的js代码作成mongodb支持的Stored JavaScript
使用 db.runCommand({$eval: function() {return mytestfunc();}, nolock: true}) 的方式, 进行nolock调用
结果发现问题依旧. 结论是mongodb的JavaScript执行环节有问题
我知道Mongodb的JavaScript引擎是SpiderMonkey, 于是想尝试再编译一个v8版本的Mongodb, 准备用如下JavaScript文件测试一下.
准备测试代码
function dotest() { var str = "xxxxxxxxxxxxxxxxx0000000000"; var data = str + str + str + str; var data = data + data + data + data; var max = 10000; var arr = []; var total = 0; for(var a=0; a<100; a++) { for(var i=0; i<max; i++) { arr.push( data + " . " + data); } for(var i=0; i<arr.length; i++) { total += arr[i].length; } arr = []; } return total; } myecho = (typeof console !== 'undefined' && typeof console.log == 'function') ? console.log : print; a = new Date(); myecho("begin:\t" + a); myecho("result:\t" + dotest()); b = new Date(); myecho("end:\t" + b); myecho("total time:\t" + (b - a));
这个JavaScript脚本能同时跑在4种环境下:
我准备编译完Mongodb的v8版本后, 四个环境都比较测试一下.
我在OpenSuse11.4下, 用linux的包管理工具准备编译环境, 还是很容易的:
#已安装的包: g++ subversion git python
sudo zypper install scons tcsh boost-devel pcre-devel readline-devel svn checkout http://v8.googlecode.com/svn/trunk/ v8 cd v8 scons cd .. git clone git://github.com/mongodb/mongo.git cd mongov8 scons #run mongodb v8 ./mongod --quiet --shardsvr --dbpath /home/dzg/data/mongodb/test/mongod --port 20237 --nohttpinterface --fork --pidfilepath /home/dzg/data/mongodb/test/mongod.pid --logpath /home/dzg/log/mongodb/test/mongod.log --logappend
1. PCRE最好在编译的时候显式指明对UTF-8的支持。
$ configure --enable-unicode-properties$ sudo make -j 2 && make install
PCRE如果不支持UTF-8,则MongoDB无法启动。
Thu Mar 31 17 : 27 : 16 Assertion: 10342 :pcre not compiled with utf8 support0x8169528 0x81e704e 0x8450212 0xb73b6ce7 0x80f5b11 ./mongod(_ZN5mongo11msgassertedEiPKc+0x208) [ 0x8169528 ] ./mongod(_ZN5mongo6RXTest3runEv+0x3fe) [ 0x81e704e ] ./mongod(main+0x3832) [ 0x8450212 ] /lib/libc.so .6 (__libc_start_main+0xe7) [ 0xb73b6ce7 ] ./mongod() [ 0x80f5b11 ]
2. Ubutun自身带了一个Spider Monkey,但版本有些老,有些MongoDB需要的特性不支持,需要先卸载。(注:可以不卸载)
$dpkg -l | grep xulrunner$sudo apt-get remove xulrunner- 1.9.2 -dev xulrunner- 1.9.2$export CFLAGS = ”-DJS_C_STRINGS_ARE_UTF8″$sudo make -f Makefile.ref$sudo JS_DIST = /usr make -f Makefile.ref export
3. 需要安装boost等库的支持。
$sudo apt-get -y install tcsh git-core scons g++$sudo apt-get -y install libpcre++-dev libboost-dev libreadline-dev xulrunner-dev$sudo apt-get -y install libboost-program-options-dev libboost-thread-dev libboost-filesystem-dev libboost-date-time-dev
4. 源代码建议从github上下载,根据需要编译相应的版本。
$git clone git://github.com/mongodb/mongo.git$cd mongo$git tag -l$git checkout r1 .8.0
5.最后,编译安装MongoDB的时候,建议连带头文件和库文件一起。
$scons all$scons --prefix = /opt/mongo --full install
另外,MongoDB也可以使用Google V8来作为js引擎,从性能方面来说,V8可能是更好的选择,从jira来看,MongoDB在未来或许会改用v8作为默认引擎。
首先编译V8,然后编译MongoDB的时候使用userv8参数:
$svn checkout http://v8.googlecode.com/svn/trunk/ v8$cd v8$scons$sudo cp libv8.a /usr/lib$sudo cp libv8preparser.a /usr/lib$sudo cp -r include/* /usr/include/$cd..$cd mongo$scons all --usev8$scons --prefix = /opt/mongo --full --usev8 install
MongoDB在32位环境下有诸多限制,只能用于学习研究的目的,线上环境一定要使用64位系统。
Thu Mar 31 17 : 24 : 58 --oplogSize of 1024MB is too big for 32 bit version. Use 64 bit build instead.
参考:
http://kb.cnblogs.com/page/96185/
http://www.mongodb.org/display/DOCS/Building+Spider+Monkey
http://www.mongodb.org/display/DOCS/Building+for+Linux
http://www.howsthe.com/blog/2010/feb/22/mongodb-and-v8/
http://jira.mongodb.org/browse/SERVER-446
执行~/opt/mongov8/mongo localhost:20237 dotest.js
初步结论:
本文地址: http://www.dulao5.com/javascript/2011/07/30/mongodb-javascript-performance.html