1 功能简述
1.1 Automove功能背景
由于memcache的内存分配是基于slab的,每个1M的page内只能存放对应slab大小范围的value值。具体原理见:http://dev.mysql.com/doc/refman/5.0/en/ha-memcached-using-memory.html 。
因为这种模式带来的问题也会随着实例的运行时间的增加而凸显。假设实例在运行初期,业务模型存放的都是1k大小的value值,并且把memcache的内存耗尽。此时,memcache的内部全部都是1k类型的slab。随着业务发展value大小变化到了2k,此时需要2k类型的slab存放,这时memcache就会在一个2k类型的page内不断evict为新的key腾出空间。而之前已经分配完毕的1k-slab则毫无用途。这样的情况显然会造成内存使用的不合理,和2k类型key的命中率大幅度降低,以及memcached eviction计数器大量增加的情况。
memcache为了解决因slab引起的内存使用不合理的问题,在1.4.11中引入了slab automove的功能。本文将围绕这个功能进行功能和性能上的测试。
slab automove实现原理简单叙述如下:
The algorithm is slow and conservative. If a slab class is seen as having the highest eviction count 3 times 10 seconds apart, it will take a page from a slab class which has had zero evictions in the last 30 seconds and move the memory. (摘自memcache wiki,详见http://code.google.com/p/memcached/wiki/ReleaseNotes1411)
1.2 Automove 功能的使用
automove分配手动重分配和自动重分配。
手动:
memcache启动时加上参数:memcached -o slab_reassign
cache运行时,执行以下命令:
echo "slabs reassign 1 4" | nc localhost 11211
自动重分配:
memcache启动时加上参数:memcached -o slab_reassign,slab_automove
之后cache就会以每10秒一次的频率进行重分配。
也可以临时停止自动重分配:echo "slabs automove 0" | nc localhost 11211
2 测试过程和结果分析
2.1 测试环境
操作系统:CentOS release 6.3 (Final)
内核版本:2.6.32-279.el6.x86_64
CPU:Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz
memcache版本:1.4.15
memcache内存:128M
2.2 测试方法
测试通过多个并发访问memcache,记录响应时间后作图的方式进行比较。
测试脚本为自己编写的perl脚本。主要步骤如下:
从一个并发到二十并发循环进行以下操作
-
slab预分配(保证内存被某种slab耗尽)
-
slab 超时get(清空之前所有的slab,并保证之前分配的slab类型不变)
-
测试正式开始
-
预分配slab类型的set,并记录响应时间,作为比较基准
-
新slab类型的set ,并记录响应时间,作为比较对象
2.3 slab富裕 vs slab紧张
测试目的:分析slab类型紧张和富裕时的set响应时间是否有差异,来说明当某个slab类型紧缺时是否会对前端业务产生响应时间的影响
从下图的测试结果可以看到当slab类型分配紧张时的set响应时间明显高于slab类型分配富裕的时候。从理论上也比较容易理解这个结果。因为当该类型的所有slab均满的时候,memcache需要做LRU list上的eviction才能腾出空间记录新的key,而这个额外步骤也造成了set响应时间的增加。
2.4 automove开启 (未使用)vs automove关闭
测试目的:由于automove是由一个额外的异步线程实现的功能。因此这个测试通过比较功能的开关是否会对set响应时间有影响,来说明额外线程是否有额外性能损耗。
从第一章的介绍可以看出,slab的automove是一个10秒循环的异步线程管理的。因此当测试时间少于10秒时,就可以模拟automove开启但未使用的情况。
测试结果:从下图可以看到, 后台线程的存在对原有响应时间的pattern并没有很大的影响。因此,开启slab automove后在没有使用的情况下,没有不良影响
2.5 automove开启(且使用) vs automove关闭
测试目的:这个测试用于观察automove开启后,slab类型重新分配后对性能是否能带来显著提升。
测试结果:从下图可以看出,相较automove关闭时,slab的重新分配确实能够带来一定程度上响应时间的提升。但效果并不明显,主要是因为slab的重新分配只是10秒一次的后台作业,需要一段非常长的时间后,slab的类型才能趋于合理稳定。当然automove的主要目的并不在于直接提高cache的响应速度,而在于slab分配合理后,key的命中率能有一定程序的提高,减少后端数据库和service的访问压力。
从测试结束后的slab情况来看,开启automove后,因为测试时间较短,只有少量slab被重新分配。
memcached-tool localhost:11211 display
# Item_Size Max_age Pages Count Full? Evicted Evict_Time OOM
12 1.2K 9s 120 106072 yes 0 0 0
13 1.4K 0s 8 5664 yes 74051 0 0
3 测试结论
以下是测试的主要结论:
-
因为slab不足的cache miss的响应时间,会比cache hit的响应时间略多
-
开启automove后台线程对于响应时间没有副作用
-
开启automove对于cache访问的响应时间提升有限
-
开启automove的主要意义在于合理使用内存,提升key的命中率,降低后端系统压力
综上,认为automove可以比较放心的在线上开启使用。
Memcache Slab Reassignment
Reallocating pages from one slab to another was not possible until memcache 1.4.11 came into release (http://code.google.com/p/memcached/wiki/ReleaseNotes1411)
Memcache memory allocation could be of trouble if your keys changes slabs. For ex, consider you have a memcache of 64GB. This memcache has been in production for about an year with most of the keys in slab 1 & 2 and memcache at 60GB full. One day you decide to change key size in code, and this key will now fall under slab 3 & 4. NOTE: Now you only have 4 GB left. Once you hit this limit, memcache will start evicting keys from slab 3 & 4 to make space for new items. Ideally, it should give you memory from slab 1 & 2 which is not used now due to slab shift. Moving memory from one slab to another started from 1.4.11 release.
Memcache allocates memory in count of pages, which doing slab reallocation.
Syntax: slabs reassign <source slab> <dest slab>
For ex,
# This will allocate 1 page from slab 3 to slab 5. That will return an error code indicating success, or a need to retry later. Success does not mean that the slab was moved, but that a background thread will attempt to move the memory as quickly as it can.
$ echo 'slabs reassign 3 5' | nc localhost 11211;
# If you want to allocate 100 pages from slab 3 to slab 5
$ for i in `seq 1 100`; do sleep 1; echo 'slabs reassign 3 5' | nc localhost 11211; done
# Find out how many pages have been moved across slabs:
$ echo stats | nc 0 11211 | grep slabs_moved
STAT slabs_moved 3984
Memcache Slab Automove
While slab reassign is a manual feature, there is also the start of an automatic memory reassignment algorithm.
$ memcached -o slab_reassign,slab_automove
The above enables it on startup. slab_automove requires slab_reassign first be enabled. Automove itself may also be enabled or disabled at runtime:
$ echo "slabs automove 0" | nc localhost 11211
for((i=0;i<1000000000;i++)); do printf "set 1_verifyToken_renter_login_to_$i 0 0 1\r\n1\r\n" | nc 127.0.0.1 11211; done;
for((i=0;i<100000;i++)); do printf "set 1_verifyToken_renter_login_to_$i 0 60 124\r\n123456789012345678901234567890ab123456789012345678901234567890123456789012345678901234567890ab123456789012345678901234567890\r\n" | nc 127.0.0.1 11211; done;
for((i=0;i<100000;i++)); do printf "set 1_verifyToken_renter_login_to_$i 0 0 256\r\n123456789012345678901234567890ab123456789012345678901234567890ab123456789012345678901234567890ab123456789012345678901234567890ab123456789012345678901234567890ab123456789012345678901234567890ab123456789012345678901234567890ab123456789012345678901234567890ab\r\n" | nc 127.0.0.1 11211; done;