轻量级分布式缓存Memcached

分布式缓存的核心技术首先是内存本身的管理问题,包括了内存的分配,管理和回收机制。其次是分布式管理和分布式算法,其次是缓存键值管理和路由。

1.什么是Memcahed

Memcached是国外社区网站LiveJournal的开发团队开发的高性能分布式内存缓存服务器。许多Web应用程序都将数据保存到RDBMS中,应用服务器从中读取数据并在浏览器中显示。但随着数据量的增大,访问的集中,就会出现RDBMS的负担加重,数据库响应恶化,网站显示延迟等重大影响。一般的使用目的是通过缓存数据库查询结果,减少数据库的访问次数,以提高动态Web应用的速度、提高扩展性。


MemcacheDB是新浪团队开发的,基于Memcached协议,所以可以使用Memcached客户端直接使用,存储引擎使用Berkeley DB,支持主从复制模式。Memcached是非持久存储,所以它的定位就是缓存,而Memcachedb不是用来做缓存的,它是和mysql同一个层次的东西。不一样的是,memcachedb性能要比mysql高,而mysql检索功能比memcachedb强。如果从缓存的角度看,memcached缓解Mysql读压力,而Memcachedb缓解mysql写压力。

Memcachedb适合应用的场景:

(1)浏览/点击/统计等,也可以局部代替mysql的count函数

(2)标志

(3)频繁写的地方,访客列表、评论之类的

2.Memcached特点

Memcached作为高速运行的分布式缓存服务器具有以下特点。

(1)协议简单:

memcached的服务器客户端通信并不使用复杂的xml等格式,而是使用简单的基于文本的协议,C/S架构。

(2)基于libevent的事件处理:

libevent是一套跨平台的事件处理接口的封装。memvached使用这个libevent库,能在Linux、BSD、Solaris等操作系统上发挥其高性能。

包装的接口包括:poll、select(Windows)、epoll(Linux),kqueue(BSD)、/dev/poo  (Solaris)

Memcached使用libevent来进行网络并发连接的处理,能够保持在很大并发情况下,仍能够保持快速的响应能力。

(3)内置内存存储方式:

为了提高性能,memcached中保存的数据都存储在memcached内置的内存存储空间中。由于数据仅存在于内存中,因此重启memcached,重启操作系统会导致全部数据消失。另外,内容容量达到指定值以后memcached会自动删除不适用的缓存。

数据存储方式:Slab Allocation

默认使用Slab Allocation机制分配,管理内存。在改进机制以前,内存的分配是通过对所有记录简单的进行malloc和free来进行的。但是这种方式会导致内存碎片,加重操作系统内存管理器的负担。

Slab Allocator的基本原理是按照预先规定的大小,将分配的内存分割成特定长度的块,已完全解决内存碎片问题。Slab  Allocation将分配的内存分割成各种尺寸的块(chunck),并把尺寸相同的块分成组(chunck的集合)。


图1  Slab Allocation的构造图

而且Slab  Allocator还有重复使用已分配内存的目的。也就是说,分配到的内存不会释放,而是重复利用。


图2       Slab  Classes分配图

Page:分配给Slab的内存空间,默认是1MB。分配给Slab之后根据slab的大小切分成chunk。

Chunk:用于缓存记录的内存空间。

Slab  Class:特定大小的chunk组。

在slab中缓存记录的原理:

memcached根据收到的数据的大小,选择最适合数据大小的slab。memcached中保存着slab内空闲chunk的列表,根据该列表选择chunk,然后将数据缓存于其中。

Slab  Allocation缺点:


这个问题是,由于分配的是特定长度的内存,因此无法有效利用分配的内存。例如,将100字节的数据缓存到128字节的chunk中,剩余的28字节就浪费了。

数据过期方式:Lazy Expiration + LRU

Memcached删除数据时数据不会真正从memcached中消失。Memcached不会释放已分配的内存。记录超时后,客户端就无法再看到该记录(visible透明),其存储空间即可重复利用。

Lazy Expiration:

memcached内部不会监视记录是否过期,而是在get时查看记录的时间戳,检查记录是否过期。这种技术被称为lazy  expiration。因此,memcached不会再过期监视上耗费cpu时间。

LRU:

memcached会优先使用已超时的记录的空间,但即使如此,也会发生追加新纪录时空间不足的情况,此时就要使用Least Recently Used(LRU)机制来分配空间。删除”最近最少使用“的记录机制。因此,当memcached的内存空间不足时,(无法从slab class 获取新的空间时),就从最近未被使用的记录中搜索,并将其空间分配给新的记录。从缓存的实用角度来看,该模型十分理想。

(4)Memcached不互相通信的分布式:

memcached尽管是“分布式”缓存服务器,但服务器端并没有分布式功能。各个memcached不会相互通信以共享信息。分布式主要通过客户端实现。

基于客户端的Memcached分布式:


例子:

假设memcached服务器有node1-node3三台,应用程序要保存键名为”tokyo“,”kanagawa“”chiba“”saitama“”gunma“的数据。

//按照Key值,获取一个服务器ID
int getServerId(char *key,int serverTotal){
    int c ,hash = 0;
    while(c = *key++){
        hash+= c;}
    return  hash%serverTatal;
}
//服务器列表
node[0] =>192.168.0.1:11211
node[1] =>192.168.0.2:11211
node[2] =>192.168.0.3:11211

//获取key是tokyo的节点ID(服务器ID)
int id = getServerId("test",3);

//得出的结果是1,那么对应的机器就是
node[id] = node[1]
首先向memcached中添加”tokyo“。将”tokyo“传给客户端程序库后,客户端实现的算法就会根据”键“来决定保存数据的memcached服务器。服务器选定后,即命令它保存”tokyo“极其值。

                
同样,”kanagawa“"chaiba""saitama""gunma"都是先选择服务器再保存。

接下来获取保存的数据。获取时也要将要获取的键”tokyo“传递给函数库。函数库通过与数据保存时相同的算法,根据"键"选择服务器。使用的算法相同,就能选中了与保存时相同的服务器,然后发送get命令。只要数据没有 因为某些原因被删除,就能获得保存的值。

这样,将不同的键保存到不同的服务器上,就实现了memcached分布式。memcached服务器增多后,键就会分散,即使一台memcached服务器发生故障无法连接,也不会影响其他的缓存,系统依然能继续运行。


3.一些经验和技巧

(1)在Memcached中可以保存的item数据量是没有限制的,只要内存足够。

(2)Memcached单进程最大使用内存为2G,要使用更多内存,可以分多个端口开启多个Memcached进程。

(3)最大30天的数据过期时间,设置为永久的也会在这个时间过期,常量REALTIME_MAXDELTA  60*60*24*30控制

(4)单个item最大数据是1M,超过1MB数据不予存储,常量POWER_BLOCK  1048576进行控制,它是默认的slab大小。

(5)最大同时连接数是200,通过conn_init()中的freetotal进行控制,最大软连接数是1024,通过settings.maxconns=1024进行控制

(6)跟空间占用相关的参数:settings.factor = 1.25,settings.chunk_size = 48,影响slab的数据占用和步进方式

查看Memcached内部工作状态:

访问Memcached:telnet 主机名  端口号

查看总状态:stats

查看某项状态:stats curr_connections

禁止LRU

有些情况下LRU机制反倒会造成麻烦。memcached启动时通过”-M“参数可以禁止LRU,如下所示:

$memcached -M -m 1024

启动时必须注意的是,小写的”-m“选项是用来指定最大内存的大小的。不指定具体数值则使用默认值64MB。

指定"-M"参数启动后,内存用尽时memcached会返回错误。不过memcached毕竟不是存储器,而是缓存,所以推荐使用LRU.

Memcached使用线程模式工作

在安装的时候必须打开:./configure --enable -threads

安装完之后,启动的时候看看帮助信息有没有这条:

-t <num>   number of  threads  to use,defalt  4

如果存在该选项,说明已经支持了线程,就可以在启动的时候使用-t选项来启动多线程

然后启动的时候必须加上需要支持的线程的数量:

/usr/local/memcache/bin/mamcached -t 1024

调优Slab和内存分配

Memcached在启动时指定Growth Factor因子(通过-f 选项),就可以再某种程度上控制slab之间的差异。默认值为1.25.但是,在该选项出现之前,这个因子曾经固定为2,称为”powers of 2“策略。

我们用以前的设置,以verbose模式启动memcached:

$memcached -f 2 -vv


slab class  1:chunk size  128 perslab  8192

slab class  2:chunk size  256 perslab  4096

slab class  3:chunk size  512 perslab  2048

slab class  4:chunk size 1024 perslab  1024

slab class  5:chunk size  2048 perslab  512

slab class  6:chunk size  4096 perslab  256

slab class  7:chunk size  8192 perslab  128

slab class  8:chunk size  16384 perslab  64

slab class  9:chunk size  32768 perslab  32

slab class  10:chunk size  65536 perslab  16

slab class  11:chunk size  131072 perslab  8

slab class  12:chunk size  262144 perslab 4

slab class  13:chunk size  524288 perslab 2

可见,从128字节的组开始,组的大小一次增大为原来的2倍。这样设置的问题是,slab之间的差别比较大,有些情况下就相当浪费内存。因此,为尽量减少内存浪费,追加了growth  factor这个选项,默认设置(f=1.25)时的输出:

slab class  1:chunk size  88 perslab  11915

slab class  2:chunk size  112 perslab  9362

slab class  3:chunk size  144 perslab  7281

slab class  4:chunk size 184 perslab  5698

slab class  5:chunk size  232 perslab  4519

slab class  6:chunk size  296 perslab  3542

slab class  7:chunk size  376 perslab  2788

slab class  8:chunk size  172 perslab  2221

slab class  9:chunk size  592 perslab  1771

slab class  10:chunk size  744 perslab  1409

可见,组间差距比因子为2时小得多,更适合缓存几百字节的记录。从上面的输出结果来看,可能会觉得有些计算误差,这些误差是为了保持字节数的对齐而故意设置的。

将memcached引入产品,或是直接使用默认值进行部署时,最好是重新计算一下数据的预期平均长度,调整growth  factor,以获得最恰当的设置。


参考:

http://wenku.baidu.com/view/8686d46c7e21af45b307a8c3.html

http://blog.sina.com.cn/s/blog_493a845501013ei0.html

http://www.t086.com/article/4698


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值