rtorrent支持ipv6的问题
[| 2011/05/14 22:21]
最近想了解一下p2p的东西,于是决定装个rtorrent,rtorrent依赖于libtorrent库。yum源里带的版本太旧,于是决定自己编译一个。
选了rtorrent官网推荐的stable版的libtorrent-0.12.6.tar.gz和rtorrent-0.8.6.tar.gz,编译过程总体比较顺利。期间遇到一个问题,就是我把libtorrent安装到了自己定义的一个路径下,在编译rtorrent的时候用pkg-config搜索libtorrent的时候无法找到。
搜了一下有两个方案,一种是export PKG_CONFIG_PATH="libtorrent的路径",把路径加入pkg-config的搜索路径,是个比较简单的方法。还有一种是定义libtorrent_LIBS环境变量,用来替代pkg-config的输出,比较复杂,不推荐。
编译好后下个bt测试一下,结果发现不能连接tracker服务器,老是timed out。查了下需要libcurl-7.19以上且编译时需要编译时加入c-ares支持,而yum源里最新的是7.15,需要重新编译libcurl,评估了一下代价太大。查了下说0.8.2版以后才有此问题,于是下了个0.8.1版的rtorrent编译了。
在编译rtorrent的时候加了--enable-ipv6,但是实际使用中无法启用ipv6,又查了下发现在编译libtorrent的时候也要加--enable-ipv6.加上后还是不行。后来发现需要给libtorrent打个补丁:
cd libtorrent-0.12.6
wget http://home.samfundet.no/~sesse/libtorrent-0.12.6-ipv6-07.patch
patch -p1 < libtorrent-0.12.6-ipv6-07.patch
然后再configure --enable-ipv6,make,make install。
一切ok。
选了rtorrent官网推荐的stable版的libtorrent-0.12.6.tar.gz和rtorrent-0.8.6.tar.gz,编译过程总体比较顺利。期间遇到一个问题,就是我把libtorrent安装到了自己定义的一个路径下,在编译rtorrent的时候用pkg-config搜索libtorrent的时候无法找到。
搜了一下有两个方案,一种是export PKG_CONFIG_PATH="libtorrent的路径",把路径加入pkg-config的搜索路径,是个比较简单的方法。还有一种是定义libtorrent_LIBS环境变量,用来替代pkg-config的输出,比较复杂,不推荐。
编译好后下个bt测试一下,结果发现不能连接tracker服务器,老是timed out。查了下需要libcurl-7.19以上且编译时需要编译时加入c-ares支持,而yum源里最新的是7.15,需要重新编译libcurl,评估了一下代价太大。查了下说0.8.2版以后才有此问题,于是下了个0.8.1版的rtorrent编译了。
在编译rtorrent的时候加了--enable-ipv6,但是实际使用中无法启用ipv6,又查了下发现在编译libtorrent的时候也要加--enable-ipv6.加上后还是不行。后来发现需要给libtorrent打个补丁:
cd libtorrent-0.12.6
wget http://home.samfundet.no/~sesse/libtorrent-0.12.6-ipv6-07.patch
patch -p1 < libtorrent-0.12.6-ipv6-07.patch
然后再configure --enable-ipv6,make,make install。
一切ok。
关于Fuse
[| 2011/05/13 23:55]
今天研究了一下fuse,感觉比较有用,在虚拟机上搞了搞还不过瘾,想在vps上也弄弄,但是由于用的是OpenVZ的vps,无法载入内核模块,而fuse又是依赖于内核模块的,所以不抱什么希望。给vps客服发了个ticket请求启用fuse。结果返回来个10刀账单,内容是服务费。没理,结果一会回复我说弄好了,进去一看,发现客服只是手动mknod了一个/dev/fuse,又yum上fuse的几个包。心里嘀咕能不能行,于是编译了一个例子上去跑了跑,居然可以。。。于是就疑惑了,客服只是简单的装了两个包而已,并没有增加内核模块什么的,为什么就好用了呢。
推测有三种可能:
1,母鸡本来内核里是由fuse模块的,小鸡里面看不见。
2,fuse可能不一定就要依赖内核模块。
3,客服在处理时同时在母鸡上也加了fuse模块,只不过没有贴出来。
在OpenVZ官网上查看了一下关于启用fuse的问题,上面的解决方案是针对母鸡内核已经有了fuse模块,只是给小鸡有一个授权的过程。
云里雾里,留待考证。
另:客服给我回复解决了的时候再进去看发现10刀的账单又消失了。。。莫非客服感觉这个太简单了,不用收费?
推测有三种可能:
1,母鸡本来内核里是由fuse模块的,小鸡里面看不见。
2,fuse可能不一定就要依赖内核模块。
3,客服在处理时同时在母鸡上也加了fuse模块,只不过没有贴出来。
在OpenVZ官网上查看了一下关于启用fuse的问题,上面的解决方案是针对母鸡内核已经有了fuse模块,只是给小鸡有一个授权的过程。
云里雾里,留待考证。
另:客服给我回复解决了的时候再进去看发现10刀的账单又消失了。。。莫非客服感觉这个太简单了,不用收费?
valgrind-内存泄露监测工具
[| 2011/04/30 23:13]
最近搞的监控程序总是莫名其妙的core,有时报curl在clean阶段错误,有时报free错误,有时一启动就报错误,有时运行几小时后才报。初步判断为内存问题。
今天下午决定查查问题出在哪里,过了一遍代码,查不出问题在哪里。无语用mtrace测试了一下,报了一堆内存问题,但定位信息都是十六进制地址,无法判断到底哪行出的问题,后来发现了valgrind工具,使用了里面的Memcheck,一测试后直接报出了在90行处strncpy一个字节的内存写泄露。。原来是少分配了一个字节。晕。
强大的valgrind。
今天下午决定查查问题出在哪里,过了一遍代码,查不出问题在哪里。无语用mtrace测试了一下,报了一堆内存问题,但定位信息都是十六进制地址,无法判断到底哪行出的问题,后来发现了valgrind工具,使用了里面的Memcheck,一测试后直接报出了在90行处strncpy一个字节的内存写泄露。。原来是少分配了一个字节。晕。
强大的valgrind。
代码全部迁移至Git代码库
[| 2011/04/30 18:12]
之前在维护博客的时候经常碰到小bug修改的问题,这时需要在线上和开发机同时修改代码,非常麻烦,并且有时并不在开发机上,经常造成线上和开发环境代码不一致的情况。新版本上线时也是一个大问题,需要手工拷贝文件,不稳定且易出错。搞过一套上线脚本,用起来也不是很爽。
对于一些c项目,在在版本升级的时候经常要重新上传一份代码编译,久而久之积累了很多个版本,时间一长就忘记哪个是最新版本了,版本和版本间的区别也不好查看。
最近终于决定把代码迁移至代码库管理,在服务器上安装了git,把代码统一同步至git库,并定期备份。可以很好的解决新版本上线的问题,并可方便的查看代码变化并回滚。
对于一些c项目,在在版本升级的时候经常要重新上传一份代码编译,久而久之积累了很多个版本,时间一长就忘记哪个是最新版本了,版本和版本间的区别也不好查看。
最近终于决定把代码迁移至代码库管理,在服务器上安装了git,把代码统一同步至git库,并定期备份。可以很好的解决新版本上线的问题,并可方便的查看代码变化并回滚。
Gae与Sae压力测试对比
[| 2011/04/30 00:05]
今天对两个云平台,Gae和Sae搞了一下压力测试。使用工具为apache内置的ab
Gae中页面为基于quercus引擎的php CI框架的默认welcome Controller。Sae中使用了自带Wordpress2.91默认页。
压力测试结果发现差距悬殊。
Sae最高并发只能支持到150个并发,然后很快就Cpu超出分钟配额,挂掉了。qps为46。
Gae最高支持1000并发毫无压力,qps能够达到600,此时启动了30个实例。
当然,由于对比所用的程序完全不同,这个结果没有太强的说服力。不过可以看出,Gae通过增开实例可以达到很强的扩展性,而Sae则无法得知。
Gae中页面为基于quercus引擎的php CI框架的默认welcome Controller。Sae中使用了自带Wordpress2.91默认页。
压力测试结果发现差距悬殊。
Sae最高并发只能支持到150个并发,然后很快就Cpu超出分钟配额,挂掉了。qps为46。
Gae最高支持1000并发毫无压力,qps能够达到600,此时启动了30个实例。
当然,由于对比所用的程序完全不同,这个结果没有太强的说服力。不过可以看出,Gae通过增开实例可以达到很强的扩展性,而Sae则无法得知。
GAE(Google App Engine)版服务器监控
[| 2011/04/25 16:28]
博客服务器最早使用shell脚本定期获取数据记录到日志里,不过把监控日志放在服务器上并不是一个好的选择,一旦服务器异常往往无法登陆上去查看日志,所以用处并不大。后来用了监控宝,感觉还不错,不过时间周期比较长,且记录不能永久保存。于是搞了个GAE版的服务器监控。
程序分两部分,服务器端和GAE端,服务器端用c编写,通过读取/proc/stat等来获取系统当前数据,分割并序列化后用curl推送到GAE,GAE端获取数据后将数据存储。
这个程序相比shell脚本的优势在于直接读取proc目录,减少了中间环节。
这次服务端程序改为常驻系统运行,避免了多次fork,且内存使用更稳定。
现有问题:
时间间隔不准确,由于推送数据是同步推送,导致数据获取时间间隔略大于指定时间。
下一步:
改进时间间隔的问题,增加数据处理功能。优化代码。
程序分两部分,服务器端和GAE端,服务器端用c编写,通过读取/proc/stat等来获取系统当前数据,分割并序列化后用curl推送到GAE,GAE端获取数据后将数据存储。
这个程序相比shell脚本的优势在于直接读取proc目录,减少了中间环节。
这次服务端程序改为常驻系统运行,避免了多次fork,且内存使用更稳定。
现有问题:
时间间隔不准确,由于推送数据是同步推送,导致数据获取时间间隔略大于指定时间。
下一步:
改进时间间隔的问题,增加数据处理功能。优化代码。
Gearman的Persistent Queues使用
[| 2011/04/14 11:55]
Gearman从0.6版起添加了Persistent Queues,通过把任务队列存入mysql等位置达到将队列持久化的目的,可以保证在server重启后任务队列可以恢复。
为了和已有服务器环境兼容,我使用了0.14版本。注意在编译时要加上--with-libdrizzle-prefix[=DIR]选项打开libdrizzle支持,DIR位置为libdrizzle安装的位置。
编译完成后,可以用gearmand -q libdrizzle --libdrizzle-db=some_db --libdrizzle-table=gearman_queue命令来启动gearmand,在0.14版本中gearmand一旦加入了libdrizzle选项,就没有错误日志了。。一旦出错就直接退出,很让人郁闷,出了问题只能盲猜。不知最新版本是否改进了这点。
启动时需要注意指定数据库用户一定要求相应权限,否则程序会直接退出。还有要注意的时候要加上-q libdrizzle来启用libdrizzle。如果不加这个只是指定libdrizzle选项的话是不起作用的。
其它选项可以使用gearmand -h查看或去官方网站gearman.org查询
为了和已有服务器环境兼容,我使用了0.14版本。注意在编译时要加上--with-libdrizzle-prefix[=DIR]选项打开libdrizzle支持,DIR位置为libdrizzle安装的位置。
编译完成后,可以用gearmand -q libdrizzle --libdrizzle-db=some_db --libdrizzle-table=gearman_queue命令来启动gearmand,在0.14版本中gearmand一旦加入了libdrizzle选项,就没有错误日志了。。一旦出错就直接退出,很让人郁闷,出了问题只能盲猜。不知最新版本是否改进了这点。
启动时需要注意指定数据库用户一定要求相应权限,否则程序会直接退出。还有要注意的时候要加上-q libdrizzle来启用libdrizzle。如果不加这个只是指定libdrizzle选项的话是不起作用的。
其它选项可以使用gearmand -h查看或去官方网站gearman.org查询
Memcached内存分配及使用问题(怎样提高Memcached内存使用率)
[| 2011/04/08 18:50]
前几天做了个Memcached的思考,并测试了一些数据,是关于如何提高Memcached内存使用率的问题。
在启动memcached的时候可以加-f参数和-n参数。-f指定各slab里面chunk大小的变化比例,默认1.25,-n指定slab里面chunk大小从多少开始。
使用memcache_add($memcache_obj, md5(rand()), str_repeat(md5(rand()),10), false,80000 );向memcache中持续灌入数据。
Memcached –d start –m 50 启动memcache,增长系数默认为1.25
结果:
2011-03-28 11:15:37:SAR:localh~211: 10 0 0 0 0/0% 0 5 265 50M 0% 0 0 0 4/0/0
2011-03-28 11:15:40:SAR:localh~211: 11 0 0 530 0/0% 0 192K 4K 50M 1% 797 530 0 4/0/0
2011-03-28 11:15:43:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 105K 50M 17% 21K 13K 0 4/0/1
2011-03-28 11:15:46:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 104K 50M 48% 61K 13K 0 4/1/1
2011-03-28 11:15:49:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 102K 50M 77% 98K 13K 580 4/1/2
2011-03-28 11:15:52:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 103K 50M 92% 116K 13K 13K 4/1/3
2011-03-28 11:15:55:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 105K 50M 92% 116K 13K 13K 4/2/4
2011-03-28 11:15:58:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 107K 50M 92% 116K 13K 13K 4/2/5
2011-03-28 11:16:01:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 101K 50M 92% 116K 13K 13K 4/3/6
使用率稳定在92%,存储116k条
stats slabs
STAT 8:chunk_size 440
STAT 8:chunks_per_page 2383
STAT 8:total_pages 50
STAT 8:total_chunks 119150
STAT 8:used_chunks 119150
使用了大小为440字节的chunk。 使用了id为8的slab
Memcached –d start –m 50 –f 2 增长系数为2
结果:
2011-03-28 11:17:53:SAR:localh~211: 10 0 0 0 0/0% 0 5 267 50M 0% 0 0 0 4/0/0
2011-03-28 11:17:56:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 107K 50M 16% 20K 13K 0 4/0/0
2011-03-28 11:17:59:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 106K 50M 47% 60K 13K 0 4/1/1
2011-03-28 11:18:02:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 106K 50M 63% 80K 13K 13K 4/1/2
2011-03-28 11:18:05:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 105K 50M 63% 80K 13K 13K 4/1/3
2011-03-28 11:18:08:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 108K 50M 63% 80K 13K 13K 4/2/4
2011-03-28 11:18:11:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 106K 50M 63% 80K 13K 13K 4/2/5
使用率稳定在63%,存储80k条。
STAT 4:chunk_size 640
STAT 4:chunks_per_page 1638
STAT 4:total_pages 50
STAT 4:total_chunks 81900
STAT 4:used_chunks 81900
使用了大小为640的chunk,使用了id为4的slab
Memcached –d start –m 50 –f 1.001 –n 375 增长率为1.001 (memcache要求增长率必须大于1)
结果:
2011-03-28 14:40:09:SAR:127.0.~211: 11 0 0 12K 0/0% 0 4M 100K 50M 98% 124K 12K 10K 4/1/3
2011-03-28 14:40:10:SAR:127.0.~211: 11 0 0 13K 0/0% 0 5M 104K 50M 99% 125K 13K 13K 4/1/3
2011-03-28 14:40:11:SAR:127.0.~211: 11 0 0 13K 0/0% 0 5M 106K 50M 99% 125K 13K 13K 4/2/4
使用率稳定在99%,存储125k条
STAT 1:chunk_size 408
STAT 1:chunks_per_page 2570
STAT 1:total_pages 6
STAT 1:total_chunks 15420
STAT 1:used_chunks 15022
使用了大小为408的chunk,使用了id为1的slab
可见调整-f和-n的值可有效提高memcache对内存的使用率。
不过需要注意的是,以上测试数据使用了同长度数据,对于长度不定长的数据,需要根据整体数据确定-f和-n的值。
经过我的测试slab的id值最大为200,若id为199的slab中chunk仍小于数据长度,那么需要将数据存放在id为200的slab中,该slab中的chunk大小为1m,造成内存的巨大浪费。
memcached -d start -m 50 -f 1.001 -n 100
2011-03-28 14:51:15:SAR:127.0.~211: 11 0 0 13K 0/0% 0 5M 101K 50M 0% 50 13K 13K 4/1/2
内存使用率约等于0,存储50条数据
STAT 200:chunk_size 1048576
STAT 200:chunks_per_page 1
STAT 200:total_pages 50
STAT 200:total_chunks 50
STAT 200:used_chunks 50
使用了大小为1m的chunk,使用了id为200的slab
现在还有一个问题:
STAT 1:chunk_size 408
STAT 1:chunks_per_page 2570
一个1m大小slab中存放了2570个大小为408的chunk,可见并没有放满,剩余的空间就被浪费了。对于这种情况,每个slab浪费的内存只有几百个字节,可以忽略不计,但是假如chunk大小为几十上百k的时候,空间浪费情况就很客观了。这时可在memcached启动时添加-I(大写的i)参数来改变slab的大小
以上就是我做的评测和总结出来的一些东西,限于个人水平,如有错误之处请大家指正。
在启动memcached的时候可以加-f参数和-n参数。-f指定各slab里面chunk大小的变化比例,默认1.25,-n指定slab里面chunk大小从多少开始。
使用memcache_add($memcache_obj, md5(rand()), str_repeat(md5(rand()),10), false,80000 );向memcache中持续灌入数据。
Memcached –d start –m 50 启动memcache,增长系数默认为1.25
结果:
2011-03-28 11:15:37:SAR:localh~211: 10 0 0 0 0/0% 0 5 265 50M 0% 0 0 0 4/0/0
2011-03-28 11:15:40:SAR:localh~211: 11 0 0 530 0/0% 0 192K 4K 50M 1% 797 530 0 4/0/0
2011-03-28 11:15:43:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 105K 50M 17% 21K 13K 0 4/0/1
2011-03-28 11:15:46:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 104K 50M 48% 61K 13K 0 4/1/1
2011-03-28 11:15:49:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 102K 50M 77% 98K 13K 580 4/1/2
2011-03-28 11:15:52:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 103K 50M 92% 116K 13K 13K 4/1/3
2011-03-28 11:15:55:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 105K 50M 92% 116K 13K 13K 4/2/4
2011-03-28 11:15:58:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 107K 50M 92% 116K 13K 13K 4/2/5
2011-03-28 11:16:01:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 101K 50M 92% 116K 13K 13K 4/3/6
使用率稳定在92%,存储116k条
stats slabs
STAT 8:chunk_size 440
STAT 8:chunks_per_page 2383
STAT 8:total_pages 50
STAT 8:total_chunks 119150
STAT 8:used_chunks 119150
使用了大小为440字节的chunk。 使用了id为8的slab
Memcached –d start –m 50 –f 2 增长系数为2
结果:
2011-03-28 11:17:53:SAR:localh~211: 10 0 0 0 0/0% 0 5 267 50M 0% 0 0 0 4/0/0
2011-03-28 11:17:56:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 107K 50M 16% 20K 13K 0 4/0/0
2011-03-28 11:17:59:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 106K 50M 47% 60K 13K 0 4/1/1
2011-03-28 11:18:02:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 106K 50M 63% 80K 13K 13K 4/1/2
2011-03-28 11:18:05:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 105K 50M 63% 80K 13K 13K 4/1/3
2011-03-28 11:18:08:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 108K 50M 63% 80K 13K 13K 4/2/4
2011-03-28 11:18:11:SAR:localh~211: 11 0 0 13K 0/0% 0 5M 106K 50M 63% 80K 13K 13K 4/2/5
使用率稳定在63%,存储80k条。
STAT 4:chunk_size 640
STAT 4:chunks_per_page 1638
STAT 4:total_pages 50
STAT 4:total_chunks 81900
STAT 4:used_chunks 81900
使用了大小为640的chunk,使用了id为4的slab
Memcached –d start –m 50 –f 1.001 –n 375 增长率为1.001 (memcache要求增长率必须大于1)
结果:
2011-03-28 14:40:09:SAR:127.0.~211: 11 0 0 12K 0/0% 0 4M 100K 50M 98% 124K 12K 10K 4/1/3
2011-03-28 14:40:10:SAR:127.0.~211: 11 0 0 13K 0/0% 0 5M 104K 50M 99% 125K 13K 13K 4/1/3
2011-03-28 14:40:11:SAR:127.0.~211: 11 0 0 13K 0/0% 0 5M 106K 50M 99% 125K 13K 13K 4/2/4
使用率稳定在99%,存储125k条
STAT 1:chunk_size 408
STAT 1:chunks_per_page 2570
STAT 1:total_pages 6
STAT 1:total_chunks 15420
STAT 1:used_chunks 15022
使用了大小为408的chunk,使用了id为1的slab
可见调整-f和-n的值可有效提高memcache对内存的使用率。
不过需要注意的是,以上测试数据使用了同长度数据,对于长度不定长的数据,需要根据整体数据确定-f和-n的值。
经过我的测试slab的id值最大为200,若id为199的slab中chunk仍小于数据长度,那么需要将数据存放在id为200的slab中,该slab中的chunk大小为1m,造成内存的巨大浪费。
memcached -d start -m 50 -f 1.001 -n 100
2011-03-28 14:51:15:SAR:127.0.~211: 11 0 0 13K 0/0% 0 5M 101K 50M 0% 50 13K 13K 4/1/2
内存使用率约等于0,存储50条数据
STAT 200:chunk_size 1048576
STAT 200:chunks_per_page 1
STAT 200:total_pages 50
STAT 200:total_chunks 50
STAT 200:used_chunks 50
使用了大小为1m的chunk,使用了id为200的slab
现在还有一个问题:
STAT 1:chunk_size 408
STAT 1:chunks_per_page 2570
一个1m大小slab中存放了2570个大小为408的chunk,可见并没有放满,剩余的空间就被浪费了。对于这种情况,每个slab浪费的内存只有几百个字节,可以忽略不计,但是假如chunk大小为几十上百k的时候,空间浪费情况就很客观了。这时可在memcached启动时添加-I(大写的i)参数来改变slab的大小
以上就是我做的评测和总结出来的一些东西,限于个人水平,如有错误之处请大家指正。
MongoDB评测
[| 2011/04/08 18:46]
最近对MongoDB做了个评测。
MongoDB是一种No-SQL数据库,存储数据采用BSON格式将数据序列化后存储。不过BSON对象最大有4m的限制,对于大于4m的,MongoDB会使用GridFs来将文件分块存储。
这里需要注意的是,在OpenVZ的VPS上需要用ulimit来限制程序最大可用的内存,否则程序会试图分配很大的内存导致OpenVZ内存配额耗尽。
测试数据:id字段:1000000-2000000的一个数字
Msg字段:32*30字节
测试脚本语言:PHP
自己搭建的虚拟机:Ubuntu 10.10,总内存:256M。
100w条插入:无索引用时70s,平均1.5w/s。插入后程序占用内存110M
100w条随机读取一条:无索引时30s,有索引12ms。
在一台Intel(R) Xeon(R) CPU E5620 @ 2.40GHz,内存2G的服务器上测试:
100w条插入:无索引用时43s。插入后程序占用内存1G。
100w条随机读取一条:无索引600ms,有索引0.18ms。
MongoDB是一种No-SQL数据库,存储数据采用BSON格式将数据序列化后存储。不过BSON对象最大有4m的限制,对于大于4m的,MongoDB会使用GridFs来将文件分块存储。
这里需要注意的是,在OpenVZ的VPS上需要用ulimit来限制程序最大可用的内存,否则程序会试图分配很大的内存导致OpenVZ内存配额耗尽。
测试数据:id字段:1000000-2000000的一个数字
Msg字段:32*30字节
测试脚本语言:PHP
自己搭建的虚拟机:Ubuntu 10.10,总内存:256M。
100w条插入:无索引用时70s,平均1.5w/s。插入后程序占用内存110M
100w条随机读取一条:无索引时30s,有索引12ms。
在一台Intel(R) Xeon(R) CPU E5620 @ 2.40GHz,内存2G的服务器上测试:
100w条插入:无索引用时43s。插入后程序占用内存1G。
100w条随机读取一条:无索引600ms,有索引0.18ms。
Gearman的一些心得
[| 2011/04/02 16:58]
最近项目要用到Gearman,之前在《构建高性能Web站点》这本书上看到过,不过一直没有太注意。最近详细研究了一下,发现还是很有用的。
Gearman是个可以把计算能力分布式部署的工具,由server,worker,client三部分组成。server在linux上叫做gearmand,使用gearmand -d即可运行,默认端口是4730。负责分配任务。
worker由用户编写,可以使用多种语言,c,php,python等等均可,作用是像server注册一个函数,表示自己可以处理该类计算请求。client也是由用户编写,语言不必和worker相同,
向server提交计算请求,并获取计算结果。
关于gearman比较好的一篇blog:http://www.kongch.com/2010/04/gearman-how-to/
之前一直疑惑server是如何根据worker的负载来分配任务的,看了原理后发现原来任务并不是由server分配,而是由worker主动领取的,
这样就大大简化了server和worker的逻辑。
如下是工作流程:
1,Worker通过CAN_DO消息,注册到Job server上。
2,随后发起GRAB_JOB,主动要求分派任务。
3,Job server如果没有job可分配,就返回NO_JOB。
4,Worker收到NO_JOB后,进入空闲状态,并给Job server返回PRE_SLEEP消息,告诉Job server:”如果有工作来的话,用NOOP请求我先。”
5,Job server收到worker的PRE_SLEEP消息后,明白了发送这条消息的worker已经进入了空闲态。
6,这时如果有job提交上来,Job server会给worker先发一个NOOP消息。
7,Worker收到NOOP消息后,发送GRAB_JOB向Job server请求任务。
8,Job server把工作派发给worker。
9,Worker干活,完事后返回WORK_COMPLETE给Job server。
不过看到这里我有一些疑问,就是在第六步的时候server向worker同时发送NOOP,会不会导致惊群效应?这个问题留待考证。
现在版本的gearman并不能监控worker的状态,任务的分配过程对client又是透明的,如果在多台机器上部署多个worker的话并不能直接获取各worker的状态。
不过通过编写一些函数还是可以实现这个功能的,甚至可以完全用gearman来监控多台服务器。网上有篇文章也讲到了这点,不过非常简略。我想了一个方式,比较幼稚,
欢迎指正:
worker基础函数及变量:
setID():用来接收监控端置入id,运行一次后注销。
manage():用来接收控制和状态查询请求,默认关闭,在setID中开启。
functionInUse():已注册的功能函数列表。
functionNotUse():未注册的功能函数列表。
count数组:记录各个功能函数执行次数。
exitWorker():退出worker,导致worker进程退出,慎用。
newWorker():启动新worker。
unregisterFunction:注销指定功能函数。
registerFunction:注册指定功能函数。
1,新worker在启动时只注册setId函数。此时worker处在就绪未注册状态。
2,监控client发送setId请求,参数为唯一id。
3,就绪未注册状态worker收到setId请求,设置id为自己的id,返回自己的主机名和进程号,然后注册manage函数为manage_id,其中id为自己的id,最后注销setId函数,进入就绪已注册状态。
4,监控client收到应答后将id与主机名进程号对应起来。
5,监控client重复2,直到无就绪未注册状态worker。
现在所有的worker都处在就绪已注册状态,监控client处也获得了所有worker的信息,此时初始化完毕,监控client通过调用manage_id来启动相应worker的指定功能函数,
worker进入工作状态。
此时整个系统开始正常工作。监控client可以周期性的调用manage_id来获取各worker的运行状态,并可以控制各个worker的注册功能函数数量。这时无论是根据负载自动调整各个worker还是上线新版本都是很方便的。
Gearman是个可以把计算能力分布式部署的工具,由server,worker,client三部分组成。server在linux上叫做gearmand,使用gearmand -d即可运行,默认端口是4730。负责分配任务。
worker由用户编写,可以使用多种语言,c,php,python等等均可,作用是像server注册一个函数,表示自己可以处理该类计算请求。client也是由用户编写,语言不必和worker相同,
向server提交计算请求,并获取计算结果。
关于gearman比较好的一篇blog:http://www.kongch.com/2010/04/gearman-how-to/
之前一直疑惑server是如何根据worker的负载来分配任务的,看了原理后发现原来任务并不是由server分配,而是由worker主动领取的,
这样就大大简化了server和worker的逻辑。
如下是工作流程:
1,Worker通过CAN_DO消息,注册到Job server上。
2,随后发起GRAB_JOB,主动要求分派任务。
3,Job server如果没有job可分配,就返回NO_JOB。
4,Worker收到NO_JOB后,进入空闲状态,并给Job server返回PRE_SLEEP消息,告诉Job server:”如果有工作来的话,用NOOP请求我先。”
5,Job server收到worker的PRE_SLEEP消息后,明白了发送这条消息的worker已经进入了空闲态。
6,这时如果有job提交上来,Job server会给worker先发一个NOOP消息。
7,Worker收到NOOP消息后,发送GRAB_JOB向Job server请求任务。
8,Job server把工作派发给worker。
9,Worker干活,完事后返回WORK_COMPLETE给Job server。
不过看到这里我有一些疑问,就是在第六步的时候server向worker同时发送NOOP,会不会导致惊群效应?这个问题留待考证。
现在版本的gearman并不能监控worker的状态,任务的分配过程对client又是透明的,如果在多台机器上部署多个worker的话并不能直接获取各worker的状态。
不过通过编写一些函数还是可以实现这个功能的,甚至可以完全用gearman来监控多台服务器。网上有篇文章也讲到了这点,不过非常简略。我想了一个方式,比较幼稚,
欢迎指正:
worker基础函数及变量:
setID():用来接收监控端置入id,运行一次后注销。
manage():用来接收控制和状态查询请求,默认关闭,在setID中开启。
functionInUse():已注册的功能函数列表。
functionNotUse():未注册的功能函数列表。
count数组:记录各个功能函数执行次数。
exitWorker():退出worker,导致worker进程退出,慎用。
newWorker():启动新worker。
unregisterFunction:注销指定功能函数。
registerFunction:注册指定功能函数。
1,新worker在启动时只注册setId函数。此时worker处在就绪未注册状态。
2,监控client发送setId请求,参数为唯一id。
3,就绪未注册状态worker收到setId请求,设置id为自己的id,返回自己的主机名和进程号,然后注册manage函数为manage_id,其中id为自己的id,最后注销setId函数,进入就绪已注册状态。
4,监控client收到应答后将id与主机名进程号对应起来。
5,监控client重复2,直到无就绪未注册状态worker。
现在所有的worker都处在就绪已注册状态,监控client处也获得了所有worker的信息,此时初始化完毕,监控client通过调用manage_id来启动相应worker的指定功能函数,
worker进入工作状态。
此时整个系统开始正常工作。监控client可以周期性的调用manage_id来获取各worker的运行状态,并可以控制各个worker的注册功能函数数量。这时无论是根据负载自动调整各个worker还是上线新版本都是很方便的。