Memcached内存管理核心原理解析

Memcached入门到缓存组件的选型

前言

上篇文章做了memcached的安装和使用,以及使用命令去介绍,包括Memcached设计理念,Redis VS Memcached如何选择以及应用场景

本篇文章会从Memcached内存分配机制、memcached内存设计及管理、Memcached缓存策略 – LRU、包括分段LRU、LRU Crawler  等机制去理解Memcached。

Memcached内存分配机制

对于普通的内存机制是来需要一个内存,就给它一个内存区域,如果按照这种方式,是不适合缓存的,因为缓存中的数据有过期的概念,一旦过期,这块区域怎么处理,没法处理的,有大量的内存碎片。data不均匀的问题

因此memcached中有自己的一个内存管理机制,内存池的分配机制,而redis中内存管理采用zmalloc方式 。

像这种需要内存进行分配,我会想到netty中池化申请内存的方式,以达到内存复用的情况来解决频繁申请内存的方式。而Memcached 确实内存管理很像netty中池化内存的方式

内存分配

会在内存空间中申请一个page大小为1m,将1m数据分成若干个chunk内存块 ,然后提出了slab的概念 slab class去分别管理 不同page    而采用的 slab alloction 方式,内存池化的方式,避免碎片化,但免不了有些内存的浪费

 这里启动 Memcached 时,-m指定内存大小,将信息保存到缓存中后才开始分配和保留物理内存。 通过 Slab allocation 机制对内存进行管理。

还可以通过 -f 去调整增长因子 默认为1.25,去调整 chunk的固定大小

最大内存默认64,通过-m调整。
内存空间由slab classes构成,内存以slab page为单位去申
请,分配到对应的slab class。
slab page :最大1兆,由1个或多个chunk组成
chunk :实际存储数据的单元
通过 -vv可以看到分配信息

默认不允许存储1m的大小的内存,可以通过 -L参数去设置大小

 整个内存设计管理要达到的三个目标

高效键值数据索引 hash、高效的内存管理 slab alloction、能够自动删除长期不用的数据 惰性、LRU链表结构

内存设计及管理

  • Item
为键值数据的实际储存结构。item主要由公共属性、数据部分两个部分组成。
在源码中有展示这个item信息

 

 item就是包含元素据的key-value 数据包 item放到chunk里面

它是像链表一样,通过next 一步一步的往下走,纵向的链表,不会太深,保证o(1)复杂度

 

  • Chunk
由申请的连续内存块平均切分而成,用来存放Item数据,根据Item大小找到近似的Chunk。

 

  • Slab
管理特定大小的 chunk 的集合。Memcached每次默认分配的一个连续内存块为1M大小,它们被切分为不同大小 的chunk。
这都是在代码中可以看到

 

  • Hash table
Memcached的哈希表采用链接法实现。hashtable被分成多个桶bucket,哈希冲突,通过h_next指针形成bucket 下链接的单向链表。
  • LUR
Memcached中每个slab中都维护了一个LRU链表,来组织该slab中已经被分配的item块,用于记录“最近最少使 用”的item信息。

内存分配方式

预分配 、按需分配

初始化16开始,每次扩容进行翻倍数据

 slots维护空闲chunk双向链表。每次从链表头移除一个即可,归还时重新添加到链表头。

 

每个数据访问的最少就放到尾部来 然后进行淘汰尾部数据,记录新访问的数据

 默认就是1m大小的page,然后来数据时,进行扩容,访问最新时间,放到头里面去。

数据淘汰

如果内存已经用完,通过LRU链表进行尾部淘汰

Memcached缓存策略 –LRU

在1.4.x及更早版本中,memcached中的LRU是标准的双向链表:有头部和尾部。将新物品插入头部,从尾部弹出驱逐物。
如果访问某个项目,则将其从其位置取消链接,然后重新链接到头部(此处称为“碰撞”),返回到LRU的顶部。

 

下面这些情况,带有超时时间的记录会被删除
1. 被人为删除
2. 被set覆盖
3. 被动删除:过期后,被get、add等命令访问
4. 主动清除:LRU机制

 

 碰撞几率太高,对同一个链表的修改导致大量的互斥锁争抢,导致CPU使用率高或者响应变慢。

 分段LRU

将原来的LRU双向链表,分段变成四个链表。temp 过期的key ,不关心是不是最近访问了hot 也不关心LRU算法排序;item存在两种状态,fetched 是否访问过,active 访问过两次以上。

每个Slab-class安排一个LRU,每个LRU拆分为四个子LRU类型。
每个存储的数据都有两个标志位:FETCHED、ACTIVE
  • FETCHED:该数据曾经被请求过
  •  ACTIVE: 该数据有两次或以上被请求,当数据被移动时移除。
TEMP : 该队列中的 item TTL 通常只有几秒,不会被挪动。 具体时间可配置 stats settings temporary_ttl选项
HOT :试用队列,数据不会长久存在该链表,一旦数据到达队列的尾部,则开始移动。
如果物品处于活动状态, 它将被移动到WARM,非活动状态,它将被移动到COLD。
WARM : 访问量不大的数据 如果物品处于活动状态, 它将被移动到warm头部,非活动状态,它将被移动到COLD。
COLD :最不活跃的数据 回收时如果处于active状态,则移动到warm,否则删除。
总结:碰撞率变小了,提高了性能。

 

LRU Crawler

LRU爬虫是一个单独的后台线程
专门用来处理失效的数据
检查每个slab class中每个子LRU链表

 

 

おすすめ

転載: blog.csdn.net/qq_33373609/article/details/120895204