许多Web应用都将数据保存到RDBMS中,应用服务器从中读取数据并在浏览器中显示。但随着数据量的增大、访问的集中,就会出现RDBMS的负担加重、数据库响应恶化、网站显示延迟等重大影响。memcached通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度、提高可扩展性。
第一次访问:从关系型数据库(RDBMS)中取得数据保存到memcached中;
之后的访问:从memcached中去的数据显示页面。
Memcached作为高速运行的分布式缓存服务器具有以下特点:
1.协议简单
memcached的服务器客户端通信并不使用复杂的MXL等格式,而是使用简单的基于文本的协议。
2.基于libevent的事件处理
libevent是个程序库,他将Linux 的epoll、BSD类操作系统的kqueue等时间处理功能封装成统一的接口。memcached使用这个libevent库,因此能在Linux、BSD、Solaris等操作系统上发挥其高性能。
3.内置内存存储方式
为了提高性能,memcached中保存的数据都存储在memcached内置的内存存储空间中。由于数据仅存在于内存中,因此重启memcached,重启操作系统会导致全部数据消失。另外,内容容量达到指定的值之后memcached回自动删除不适用的缓存。
4.Memcached不互通信的分布式
memcached尽管是“分布式”缓存服务器,但服务器端并没有分布式功能。各个memcached不会互相通信以共享信息。他的分布式主要是通过客户端实现的。
Slab Allocation机制
最近的memcached默认情况下采用了名为Slab Allocator的机制分配、管理内存。 在该机制出现以前,内存的分配是通过对所有记录简单地进行malloc和free来进行的。 但是,这种方式会导致内存碎片,加重操作系统内存管理器的负担,最坏的情况下, 会导致操作系统比memcached进程本身还慢。Slab Allocator就是为解决该问题而诞生的。
Slab Allocator的基本原理是按照预先规定的大小,将分配的内存分割成特定长度的块, 以完全解决内存碎片问题。Slab Allocation的原理相当简单。 将分配的内存分割成各种尺寸的块(chunk), 并把尺寸相同的块分成组(chunk的集合)。但是分成组由于分配的是特定长度的内存,因此无法有效利用分配的内存。
例如,将100字节的数据缓存到128字节的chunk中,剩余的28字节就浪费了(如下图)。
就是说,如果预先知道客户端发送的数据的公用大小,或者仅缓存大小相同的数据的情况下,只要使用适合数据大小的组的列表,就可以减少浪费。
数据过期方式
1.Lazy expiration
memcached内部不会监视记录是否过期,而是在get时查看记录的时间戳,检查记录是否过期。这种技术被称为lazy(惰性)expiration。假如我们所存储的数据项相当多的时候,在这时候进行监控的话,花费的代价是相当大的,所以memcached不会在过期监视上耗费过多的CPU时间,从而在性能方面也起到一定的优化作用。
2.LRU
memcached会优先使用已超时的记录的空间,但即使如此,也会发生追加新记录时空间不足的情况,此时就要使用名为 Least Recently Used(LRU)机制来分配空间。顾名思义,这是删除“最近最少使用”的记录的机制。因此,当memcached的内存空间不足时(无法从slab class 获取到新的空间时),就从最近未被使用的记录中搜索,并将其空间分配给新的记录。从缓存的实用角度来看,该模型十分理想。
基于客户端的memcached分布式
memcached的分布式,通过键值进行hash计算,获得一个hash值,然后,通过通过该hash值对已有的服务器台数进行求余,把该需缓存对象存到相应的服务器上,不过该方式也存在严重的问题,接下来再讨论,先从简单的谈起。
假设memcached服务器中有node1-node3三台服务器,应用程序要保存键名为“tokyo”“kanagawa”“chiba”“saitama”“gunma” 的数据.
1.准备
首先向memcached中添加“tokyo”。将“tokyo”传给客户端程序库后, 客户端实现的算法就会根据“键”来决定保存数据的memcached服务器。 服务器选定后,即命令它保存“tokyo”及其值。
2.添加时
“kanagawa”“chiba”“saitama”“gunma”都是先选择服务器再保存。接下来获取保存的数据。获取时也要将要获取的键“tokyo”传递给函数库。 函数库通过与数据保存时相同的算法,根据“键”选择服务器。 使用的算法相同,就能选中与保存时相同的服务器,然后发送get命令。 只要数据没有因为某些原因被删除,就能获得保存的值。
3.获取时
讲不通的键保存在不同的服务器上,就实现了memcached的分布式,memcached服务器增多,键就会分散,即使一台服务器发生故障无法使用,也不会影响其他的缓存,系统可以继续运行下去。
实现了memcached的分布式,但是对于服务器端的分布式还是没有实现,当考虑到一个问题,如果新增或者是移除服务器的话,会导致一个严重的问题,就是缓存的命中率严重下降,以为算法中的余数计算没有考虑到服务器数量的变动,如果服务器数量保持不变,那肯定是个不错的选择,但是在实际中,我们的系统在不断增强,所需要的缓存的数据量不断提高,面对这种情况,出现宕机或者是服务器数量的变动问题是正常的,所以我们需要想一个合适的办法去解决这个问题,把损失降到最小,不能因服务器的变动而导致缓存命中率严重下降,这样的话就失去了使用memcached的意义了。
所以需要结合一致性哈希算法来分析,关于一致性哈希算法的细节,在另外一篇博客中详细介绍了。在此不再赘述。