memcached学习笔记

原文地址:http://blog.sina.com.cn/s/blog_62c5a4810100ndl5.html

这个讲的跟《NOSQL数据库入门》中的memcached介绍节一样,不过看了看,这个还是做了些总结的。

原文内容copy:

1、背景: Memcached是国外社区网站 LiveJournal 的开发团队开发的高性能的分布式内存缓存服务器。一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度、提高可扩展性。

2、缘由:许多Web应用都将数据保存到RDBMS中,应用服务器从中读取数据并在浏览器中显示。但随着数据量的增大、访问的集中,就会出现RDBMS的负担加重、数据库响应恶化、网站显示延迟等重大影响。

memcached学习笔记

3、内部主要实现原理:通过在内存里维护一个统一的巨大的hash表,memcached能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果。

 4、memcached特点:

基于C/S架构,协议简单。

基于liberent的事件处理。

自主内存存储处理。

基于客户端的memcached分布式

对于其中一些特点的理解:

    libevent是一套跨平台的事件处理接口的封装,能够兼容包括这些操作系统:Windows/Linux/BSD/Solaris 等操作系统的的事件处理。

存储处理:

数据存储方式:Slab Allocation

memcached学习笔记

该存储方式的特点是:Slab Allocation的原理相当简单。将分配的内存分割成各种尺寸的块(chunk),并把尺寸相同的块,但是分成组由于分配的是特定长度的内存,因此无法有效利用分配的内存。例如,将100字节的数据缓存到128字节的chunk中,剩余的28字节就浪费了(如下图)。针对这个问题的解决方案是:

memcached学习笔记

The most efficient way to reduce the waste is to use a list of size classes that closely matches (if that's at all possible) common sizes of objects that the clients of this particular installation of memcached are likely to store.
就是说,如果预先知道客户端发送的数据的公用大小,或者仅缓存大小相同的数据的情况下,只要使用适合数据大小的组的列表,就可以减少浪费。
memcached学习笔记


数据过期方式:Lazy Expiration + LRU

Lazy Expiration
memcached内部不会监视记录是否过期,而是在get时查看记录的时间戳,检查记录是否过期。这种技术被称为lazy(惰性)expiration。假如我们所存储的数据项相当多的时候,在这时候进行监控的话,花费的代价是相当大的,所以memcached不会在过期监视上耗费过多的CPU时间,从而在性能方面也起到一定的优化作用。

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

memcached的分布式,通过键值进行hash计算,获得一个hash值,然后,通过通过该hash值对已有的服务器台数进行求余,把该需缓存对象存到相应的服务器上,不过该方式也存在严重的问题,接下来再讨论,先从简单的谈起。

memcached学习笔记

                 (最原始想法)

memcached学习笔记

                (分布式想法)

memcached学习笔记

                      (新增一个缓存对象)

memcached学习笔记

                  (获取缓存对象)

//按照Key值,获取一个服务器ID
int getServerId(char *key, int serverTotal) {
    int c, hash = 0;
    while (c = *key++) {
        hash += c;
    }
    return hash % serverTotal;
}

//服务器列表
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的分布式算法为余数计算算法,的确是实现了memcached的分布式,但是对于服务器端的分布式还是没有实现,当考虑到一个问题,如果新增或者是移除服务器的话,会导致一个严重的问题,就是缓存的命中率严重下降,以为算法中的余数计算没有考虑到服务器数量的变动,如果服务器数量保持不变,那肯定是个不错的选择,但是在实际中,我们的系统在不断增强,所需要的缓存的数据量不断提高,面对这种情况,出现宕机或者是服务器数量的变动问题是正常的,所以我们需要想一个合适的办法去解决这个问题,把损失降到最小,不能因服务器的变动而导致缓存命中率严重下降,这样的话就失去了使用memcached的意义了。

下面提到的另一种优化的算法:Consistent Hashing

Consistent Hashing如下所示:首先求出memcached服务器(节点)的哈希值,并将其配置到0~232的(continuum)上。然后用同样的方法求出存储数据的键的哈希值,并映射到圆上。然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过232仍然找不到服务器,就会保存到第一memcached服务器上。这样的话,当我们添加一台memcached服务器。余数分布式算法由于保存键的服务器会发生巨大变化而影响缓存的命中率,但Consistent Hashing中,只有在continuum上增加服务器的地点逆时针方向
的第一台服务器上的键会受到影响。因此,Consistent Hashing最大限度地抑制了键的重新分布。而且,有的Consistent Hashing的实现方法还采用了虚拟节点的思想。使用一般的hash函数的话,服务器的映射地点的分布非常不均匀。因此,使用虚拟节点的思想,为每个物理节点(服务器)在continuum上分配100~200个点。这样
就能抑制分布不均匀,最大限度地减小服务器增减时的缓存重新分布。通过测试,结果是,由服务器台数(n)和增加的服务器台数(m)计算增加服务器后的命中率计算公式如下:(1 n/(n+m)) * 100

memcached学习笔记

memcached学习笔记


你可能感兴趣的:(memcached)