memcached 简介
memcache是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。Memcache是danga.com的一个项目,最早是为 LiveJournal 服务的,最初为了加速 LiveJournal 访问速度而开发的,后来被很多大型的网站采用。目前全世界不少人使用这个缓存项目来构建自己大负载的网站,来分担数据库的压力。起初作者编写它可能是为了提高动态网页应用,为了减轻数据库检索的压力,来做的这个缓存系统。它的缓存是一种分布式的,也就是可以允许不同主机上的多个用户同时访问这个缓存系统,这种方法不仅解决了共享内存只能是单机的弊端,同时也解决了数据库检索的压力,最大的优点是提高了访问获取数据的速度!基于memcache作者对分布式 cache的理解和解决方案。 memcache完全可以用到其他地方 比如分布式数据库, 分布式计算等领域。
memcached 协议
memcached 协议简单的说有一组规定好的字符串组成,例如:
memcached 和nginx 结合使用:
原文地址:
http://www.igvita.com/2008/02/11/nginx-and-memcached-a-400-boost/
配置例子:
架构图:
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
find slab id
以下是根据slabid计算chunk大小的公式(1.2版本):
id = 0 的slab 永远都是 80字节每个chunk,除非你重编译源码
那么 id为0的slab有 (1024* 1024)/80= 13107 个chunk
memcached1.2版本 会初始化 id 到 40.
直到 chunk 大小为1M,最有一个slab_id中对应的chunk只有一个。
那么memcached为什么使用这种方式存储那,是因为通过chunk的大小就能得到slab_id,从而找到slab,但是,这样做有一个缺点就是空间利用率下降了,chunk的大小可能不会是1M的整数倍.
计算slab_id公式如下:
你知道了slab和chunk的关系,就可以改变factor 来优化你的memcached了。
需要提醒的是,因为id=0的chunk为80字节,如果你保存的数据超过80字节,性能会有一些损耗。
修改chunk size
根据以上代码我发现,memcache slab 只取一个 slab_class ,需要如下修改
如下结果
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滴大小
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
memcache是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。Memcache是danga.com的一个项目,最早是为 LiveJournal 服务的,最初为了加速 LiveJournal 访问速度而开发的,后来被很多大型的网站采用。目前全世界不少人使用这个缓存项目来构建自己大负载的网站,来分担数据库的压力。起初作者编写它可能是为了提高动态网页应用,为了减轻数据库检索的压力,来做的这个缓存系统。它的缓存是一种分布式的,也就是可以允许不同主机上的多个用户同时访问这个缓存系统,这种方法不仅解决了共享内存只能是单机的弊端,同时也解决了数据库检索的压力,最大的优点是提高了访问获取数据的速度!基于memcache作者对分布式 cache的理解和解决方案。 memcache完全可以用到其他地方 比如分布式数据库, 分布式计算等领域。
memcached 协议
memcached 协议简单的说有一组规定好的字符串组成,例如:
- socket.write "get #{cache_key}\r\n"
- socket.write "gets #{cache_key}\r\n"
- socket.write "incr #{cache_key} #{amount}#{noreply}\r\n"
memcached 和nginx 结合使用:
原文地址:
http://www.igvita.com/2008/02/11/nginx-and-memcached-a-400-boost/
配置例子:
- location /dynamic_request {
- # append an extenstion for proper MIME type detection
- if ($args ~* format=json) { rewrite ^/dynamic_request/?(.*)$ /dynamic_request.js$1 break; }
- if ($args ~* format=xml) { rewrite ^/dynamic_request/?(.*)$ /dynamic_request.xml$1 break; }
- memcached_pass 127.0.0.1:11211;
- error_page 404 = @dynamic_request;
- }
架构图:
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
- class SlabClass
- {
- int size #chunk size
- int perslab chunk个数
- Array *slot #空闲槽
- int slabs #slab 数量
- Array * slab_list 指针数值 1M slab #不够就申请slab,并加入slab_list 中。
- }
find slab id
- unsigned int slabs_clsid(const size_t size) {
- int res = POWER_SMALLEST;
- if (size == 0)
- return 0;
- while (size > slabclass[res].size)
- if (res++ == power_largest) /* won't fit in the biggest slab */
- return 0;
- return res;
- }
以下是根据slabid计算chunk大小的公式(1.2版本):
- chunk 大小 = 初始大小 * factor ^ id
- slab_id = 0
- chunk 大小 = 80字节 * 1.25 ^ 0
- slab_id = 1
- chunk 大小 = 80字节 * 1.25 ^ 1
id = 0 的slab 永远都是 80字节每个chunk,除非你重编译源码
那么 id为0的slab有 (1024* 1024)/80= 13107 个chunk
memcached1.2版本 会初始化 id 到 40.
- :~> memcached -vvv
- slab class 1: chunk size 96 perslab 10922
- slab class 2: chunk size 120 perslab 8738
- slab class 3: chunk size 152 perslab 6898
- slab class 4: chunk size 192 perslab 5461
- slab class 5: chunk size 240 perslab 4369
- slab class 6: chunk size 304 perslab 3449
- slab class 7: chunk size 384 perslab 2730
- slab class 8: chunk size 480 perslab 2184
- slab class 9: chunk size 600 perslab 1747
- slab class 10: chunk size 752 perslab 1394
- slab class 11: chunk size 944 perslab 1110
- slab class 12: chunk size 1184 perslab 885
- slab class 13: chunk size 1480 perslab 708
- slab class 14: chunk size 1856 perslab 564
- slab class 15: chunk size 2320 perslab 451
- slab class 16: chunk size 2904 perslab 361
- slab class 17: chunk size 3632 perslab 288
- slab class 18: chunk size 4544 perslab 230
- slab class 19: chunk size 5680 perslab 184
- slab class 20: chunk size 7104 perslab 147
- slab class 21: chunk size 8880 perslab 118
- slab class 22: chunk size 11104 perslab 94
- slab class 23: chunk size 13880 perslab 75
- slab class 24: chunk size 17352 perslab 60
- slab class 25: chunk size 21696 perslab 48
- slab class 26: chunk size 27120 perslab 38
- slab class 27: chunk size 33904 perslab 30
- slab class 28: chunk size 42384 perslab 24
- slab class 29: chunk size 52984 perslab 19
- slab class 30: chunk size 66232 perslab 15
- slab class 31: chunk size 82792 perslab 12
- slab class 32: chunk size 103496 perslab 10
- slab class 33: chunk size 129376 perslab 8
- slab class 34: chunk size 161720 perslab 6
- slab class 35: chunk size 202152 perslab 5
- slab class 36: chunk size 252696 perslab 4
- slab class 37: chunk size 315872 perslab 3
- slab class 38: chunk size 394840 perslab 2
- slab class 39: chunk size 493552 perslab 2
- slab class 40: chunk size 616944 perslab 1
- slab class 41: chunk size 771184 perslab 1
- slab class 42: chunk size 1048576 perslab 1
- <26 server listening (auto-negotiate)
- <27 send buffer was 124928, now 268435456
- <28 send buffer was 124928, now 268435456
直到 chunk 大小为1M,最有一个slab_id中对应的chunk只有一个。
那么memcached为什么使用这种方式存储那,是因为通过chunk的大小就能得到slab_id,从而找到slab,但是,这样做有一个缺点就是空间利用率下降了,chunk的大小可能不会是1M的整数倍.
计算slab_id公式如下:
- factor^id = chunk 大小 / 初始大小
- id = log(chunk 大小 / 初始大小 ) / log(factor)
- 这样通过chunk 大小就能得到 slab id 了.
- 例如:
- id = log(80字节 / 80字节) / log(1.25) = 0
你知道了slab和chunk的关系,就可以改变factor 来优化你的memcached了。
需要提醒的是,因为id=0的chunk为80字节,如果你保存的数据超过80字节,性能会有一些损耗。
修改chunk size
- /* 修改slab.c 文件中的 slabs_init方法 */
- while (++i < POWER_LARGEST && size <= settings.item_size_max / factor) {
- /* Make sure items are always n-byte aligned */
- if (size % CHUNK_ALIGN_BYTES)
- size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES);
- slabclass[i].size = 200 /*size;*/
- slabclass[i].perslab = 5000 /*settings.item_size_max / slabclass[i].size;*/
- size *= factor;
- if (settings.verbose > 1) {
- fprintf(stderr, "slab class %3d: chunk size %9u perslab %7u\n",
- i, slabclass[i].size, slabclass[i].perslab);
- }
- }
- slab class 1: chunk size 200 perslab 5000
- slab class 2: chunk size 200 perslab 5000
- slab class 3: chunk size 200 perslab 5000
- slab class 4: chunk size 200 perslab 5000
- slab class 5: chunk size 200 perslab 5000
- slab class 6: chunk size 200 perslab 5000
- slab class 7: chunk size 200 perslab 5000
- slab class 8: chunk size 200 perslab 5000
- slab class 9: chunk size 200 perslab 5000
- # Item_Size Max_age 1MB_pages Count Full?
- 1 200 B 245 s 2 5139 no
- # Item_Size Max_age 1MB_pages Count Full?
- 1 200 B 245 s 5 21966 no
根据以上代码我发现,memcache slab 只取一个 slab_class ,需要如下修改
- /* 修改slabs_clsid */
- unsigned int slabs_clsid(size_t size) {
- return 1;
- }
- /* 修改slab_init */
- void slabs_init(const size_t limit, const double factor, const bool prealloc) {
- //while (++i < POWER_LARGEST && size <= settings.item_size_max / factor) {
- // /* Make sure items are always n-byte aligned */
- // if (size % CHUNK_ALIGN_BYTES)
- // size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES);
- //
- // slabclass[i].size = 200;//size;
- // slabclass[i].perslab = 5000;/*settings.item_size_max / slabclass[i].size;*/
- // size *= factor;
- // if (settings.verbose > 1) {
- // fprintf(stderr, "slab class %3d: chunk size %9u perslab %7u\n",
- // i, slabclass[i].size, slabclass[i].perslab);
- // }
- // }
- i = 1;
- power_largest = i;
- slabclass[1].size = 200; //settings.item_size_max;
- slabclass[1].perslab = 5000;
- //slabclass[power_largest].size = settings.item_size_max;
- //slabclass[power_largest].perslab = 1;
如下结果
- slab class 1: chunk size 200 perslab 5000
- # Item_Size Max_age 1MB_pages Count Full?
- 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滴大小
- -I Override the size of each slab page. Adjusts max item size
- (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