1.Memcached 简介

Memcached 是一个开源的,支持高性能,高并发的分布式内存缓存系统,由 C 语言编写,总共 2000 多行代码。从软件名称上看,前 3 个字符 Mem 就是内存的意思,而接下来的后面 5 个字符 cache 就是缓存的意思,最后一个字符 d,是 daemon 的意思,代表的是服务器端守护进程模式服务。

Memcached 软件诞生于 2003 年,最初由 LiveJournal 的 Brad Fitzpatrick 开发完成。Memcache 是整个项目的名称,而 Memcached 是服务器端的主程序名,因其协议简单,应用部署方便,且支持高并发,因此被互联网企业广泛使用,直到现在仍然如此。其官方网站地址:http://memcached.org/。

2、Memcached 的作用

传统场景中,多数 Web 应用都将数据保存到关系型数据库中(如 MySQL),Web 服务器从中读取数据并在浏览器中显示。但随着数据量增大、访问集中,关系型数据库的负担就会出现加重,响应缓慢,导致网站打开延迟等问题,影响用户体验。

这时就需要 Memcached 软件出马了。使用 Memcached 的主要目的是,通过在自身内存中缓存关系型数据库的查询结果,减少数据库被访问的次数,以提高动态 Web 应用的速度,提高网站架构的并发能力和可扩展性。

Memcached 服务的运行原理是通过在事先规划好的系统内存空间中临时缓存数据库中的各类数据,以达到减少前端业务服务对数据库的直接高并发访问,从而提升大规模网站集群中动态服务的并发访问能力。

生产场景的 Memcached 服务一般被用来保存网站中经常被读取的对象或数据,就像我们的客户端浏览器也会把经常访问的网页缓存起来一样,通过内存缓存来存取对象或数据要比磁盘存取快很多,因为磁盘是机械的。因此,在当今的 IT 企业中,Memcached 的应用范围很广泛。

3.Memcached 的用户与应用场景

3.1 Memcached 常见用途工作流程

Memcached 是一种内存缓存软件,在工作中经常用来缓存数据库的查询数据,数据被缓存在事先与分配的 Memcached 管理的内存中,可以通过 API 或命令的方式存取内存中缓存的这些数据,Memcached 服务内存中缓存的数据就像一张巨大的 Hash 表,每条数据都是以 Key-Value 对的形式存在。

3.2 网站读取 Memcached 数据时工作流程

从逻辑上来说,当程序访问后端数据库获取数据时会优先访问 Memcached 缓存,如果缓存中有数据就直接返回给客户端用户,如果没有合适的数据(没有命中),再去后端的数据库读取数据,读取到需要的数据后,就会把数据返回给客户端,同时还会把读取到的数据缓存到 Memcached 内存中,这样客户端用户再次请求相同的数据时就会直接读取 Memcached 缓存的数据了,这就大大地减轻了后端数据库的压力,并提高了整个网站的响应速度,提升了用户体验。

a.png

如上图所示:使用 Memcached 缓存查询的数据来减少数据库压力的具体工作流程如下:

        Web 程序首先检查客户端请求的数据是否在 Memcached 缓存中存在,如果存在,直接把请求的数据返回给客户端,此时不再请求后端数据库。

        如果请求的数据在 Memcached 缓存中不存在,则程序会去请求数据库服务,把从数据库中取到的数据返回给客户端,同时把新取到的数据缓存一份到 Memcached 缓存中。

(1)当程序更新或删除数据时,会首先处理后端数据库中的数据。

(2)在处理后端数据库中数据的同时,也会通知 Memcached,告诉它对应的旧数据失效,从而保证 Memcached 中缓存的数据始终和数据库中一致,这个 数据一致性 非常重要,也是大型网站分布式缓存集群最头疼的问题所在。

(3)如果是在高并发读写场合,除了要程序通知 Memcached 过期的缓存失效外,还可能要通过相关机制,例如在数据库上部署相关程序(如在数据库中设置触发器使用 UDFs),实现当数据库有更新时就把数据更新到 Memcached 服务中,这样一来,客户端在访问新数据时,因预先把更新过的数据库数据复制到 Memcached 中缓存起来了,所以可以减少第一次查询数据库带来的访问压力,提升 Memcached 中缓存的命中率,甚至新浪门户还会把持久化存储 Redis 做成 MySQL 数据库的从库,实现真正的主从复制。

3.3 Memcached 在企业中的应用场景

3.3.1 作为数据库的查询数据缓存

(1)完整数据缓存

        例如:电商的商品分类功能不是经常变动的,因此可以事先放到 Memcached 里,然后再对外提供数据访问。这个过程被称之为 数据预热。此时只需读取缓存,无需读取数据库就能得到 Memcached 缓存里的所有商品分类数据了,所以数据库的访问压力就会大大降低。

        为什么商品分类数据可以事先放在缓存里呢?因为商品分类几乎都是由内部人员管理的,如果需要更新数据,更新数据库后,就可以把数据同时更新到 Memcached 里。如果把商品分类数据做成静态化文件,然后通过在前端 Web 缓存或者使用 CDN 加速效果更好。

(2)热点数据缓存

        热点数据缓存一般是用于由用户更新的商品,例如淘宝的卖家,在卖家新增商品后,网站程序就会把商品写入后端数据库,同时把这部分数据,放入 Memcached 内存中,下一次访问这个商品的请求就直接从 Memcached 内存中取走了。这种方法用来缓存网站热点的数据,即利用 Memcached 缓存经常被访问的数据。

    注:这个过程可以通过程序实现,也可以在数据库上安装相关软件进行设置,直接由数据库把内容更新到 Memcached 中,就相当于 Memcached 是 MySQL 的从库一样。

如果碰到电商双 11,秒杀高并发的业务场景,必须要事先预热各种缓存,包括前端的 Web 缓存和后端的数据库缓存。也就是先把数据放入内存预热,然后逐步动态更新。此时,会先读取缓存,如果缓存里没有对应的数据,再去读取数据库,然后把读到的数据放入缓存。如果数据库里的数据更新,需要同时触发缓存更新,防止给用户过期的数据,当然对于百万级别并发还有很多其他的工作要做。

绝大多数的网站动态数据都是保存在数据库当中的,每次频繁地存取数据库,会导致数据库性能急剧下降,无法同时服务更多的用户(比如 MySQL 特别频繁的锁表就存在此问题),那么,就可以让 Memcached 来分担数据库的压力。增加 Memcached 服务的好处除了可以分担数据库的压力以外,还包括无须改动整个网站架构,只须简单地修改下程序逻辑,让程序先读取 Memcached 缓存查询数据即可,当然别忘了,更新数据时也要更新 Memcached 缓存。

4、Memcached Slab 内存管理机制

现在的 Memcached 是利用 Slab Allocation 机制来分配和管理内存的,过程如下:

提前将大内存分配大小为 1MB 的若干个 slab,然后针对每个 slab 再进行小对象填充,这个小对象称为 chunk,避免大量重复的初始化和清理,减轻了内存管理器的负担。

Slab Allocation 内存分配的原理是按照预先规定的大小,将分配给 Memcached 服务的内存预先分割成特定长度的内存块(chunk),再把尺寸相同的内存块(chunk)分成组(chunks slab class),这些内存块不会释放,可以重复利用,如下图所示。

slab.png

新增数据对象存储时。因 Memcached 服务器中保存着 slab 内空闲 chunk 的列表,他会根据该列表选择 chunk,然后将数据缓存于其中。当有数据存入时,Memcached 根据接收到的数据大小,选择最适合数据大小的 slab 分配一个能存下这个数据的最小内存块(chunk)。例如:有 100 字节的一个数据,就会被分配存入下面 112 字节的一个内存块中,这样会有 12 字节被浪费,这部分空间就不能被使用了,这也是 Slab Allocator 机制的一个缺点。

4.1memcache内存分配三个重要的概念: 

1.page 

系统分配给slab的内存空间(对应实际的物理空间),1个page默认为1M,可以使用-I参数进行调解(default: 1mb, min: 1k, max: 128m),分配给Slab之后根据chunk的大小切分成大小相同的chunk空间,chunk用于缓存记录。 

2.Chunk 

为固定大小的内存空间,默认为96Byte,可以使用-n参数进行调节,默认的-f大小为1.25,即每个slab的chunk大小会以1.25倍的大小增长 

3. slab class 

同样大小的chunk又称为slab class。

三个重要的参数 -m -f -n 

-m 分配的最大内存 

-f slab class(chunk组)的增长因子 

-n ( slab class 1中)chunk的初始大小

5、Memcached功能特点

1.  协议简单

     其使用基于文本行的协议,能直接通过 telnet 在Memcached 服务器上存取数据

2.  基于 libevent 的事件处理

     libevent 利用 C 开发的程序库,它将 BSD 系统的kqueue,Linux 系统的 epoll 等事件处理功能封装成为一个接口,确保即使服务器端的链接数。加也能发挥很好的性能。      Memcached 利用这个库进行异步事件处理。

3.  内置的内存管理方式

     Memcached 有一套自己管理内存的方式,这套方式非常高效,所有的数据都保存在Memcached内置的内存中,当存入的数据占满空间时,使用 LRU 算法自动删除不使用的缓存,即重用过期的内存空间。Memecached 不考虑数据的容灾问题,一旦重启所有数据全部丢失。

4.  节点相互独立的分布式

     各个 Memecached 服务器之间互不通信,都是独立的存取数据,不共享任何信息。通过对客户端的设计,让 Memcached 具有分布式,能支持海量缓存和大规模应用

6、使用Memcached应该考虑的因素

1. Memcached服务单点故障

  在Memcached集群系统中每个节点独立存取数据,彼此不存在数据同步镜像机制,如果一个Memcached节点故障或者重启,则该节点缓存在内存的数据全部会丢失,再次访问时数据再次缓存到该服务器

2. 存储空间限制

    Memcache缓存系统的数据存储在内存中,必然会受到寻址空间大小的限制,32位置系统可以缓存的数据为2G,64位系统缓存的数据可以是无限的,要看Memcached服务器物理内存足够大即可

3. 存储单元限制

    Memcache缓存系统以 key-value 为单元进行数据存储,能够存储的数据key尺寸大小为250字节,能够存储的value尺寸大小为1MB,超过这个值不允许存储

4. 数据碎片

    Memcache缓存系统的内存存储单元是按照Chunk来分配的,这意味着不可能,所有存储的value数据大小正好等于一个Chunk的大小,因此必然会造成内存碎片,而浪费存储空间

5. 利旧算法局限性

    Memcache缓存系统的LRU算法,并不是针对全局空间的存储数据的,而是针对Slab的,Slab是Memcached中具有同样大小的多个Chunk集合

6.数据访问安全性

    Memcache缓存系统的慢慢Memcached服务端并没有相应的安全认证机制通过,通过非加密的telnet连接即可对Memcached服务器端的数据进行各种操作