spcached : memcached 的多线程实现

原贴:http://www.javaeye.com/article/80095

iunknown的博客:iunknown
iunknown 发表于 2007-05-15 14:43   浏览3242次
关键字: C++   libevent memcached 内存池 平衡树 性能测试
发布在 C++语言 圈子    加入在 C/C++专栏 专栏
     



实现 spcached 的目的:不是与 memcached 进行竞争,只是为了测试。

最初想到要实现 spcached 的时候,是因为想对 spserver 这个框架做一个压力测试。当时想用作个简单的 http 服务器,然后用 apache 的 ab 工具进行测试。后来觉得如果做测试,最好能有一个对比,因此就想起了 memcached 来。并且刚好 memcached 和 spserver 都是基于 libevent 的。

memcached 是公认的高性能服务器,而且里面完全不涉及文件的 IO 操作,适合用来衡量以下几个方面:单线程 event-driven VS. 多线程,内存池 VS. 非内存池,hash table VS. BalancedTree。

memcached 采用的通信协议有详细的说明文档:
http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt
spcached 就是根据这份文档进行开发的,目前只实现了测试必须的几个命令:add,set,replace,get,delete,incr,decr,stats,version,quit 。

memcached 采用 ansi c 实现,采用了很多的优化手段,包括
1.程序基于libevent,使用单线程 event-driven 的风格(1.2.0 版本,1.2.2 版本已经开始使用多线程)
2.使用了内存池
3.使用 hash table 来保存 (key, value) pair

spcached 采用 c++ 实现,对应上面的各个方面,采用的手段为
1.程序基于半同步半异步的多线程风格(使用 spserver 框架)
2.没有使用内存池,直接使用 c++ 的 new/delete/malloc/free
3.使用 BalancedTree 来保存 (key, value) pair (使用 spdict 库)

对比测试结果在后面回贴中陆续更新。




声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。若作者同意转载,必须以超链接形式标明文章原始出处和作者。
相关文章:    [翻译]Berkeley DB 文档 - C++入门篇 - 1.3节 - 访问方式(Access Methods)    SPWebServer:一个基于 SPServer 的 web 服务器框架
评论    共 7 条 发表评论
Arbow     2007-05-15 17:47

great,望尽快提供性能测试对比:)
从猜测角度来说,感觉使用new/delete和平衡树的开销会大一些

iunknown     2007-05-15 22:50

测试环境:
CPU:intel T2300 1.66G ,1G MEM
HOST:windows xp + vmware 5.5.1 + RedHatLine 7.2 ( linux 2.4.18-3 )
vmware 的内存设置为 128M
测试之前,先重启了 windows xp,再重启 vmware。测试期间不上网,不运行其他程序。
T2300 是双核 CPU ,但是在 vmware 中使用 top 命令只能看到一个 CPU 。

测试工具:
com/danga/MemCached/test/MemCachedBench
由于使用 jdk1.4,所以用的不是最新的包,而是 java_memcached-release_1.3.2.tar.gz 。
MemCachedBench 经过少量修改,以便在命令行指定不同的端口。

测试模型:
1.限定 memcached 和 spcached 在测试中将保存同样多的 items 数目。memcached 通过内存使用量来限定 items 数目,spcached 直接有参数来限定 items 数目。
2.MemCachedBench 的步骤是先增加 五十万 个 item 到服务器(实际真正保存的数目为291984),然后再查询这 五十万 个 item 。分别计算插入的时间和查询的时间。
3.运行一次测试之后,通过 stats 命令查询 memcached 和 spcached 的内部状态。
4.由于分配给 vmware 的内存少,测试 memcached 的时候,停止 spcached ;测试 spcached 的时候,停止 memcached 。
5.memcached , spcached 和 测试工具 都运行在同一个操作系统中。

软件版本:
memcached 1.2.0
spcached svn revision 5 + spserver 0.3 + spdict 0.2

具体的测试数据见后面,先来看结果。

从客户端计算测试的结果(处理速度之比,spcached/memcached):
插入 162758 / 229266 = 71 %
查询 201934 / 284856 = 71 %

从服务器计算测试的结果(使用 cpu 时间之比,spcached/memcached):
rusage_user 1.330000 / 0.770000 = 1.72
rusage_system 38.670000 / 75.630000 = 0.51

即从客户端来看,spcached 只达到 memcached 71% 的性能。
从服务器的 cpu 使用角度来看,spcached 的 system 时间只有 memcached 的一半,user 时间是 memcached 的 1.72 倍。

测试的环境使用的是 linux 2.4.18-3 ,使用 LinuxThreads 。spcached 的 user 时间比 memcached 多,应该是由于 LinuxThreads 进行调度耗费了不少时间。另外 hash table 和 BalancedTree 的操作也是属于 user 时间,BalancedTree 的操作比 hash table 慢。
出乎意料,memcached 的 system 时间居然是 spcached 的两倍。没仔细看 memcached 的代码,不知道是什么原因。

结合客户端和服务器两方面的结果来看,令人非常迷茫。服务器费时少的程序,对应的客户端用的时间居然反而长。
要解释这种情况,看来要进一步看看操作系统方面的书。

最初希望 spcached 能达到 memcached 80% 的性能,现在只能达到 70% ,也算是一个还能接受的结果。

代码
  1. rusage_user       32u:32u  Accumulated user time for this process   
  2.                            (seconds:microseconds)  
  3. rusage_system     32u:32u  Accumulated system time for this process   
  4.                            (seconds:microseconds)  
<script type="text/javascript">render_code();</script>
代码
  1. bash-2.05a$ ./memcached -m 128  
  2.   
  3. bash-2.05a$ java com/danga/MemCached/test/MemCachedBench 500000 0 11211  
  4. 500000 sets: 162758ms  
  5. 500000 gets: 201934ms  
  6.   
  7. bash-2.05a$telnet 0 11211  
  8. STAT rusage_user 0.770000  
  9. STAT rusage_system 75.630000  
<script type="text/javascript">render_code();</script>
代码
  1. bash-2.05a$ ./spcached -c 291984  
  2.   
  3. bash-2.05a$ java com/danga/MemCached/test/MemCachedBench 500000 0 11216  
  4. 500000 sets: 229266ms  
  5. 500000 gets: 284856ms  
  6.   
  7. bash-2.05a$ telnet 0 11216  
  8. STAT rusage_user 1.330000  
  9. STAT rusage_system 38.670000  
  10.   
  11. bash-2.05a$ top  
  12.   PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND  
  13. 15854 svn       15   0  112M  96M 66952 S     0.0 77.9   0:21 spcached  
<script type="text/javascript">render_code();</script>
iunknown     2007-05-16 23:25
引用
出乎意料,memcached 的 system 时间居然是 spcached 的两倍。没仔细看 memcached 的代码,不知道是什么原因。

查看了 MemCachedBench 的源代码之后,发现了问题所在。

代码
  1. pool.setInitConn(100);  
  2. pool.setMinConn(100);  
<script type="text/javascript">render_code();</script>
测试工具在开始测试的时候就发起了 100 个连接到服务器,而测试过程中只会用到一个连接。由于测试环境的 linux 版本低,所以使用的还是 select ,而不是 epoll 。epoll 对于这种只有少量连接活跃的情况能够处理的很好,但是 select 却是相反,因此导致服务器在 select 上消耗了大量的时间。

spcached 比 memcached 消耗少的原因在于 spcached 对于不活跃的连接设置了 60 秒的超时时间,而 memcached 是永不超时的。所以 spcached 在前 60 秒受到 99 个不活跃连接的干扰,而 memcached 是一直受干扰。

改 MemCachedBench 的代码如下,重新测试

代码
  1. pool.setInitConn(1);  
  2. pool.setMinConn(1);  
<script type="text/javascript">render_code();</script>

从客户端计算测试的结果(处理速度之比,spcached/memcached):
插入 132917 / 204055 = 65 %
查询 150149 / 220507 = 68 %

从服务器计算测试的结果(使用 cpu 时间之比,spcached/memcached):
rusage_user 0.800000 / 0.470000 = 1.7
rusage_system 34.050000 / 53.730000 = 0.63

测试结果是 memcached 更快了。

代码
  1. ./memcached -m 96  
  2.   
  3. bash-2.05a$ java com/danga/MemCached/test/MemCachedBench 500000 0 11211  
  4. 500000 sets: 132917ms  
  5. 500000 gets: 150149ms  
  6.   
  7. bash-2.05a$ telnet 0 11211  
  8. STAT rusage_user 0.470000  
  9. STAT rusage_system 53.730000  
  10.   
  11. bash-2.05a$ top  
  12.   PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND  
  13. 16587 liusf     15   0 99.8M  80M  2800 S     0.0 65.3   0:54 memcached  
<script type="text/javascript">render_code();</script>
代码
  1. bash-2.05a$ ./spcached -c 185808  
  2.   
  3. bash-2.05a$ java com/danga/MemCached/test/MemCachedBench 500000 0 11216  
  4. 500000 sets: 204055ms  
  5. 500000 gets: 220507ms  
  6.   
  7. bash-2.05a$ telnet 0 11216  
  8. STAT rusage_user 0.800000  
  9. STAT rusage_system 34.050000  
  10.   
  11. bash-2.05a$ top  
  12.   PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND  
  13. 16563 svn       15   0 74916  73M   608 S     0.0 59.1   2:07 spcached  
<script type="text/javascript">render_code();</script>
iunknown     2007-05-16 23:34

使用 cprof 对 spcached 做 profiler ,其中对 key 进行比较的函数占用差不多 60% 的时间。

代码
  1. bash-2.05a$ cprof spcached cmon.out  | more  
  2. Function Name                        calls   func%  func(ms)    f+c%   f+c(ms)  
  3.                                          0 4930875599.984 11095618832560 100.000    225023  
  4. compare__19SP_CacheItemHandlerPCvT1  32320411  35.035     78837  57.750    129949  
<script type="text/javascript">render_code();</script>
代码
  1. int xxx :: compare( ... )  
  2. {  
  3.         ......  
  4.         return strcmp( i1->getKey(), i2->getKey() );  
  5. }  
<script type="text/javascript">render_code();</script>

如果使用 hash table ,会减少很多对这个函数的调用。

改用和 memcached 同样的 hash table 之后,数据如下:

代码
  1. Function Name                        calls   func%  func(ms)    f+c%   f+c(ms)  
  2.                                          0 13660645568.442 11095652346241 100.000     81223  
  3. hashCode__19SP_CacheItemHandlerPCv   2600000   8.435      6851  13.449     10923  
  4. compare__19SP_CacheItemHandlerPCvT1    785604   2.392      1942   3.983      3235  
<script type="text/javascript">render_code();</script>
代码
  1. bash-2.05a$ java com/danga/MemCached/test/MemCachedBench 500000 0 11216  
  2. 500000 sets: 193644ms  
  3. 500000 gets: 207668ms  
  4.   
  5. bash-2.05a$ telnet 0 11216  
  6. STAT rusage_user 0.220000  
  7. STAT rusage_system 27.780000  
  8.   
  9. bash-2.05a$ top  
  10.  PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND  
  11. 19315 svn       15   0 77164  75M   608 S     0.0 60.9   1:57 spcached  
<script type="text/javascript">render_code();</script>
hqman     2007-07-27 17:25

高手问个问题。

memcached 对 cache 对象 大小有什么限制 。

我在程序中 如果对象的大小 超过255kb 就出错。

(SERVER_ERROR object too large for cache)
[50:30.597] - ++++ error storing data in cache for key: test_key7 -- length: 1048603
[50:30.597] - SERVER_ERROR object too large for cache
[50:30.597] - ++++ serializing for key: test_key8 for class: [I
[50:30.701] - ++++ memcache cmd (result code): set test_key8 8 0 1048603
(SERVER_ERROR object too large for cache)
[50:30.702] - ++++ error storing data in cache for key: test_key8 -- length: 1048603
[50:30.703] - SERVER_ERROR object too large for cache
[50:30.703] - ++++ serializing for key: test_key9 for class: [I
[50:30.805] - ++++ memcache cmd (result code): set test_key9 8 0 1048603
(SERVER_ERROR object too large for cache)
[50:30.806] - ++++ error storing data in cache for key: test_key9 -- length: 1048603
[50:30.806] - SERVER_ERROR object too large for cache

pi1ot     2007-07-27 18:03

memcached现在可以./configure --enable-threads,用-t参数指定threads数量。

iunknown     2007-07-27 21:07
引用
memcached 对 cache 对象 大小有什么限制 。

我在程序中 如果对象的大小 超过255kb 就出错。

从 error message 来看,出错的时候,size 不是 255kb 哦,而是

引用
[50:30.597] - ++++ error storing data in cache for key: test_key7 -- length: 1048603

1M = 1048576 ,这里显示的是 1048603 ,超过 1M 了。

这里有说明 memcached 的限制是 1M 。
http://lists.danga.com/pipermail/memcached/2006-October/002986.html

引用
The maximum size is 1 megabyte. It can be increased; I believe there was
a patch (against the old 1.1.12 version) to do it. The trick is that
memcached's memory manager allocates memory in 1MB chunks, so increasing
the maximum is not just a matter of changing a "maximum object size"
setting somewhere. But it is certainly doable.
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值