谈谈 Memcached LRU

一. Memcached 内存结构


可以看出 Memcached 将内存分为一个一个 slab class,slab class 没有大小,所有的 slab class 加起来就是 Memcached 启动时设置的内存大小。slab class 里面有 slab page,slab class 大小由 slab page 个数决定,默认的 slab page 为 1M,可以在启动 Memcached 时设置。slab page 里又分为同等大小的 chunk,chunk 就是存储缓存的基本单元,chunk 大小,不同 slab class 的 page 大小一致,但是 chunk 大小不一致,默认 class1 的 chunk 大小为 96 byte,不同 class 的 chunk 大小由启动时设置的 factor 系数决定,下一个 class 的 chunk 是上一个 class 的 chunk 的 1.25 倍(默认是 1.25)。


Memcached默认情况下采用了名为Slab Allocator的机制分配、管理内存。在该机制出现以前,内存的分配是通过对所有记录简单地进行malloc和free来进行的。但是,这种方式会导致内存碎片,加重操作系统内存管理器的负担,最坏的情况下,会导致操作系统比memcached进程本身还慢。Slab Allocator就是为解决该问题而诞生的。


      Slab Allocator的基本原理是按照预先规定的大小,将分配的内存以page为单位,默认情况下一个page是1M,可以通过-I参数在启动时指定,分割成各种尺寸的块(chunk), 并把尺寸相同的块分成组(chunk的集合),如果需要申请内存时,memcached会划分出一个新的page并分配给需要的slab区域。page一旦被分配在重启前不会被回收或者重新分配,以解决内存碎片问题。



二. 如何分配

Memcached在启动时通过-m参数指定最大使用内存,但是这个不会一启动就占用完,而是逐步分配给各slab的。如果一个新的数据要被存放,首先选择一个合适的slab(存入的数据大小和 chunk 大小最接近,这样可以减少内部碎片的浪费),然后查看该slab是否还有空闲的chunk,如果有则直接存放进去;如果没有则要进行申请,slab申请内存时以page为单位,无论大小为多少,都会有1M大小的page被分配给该slab(该page不会被回收或者重新分配,永远都属于该slab)。申请到page后,slab会将这个page的内存按chunk的大小进行切分,这样就变成了一个chunk的数组,再从这个chunk数组中选择一个用于存储数据。若没有空闲的page的时候,则会对改slab进行LRU,而不是对整个memcache进行LRU。(PS:局部 LRU)



三. 面临的问题

在这样的内存结构和内存分配的策略上,会有一些典型的问题,比如 Memcached 还有一般的空闲内存,但是进行了 LRU,原因就是某些缓存数据大小相近的都是分配在某个 slab class 上,这些数据又是热数据,又不断有加入的新数据,因为是局部 LRU,所以导致在这个 slab class 上频繁进行 LRU,但是其他 slab class 里面却有大量空闲空间。这样的情况如果频繁,可以考虑调小 factor,这样大小类似的数据可能会分配到不同的 slab class 上,减少 LRU 情况。



猜你喜欢

转载自blog.csdn.net/wenniuwuren/article/details/51727326
LRU