Memcached原理

来源:互联网 发布:安卓淘宝秒杀器 编辑:程序博客网 时间:2024/06/07 01:10

Memcached是一款开源的、高性能的、基于内存的key-value的分布式内存对象缓存系统,可应用各种需要缓存的场景,其主要目的是通过降低对数据库的访问来加速web应用程序。

缓存方式

enter description here

主要特征

  • 基于C/S架构,协议简单
  • 基于libevent的事件处理
  • 自主内存存储处理
  • 基于客户端的Memcached分布式

本文则通过其主要特征认识mecached

简单的底层协议

memcached基于C/S架构。客户端和 memcached的服务器通信并不使用复杂的XML等格式,而使用简单的基于文本行的协议。
因此,通过telnet也能在memcached上保存数据、取得数据。

通过telnet作为客户端与memcacehed服务器端通信

$ telnet localhost 11211Trying 127.0.0.1Connected to localhost.localdomain (127.0.0.1).Escape character is '^]'.set foo 0 0 3     # 设置key bar               # 输入保存的数据STORED            # 结果保存成功get foo           # 获取keyVALUE foo 0 3     # 成功取到数据bar 

事件处理方式

memcached采用基于libevent的事件处理机制。
libevent库将Linux的epoll、BSD类操作系统的kqueue等事件处理功能封装成统一的跨平台的事件处理接口。即使对服务器的连接数增加,也能发挥O(1)的性能。Memcached使用libevent来进行网络并发连接的处理,能够保持在很大并发情况下,仍旧能够保持快速的响应能力。

存储方式

为了提高性能,memcached中保存的数据都存储在memcached内置的内存存储空间中。memcached采用自主内存管理的方式,内存管理方式将直接决定其性能,我们将从两方面认识其内存管理方式:

  • 数据的存储方式 Slab Allocation
  • 数据过期方式Lazy Expiration + LRU

数据存储
内存的碎片化
当我们使用C语言或者其他语言进行malloc,free等类似的命令操作内存的时候,在不断的申请和释放的过程中,形成了一些很小的内存片段,我们无法继续的利用,那这种空闲,无法继续利用内存的情况,我们称之为内存的碎片化。

memcached使用slab allocator的机制来管理内存
Slab Allocator 的基本原理是按照预先规定的大小,将分配的内存分割成数个slab class仓库。各个仓库切分成不同尺寸的小块(chunk)。
Slab Alloction 构造图

enter description here

memcached根据收到的数据的大小,选择最合适数据大小的chunk组(slab class),在memcached中保存着slab class内空闲chunk的列表,根据列表选择空的chunk,然后将数据缓存其中

Slab Classes分配图

enter description here

由于slab allocate机制中,分配的chunk的大小是固定的。因此,对于特定的item,可能更会造成内存的浪费
比如说:将100字节的数据缓存到122字节的chunk中,剩余的22个字节就浪费了

enter description here

对于chunk空间的浪费问题,无法彻底的解决,只能修改参数grow factor(增长因子)。

数据过期
memcached采用Lazy Expiration+LRU相结合的方式保证内存空间的循环利用

  • Lazy Expiration
    memcached内部不会监视记录是否过期,而是在get时查看记录的时间戳,检查记录是否过期。这种技术被称为lazy(惰性)expiration。因此,memcached不会在过期监视上耗费CPU时间。
  • LRU
    memcached会优先使用已超时的记录的空间,但即使如此,也会发生追加新记录时空间不足的情况,此时就要使用名为 Least Recently Used Least Recently Used(LRU)机制来分配空间。顾名思义,这是删除最近最少使用的记录的机制。因此,当memcached的内存空间不足时,就从最近未被使用的记录中搜索,并将其空间分配给新的记录。从缓存的实用角度来看,该模型十分理想。

LRU算法原理:当某个单元被请求时,单元内维护者一个计数器,通过计数器判断谁最近最少未使用。

通信分布式

memcached尽管是“分布式”缓存服务器,但服务器端并没有分布式功能。各个memcached不会互相通信以共享信息。那么,怎样进行分布式呢?这完全取决于客户端的实现。

通信过程:
当向memcached集群存入/取出key/value时,memcached客户端程序根据一定的算法计算存入哪台服务器,然后再把key/value值存到此服务器中。当需要读取时,客户端根据算法到指定的服务器读取即可。

enter description here

常见的分布式缓存算法

取模法

先求得键做哈希计算,再除以服务器台数,根据余数确定存取服务器,就可得到下面的式子:
hash(key)%N

key 数据的键
hash() hash的函数
N 缓存服务器数量

这种方法计算简单,但结果很容易受N的值影响,当服务器数量N增加或者减少的时候,原先的缓存数据定位几乎失效。
于是 人们提出了一致性hash算法,最终目的是实现在移除、添加一个memcached服务器时对已经存在的缓存数据的定位影响尽可能的降到最小。

一致性哈希

先算出memcached服务器的hash值hash(node),并将其分布hash环上(0到2的32次方的圆),然后用同样的方法算出存储数据的键的hash值hash(key),并映射至hsah环上,当从数据映射到的位置开始顺时针查找,将数据保存到查找到的第一个服务器上,(如果超过2的32次方,依然找不到服务器,就将数据保存到第一台memcached服务器上)。如果添加了一台memcached服务器,只在圆上增加服务器的逆时针方向的第一台服务器上的键会受到影响。

enter description here

参考

Memcached原理和使用详解
Memcache知识点梳理