memcached 深度解剖

  memcached 简介  
 memcache是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。Memcache是danga.com的一个项目,最早是为 LiveJournal 服务的,最初为了加速 LiveJournal 访问速度而开发的,后来被很多大型的网站采用。目前全世界不少人使用这个缓存项目来构建自己大负载的网站,来分担数据库的压力。起初作者编写它可能是为了提高动态网页应用,为了减轻数据库检索的压力,来做的这个缓存系统。它的缓存是一种分布式的,也就是可以允许不同主机上的多个用户同时访问这个缓存系统,这种方法不仅解决了共享内存只能是单机的弊端,同时也解决了数据库检索的压力,最大的优点是提高了访问获取数据的速度!基于memcache作者对分布式 cache的理解和解决方案。 memcache完全可以用到其他地方 比如分布式数据库, 分布式计算等领域。 

memcached 协议  

memcached 协议简单的说有一组规定好的字符串组成,例如: 
Java代码   收藏代码
  1. socket.write "get #{cache_key}\r\n"  
  2. socket.write "gets #{cache_key}\r\n"  
  3. socket.write "incr #{cache_key} #{amount}#{noreply}\r\n"  
  4.    


memcached 和nginx 结合使用:  
原文地址: 
http://www.igvita.com/2008/02/11/nginx-and-memcached-a-400-boost/ 
配置例子: 
Java代码   收藏代码
  1.   location /dynamic_request {  
  2.        # append an extenstion for proper MIME type detection  
  3.            if ($args ~* format=json) { rewrite ^/dynamic_request/?(.*)$ /dynamic_request.js$1 break; }  
  4.            if ($args ~* format=xml)  { rewrite ^/dynamic_request/?(.*)$ /dynamic_request.xml$1 break; }  
  5.    
  6.            memcached_pass 127.0.0.1:11211;  
  7.            error_page 404 = @dynamic_request;  
  8. }  

架构图:  
 

memcached 内部数据存储分析:  
memcached 的数据结构可以简单的有slab -> chunks 来描述,slab 可以理解为一个内存块,一个slab是memcached一次申请内存的最小单位,在memcache中,一个slab大小默认为1M,每个slab被划分为若干个chunk,每个chunk里保存一个item,slab安装自己的id分别组成链表,这些链表又按id挂在一个slabclass数组上,整个结构看起来有点像二维数组。slabclass的长度在memcached 1.1中是21,在memcached 1.2中是200。 
slab有一个初始chunk大小,memcached1.1中是1字节,memcached1.2中是80字节, 
memcached 1.2中有一个factor值,默认为1.25, memcached -help 查看一下参数factor 

SlabClass(1.2版本) 
id 从 0 开始 
|------| 0          slab 
|  id1 | ------->|-------| 
|  id2 |            |chunk| -> item {key:value} 这个根据slabId 计算chunk大小 
|   ..   |            |   ....   | 
|------| 199 

C代码   收藏代码
  1. class SlabClass  
  2. {  
  3.     int size #chunk size  
  4.     int perslab chunk个数  
  5.     Array *slot #空闲槽  
  6.     int slabs #slab 数量  
  7.     Array * slab_list 指针数值 1M slab #不够就申请slab,并加入slab_list 中。  
  8. }  


find slab id  
C代码   收藏代码
  1. unsigned int slabs_clsid(const size_t size) {  
  2.     int res = POWER_SMALLEST;  
  3.   
  4.     if (size == 0)  
  5.         return 0;  
  6.     while (size > slabclass[res].size)  
  7.         if (res++ == power_largest)     /* won't fit in the biggest slab */  
  8.             return 0;  
  9.     return res;  
  10. }  


以下是根据slabid计算chunk大小的公式(1.2版本):  
Java代码   收藏代码
  1. chunk 大小 = 初始大小 * factor ^ id   
  2. slab_id  =  0  
  3. chunk 大小 = 80字节 * 1.25 ^ 0  
  4. slab_id  =  1  
  5. chunk 大小 = 80字节 * 1.25 ^ 1  

id = 0 的slab 永远都是 80字节每个chunk,除非你重编译源码 
那么 id为0的slab有 (1024* 1024)/80= 13107 个chunk 
memcached1.2版本 会初始化 id 到 40. 



Java代码   收藏代码
  1. :~> memcached -vvv  
  2. slab class   1: chunk size        96 perslab   10922  
  3. slab class   2: chunk size       120 perslab    8738  
  4. slab class   3: chunk size       152 perslab    6898  
  5. slab class   4: chunk size       192 perslab    5461  
  6. slab class   5: chunk size       240 perslab    4369  
  7. slab class   6: chunk size       304 perslab    3449  
  8. slab class   7: chunk size       384 perslab    2730  
  9. slab class   8: chunk size       480 perslab    2184  
  10. slab class   9: chunk size       600 perslab    1747  
  11. slab class  10: chunk size       752 perslab    1394  
  12. slab class  11: chunk size       944 perslab    1110  
  13. slab class  12: chunk size      1184 perslab     885  
  14. slab class  13: chunk size      1480 perslab     708  
  15. slab class  14: chunk size      1856 perslab     564  
  16. slab class  15: chunk size      2320 perslab     451  
  17. slab class  16: chunk size      2904 perslab     361  
  18. slab class  17: chunk size      3632 perslab     288  
  19. slab class  18: chunk size      4544 perslab     230  
  20. slab class  19: chunk size      5680 perslab     184  
  21. slab class  20: chunk size      7104 perslab     147  
  22. slab class  21: chunk size      8880 perslab     118  
  23. slab class  22: chunk size     11104 perslab      94  
  24. slab class  23: chunk size     13880 perslab      75  
  25. slab class  24: chunk size     17352 perslab      60  
  26. slab class  25: chunk size     21696 perslab      48  
  27. slab class  26: chunk size     27120 perslab      38  
  28. slab class  27: chunk size     33904 perslab      30  
  29. slab class  28: chunk size     42384 perslab      24  
  30. slab class  29: chunk size     52984 perslab      19  
  31. slab class  30: chunk size     66232 perslab      15  
  32. slab class  31: chunk size     82792 perslab      12  
  33. slab class  32: chunk size    103496 perslab      10  
  34. slab class  33: chunk size    129376 perslab       8  
  35. slab class  34: chunk size    161720 perslab       6  
  36. slab class  35: chunk size    202152 perslab       5  
  37. slab class  36: chunk size    252696 perslab       4  
  38. slab class  37: chunk size    315872 perslab       3  
  39. slab class  38: chunk size    394840 perslab       2  
  40. slab class  39: chunk size    493552 perslab       2  
  41. slab class  40: chunk size    616944 perslab       1  
  42. slab class  41: chunk size    771184 perslab       1  
  43. slab class  42: chunk size   1048576 perslab       1  
  44. <26 server listening (auto-negotiate)  
  45. <27 send buffer was 124928, now 268435456  
  46. <28 send buffer was 124928, now 268435456  


直到 chunk 大小为1M,最有一个slab_id中对应的chunk只有一个。 
那么memcached为什么使用这种方式存储那,是因为通过chunk的大小就能得到slab_id,从而找到slab,但是,这样做有一个缺点就是空间利用率下降了,chunk的大小可能不会是1M的整数倍. 
计算slab_id公式如下:  
Java代码   收藏代码
  1. factor^id = chunk 大小 /  初始大小  
  2. id = log(chunk 大小 /  初始大小 ) / log(factor)  
  3. 这样通过chunk 大小就能得到 slab id 了.  
  4. 例如:  
  5. id = log(80字节 / 80字节) / log(1.25) = 0  


你知道了slab和chunk的关系,就可以改变factor 来优化你的memcached了。 
需要提醒的是,因为id=0的chunk为80字节,如果你保存的数据超过80字节,性能会有一些损耗。 

修改chunk size  
C代码   收藏代码
  1. /* 修改slab.c 文件中的 slabs_init方法 */  
  2.   
  3.  while (++i < POWER_LARGEST && size <= settings.item_size_max / factor) {  
  4.         /* Make sure items are always n-byte aligned */  
  5.         if (size % CHUNK_ALIGN_BYTES)  
  6.             size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES);  
  7.   
  8.         slabclass[i].size = 200 /*size;*/  
  9.         slabclass[i].perslab = 5000 /*settings.item_size_max / slabclass[i].size;*/  
  10.         size *= factor;  
  11.         if (settings.verbose > 1) {  
  12.             fprintf(stderr, "slab class %3d: chunk size %9u perslab %7u\n",  
  13.                     i, slabclass[i].size, slabclass[i].perslab);  
  14.         }  
  15.     }  


Bash代码   收藏代码
  1. slab class   1: chunk size       200 perslab    5000  
  2. slab class   2: chunk size       200 perslab    5000  
  3. slab class   3: chunk size       200 perslab    5000  
  4. slab class   4: chunk size       200 perslab    5000  
  5. slab class   5: chunk size       200 perslab    5000  
  6. slab class   6: chunk size       200 perslab    5000  
  7. slab class   7: chunk size       200 perslab    5000  
  8. slab class   8: chunk size       200 perslab    5000  
  9. slab class   9: chunk size       200 perslab    5000  


Bash代码   收藏代码
  1.    
  2. #  Item_Size   Max_age  1MB_pages Count   Full?  
  3.        1     200 B      245 s       2         5139      no  
  4. #  Item_Size   Max_age  1MB_pages Count   Full?  
  5.       1     200 B      245 s       5         21966      no    


根据以上代码我发现,memcache slab 只取一个 slab_class ,需要如下修改 
C代码   收藏代码
  1. /* 修改slabs_clsid */  
  2. unsigned int slabs_clsid(size_t size) {  
  3.         return 1;  
  4. }  
  5.   
  6. /* 修改slab_init */  
  7. void slabs_init(const size_t limit, const double factor, const bool prealloc) {  
  8.   
  9. //while (++i < POWER_LARGEST && size <= settings.item_size_max / factor) {                                                    
  10.     //    /* Make sure items are always n-byte aligned */                                                                         
  11.     //    if (size % CHUNK_ALIGN_BYTES)                                                                                           
  12.     //        size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES);                                                             
  13.     //                                                                                                                            
  14.     //       slabclass[i].size = 200;//size;                                                                                      
  15.     //  slabclass[i].perslab = 5000;/*settings.item_size_max / slabclass[i].size;*/                                               
  16.     //  size *= factor;                                                                                                           
  17.     //  if (settings.verbose > 1) {                                                                                               
  18.     //      fprintf(stderr, "slab class %3d: chunk size %9u perslab %7u\n",                                                       
  19.     //               i, slabclass[i].size, slabclass[i].perslab);                                                                 
  20. //  }                                                                                                                             
  21. //  }                                                                                                                             
  22.     i = 1;  
  23.     power_largest = i;                                                                                                          
  24.   
  25.     slabclass[1].size = 200; //settings.item_size_max;                                                                            
  26.     slabclass[1].perslab = 5000;  
  27.   
  28.     //slabclass[power_largest].size = settings.item_size_max;                                                                     
  29.     //slabclass[power_largest].perslab = 1;     


如下结果 
Bash代码   收藏代码
  1. slab class   1: chunk size       200 perslab    5000  
  2.   
  3. #  Item_Size   Max_age  1MB_pages Count   Full?  
  4.       1     200 B        7 s       3            10137      no  



Memcached一些特性和限制 
在 Memcached 中可以保存的item数据量是没有限制的,只有内存足够 
最大30天的数据过期时间, 设置为永久的也会在这个时间过期,常量REALTIME_MAXDELTA 60*60*24*30 控制 
最大键长为250字节,大于该长度无法存储,常量KEY_MAX_LENGTH 250 控制 
单个item最大数据是1MB,超过1MB数据不予存储,常量POWER_BLOCK 1048576 进行控制,它是默认的slab大小 
最大同时连接数是200,通过 conn_init()中的freetotal 进行控制,最大软连接数是1024,通过 settings.maxconns=1024 进行控制 
跟空间占用相关的参数:settings.factor=1.25, settings.chunk_size=48, 影响slab的数据占用和步进方式 

在新版本中可以使用 -I  来设置slab滴大小 

Java代码   收藏代码
  1. -I            Override the size of each slab page. Adjusts max item size  
  2.               (default: 1mb, min: 1k, max: 128m)  




As far as this list is concerned, if you run a 32-bit 
Linux OS, memcached can only use 2GB of memory for the entire process.  That 
includes the memory needed for connections.  If you run a 64-bit Linux  OS you do not have this limit 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值