http://blog.chinaunix.net/u/26905/showart.php?id=255927
根据memcached-1.2.1的文档以及我对memcached的一些测试, 可以得到一些结论.
开启memcached:
memcached -d -m 10 -l 192.168.1.21 -p 11222 -u userA
这行命令会开启memcached服务,memcached在192.168.1.21:112222上面进行监听, 同时设置memcached使用的最大内存为10MB, memcached一开始并不会一下子申请10MB的内存, 而是在需要的时候才会使用malloc申请内存,当申请内存达到10MB时就不会再申请.
为了减少管理内存碎片的麻烦,当你需要通过memcached往缓存里面保存一个数据时, memcached给这个数据提供一个固定大小的内存块(chunk),比如数据的长度是100bytes,那么memcached提供一个大小为128b的chunk来存储该数据,chunk块的大小可以为64B,128B,256B...1024KB.使用何种大小的chunk块是由memcache根据数据的长度来决定的.
当你第一次往memcached存储数据时, memcached会去申请1MB的内存, 把该块内存称为一个slab, 也称为一个page, 如果可以存储这个数据的最佳的chunk大小为128B,那么memcached会把刚申请的slab以128B为单位进行分割成8192块. 当这页slab的所有chunk都被用完时,并且继续有数据需要存储在128B的chunk里面时,如果已经申请的内存小于最大可申请内存10MB时,memcached继续去申请1M内存,继续以128B为单位进行分割再进行存储;如果已经无法继续申请内存,那么mamcached会先根据LRU算法把队列里面最久没有被使用到的chunk进行释放后,再将该chunk用于存储.
chunk属于某个slab,slabs由memcached进行分组管理,以同样chunk大小进行分割的slab属于同一组.
对一组slab, memcached使用这样的几个内部变量进行管理:
total_pages
total_chunks
used_chunks
free_chunks
free_chunks_end
假设现在一组slab,它的chunk大小是128KB, total_pages =1, 那么
total_chunks = (1MB/128KB) * 1 = 8,
total_chunks=used_chunks + free_chunks,
free_chunks = 被使用过但是已经释放的chunk个数(注:个人理解)
free_chunks_end = 没有被使用过的chunk个数(注:个人理解)
used_chunks = free_chunks_end + 现在存储着数据的chunk个数
当一个数据在memcached中被删除时, 存储该数据的chunk被释放, 对应slab组的free_chunks++,
当有数据想添加到缓存里面时, memcached优先使用free_chunks里面的chunk, 如果free_chunks=0,再使用free_chunks_end里面的chunk, 如果连free_chunks_end也为0, 那么重新申请一页内存.
通过telnet 192.168.1.21 11222 可以连上memcached, 键入命令 stats slabs 可以看到所有slabs组的统计数据以及统计情况.
memcached安装包scripts/memcached-tool是一个可以查看memcached的slabs统计情况的perl脚本
为了避免使用memcached时出现异常, 使用memcached的项目需要注意:
1. 不能往memcached存储一个大于1MB的数据.
2. 往memcached存储的所有数据,如果数据的大小分布于各种chunk大小区间,从64B到1MB都有,可能会造成内存的极大浪费以及memcached的异常.
举个例子:
memcached最大可申请内存为2M, 你第一次存储一个10B的数据,那么memcached会申请1MB的内存,以64B进行分割然后存储该数据, 第二次存储一个90B的数据,那么memcached会继续申请1M的内存,以128B进行分割然后存储该数据, 第三次如果你想存储一个150B的数据, 如果可以继续申请内存, memcached会申请1M内存以256B的大小进行分割, 但是由于最大可申请仅仅为2MB,所以会导致该数据无法存储.