0x00 Memcached简述
Memcached是一套高性能的分布式内存对象缓存系统,用于在动态系统中减少数据库负载,提升性能。
0x01 Memcached特性
基于libevent的事件处理
内置内存存储方式SLab Allocation机制
并不单一的数据删除机制
基于客户端的分布式系统
0x02 高性能的基础:libevent事件处理
Libevent 是一个用C语言编写的、轻量级的开源高性能网络库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大;源代码相当精炼、易读;跨平台,支持 Windows、 Linux、 *BSD 和 Mac Os;支持多种 I/O 多路复用技术, epoll、 poll、 dev/poll、 select 和 kqueue 等;支持 I/O,定时器和信号等事件;注册事件优先级。
以上引自百度百科,在不支持I/O多路复用的情况下,一个线程同时只能处理一个socket文件操作符,所以当一个任务未完成时,线程需要等待任务的处理,这种处理模型效率低下。而I/O多路复用无需等待任务完成,而是将所有任务维护在一个I/O组中,在等待过程中线程可以去处理其他的任务,当某个任务完成后,再去操作该socket操作符。值得一提的是,在I/O多路复用技术中,epoll是非常棒的,相比于select模型,epoll没有文件操作符数量的限制;并且select模型是将所有操作符维护在一个I/O组中,当有socket数据可操作时,线程需要在组中寻找哪个文件操作符可操作,而epoll只将可操作的socket文件操作符给线程,线程无需自己寻找,可以直接操作该socket,提高了处理性能。
所以,使用libevent时间处理模型,非常好的提升了memcached的性能。
0x03 SLab Allocation机制
在memcached中,内存不是直接C语言提供的malloc()
free()
进行管理的,因为原生的内存管理方式会造成内存碎片,会加重内存管理器的内存管理负担。而SLab Allocation机制完美的解决了内存碎片化的问题。
a.解决内存碎片化
SLab Allocator 在初始化时,通过将内存分配成预先设置的大小,将这些内存分割成特定长度的块(chunk),并把尺寸相同的chunk分成一个组,也就是chunk集合,而这种方式就解决了内存碎片化的问题。
b.内存预分配
在需要存储缓存数据时,memcached会在chunk中选择与所存数据大小最接近的chunk,并将数据存储到该chunk中,这样不需要每次在存储数据时,都向操作系统申请空间,提升了memcached的处理性能。
c.内存重复利用
当存储的数据过期后,memcached不会释放该数据的所占用的内存,而仅仅是将该数据标记为不可用,当有新数据需要存储时,memcached会将数据重新存储到该空间中,用这种方式对内存进行重复利用。
d.缺点
因为Slab Allocator将内存分割成固定大小的块,当存储的数据小于chunk的长度,会导致该chunk剩余空间的浪费。例如:当一个数据占用60K,而最接近的chunk长度为64K,此时就有4K的空间造成浪费。而目前仅有的调优方案是调整Growth Factor因子,让chunk的大小尽可能的接近,减少空间的浪费。
0x04 memached的删除机制
a.不会真正删除记录
当存储在memcached中的记录过期时,memcached不会释放该内存,而是让客户端对该记录不可见。留下内存来,让之后的存储记录进行内存重复利用。
b.Lazy Expiration(懒过期机制)
memcached为了提升性能,在内部不会对存储在memcached中的记录进行监视,而是在每次get数据的时候,对该记录的过期时间进行校验,当记录过期,则不返回数据。
c.LRU(最近最少使用)
虽然memcached拥有内存重复利用的机制,但是进行大量数据缓存时,还是会出现内存吃满,memcached无法在SLab中获取到空闲的内存,在这种情况下,memcached会触发LRU,会在最近未被使用的记录中进行搜索,并将这些空间分配给新的记录。
0x05 memcached的分布式
不同于其他软件的分布式,memcached的分布式不存在于服务端,而是完全由客户端进行分布式的处理。这样的好处是,减少memcached服务端之间的网络连接,当某一个服务器宕机时,不至于影响其他机器的正常使用。
a.根据余数计算分散
通过crc32()
计算出键的整数哈希值,然后除以服务器的台数,求得余数进行服务器节点的选择,此种方式的优点是,简单易操作,并且数据的分散性也非常优秀。但缺点是,当改变服务器的数量时,缓存重组的代价巨大,在此过程中缓存的命中率急剧下降。
b.Consistent Hashing(一致性哈希)
首先求出memcached服务器节点的哈希值,并将其分配到一个0~2^32的圆上,我们称该这个圆为值域,之后通过同样的计算方式求出键的哈希值,并将值映射到圆上,然后从数据映射到的位置开始顺时针寻找,并将数据存储到找到的第一个服务器节点上,如果找到2^32仍然找不到就将数据存储到第一台memcached机器上。
当添加一台新机器时,通过同样的hash算法将该机器映射到圆上,影响的仅仅是新机器的节点到它的上一个节点之间的数据。
当删除一台机器时,同样也仅仅影响映射到删除的机器和它的上一台机器之间的数据,而不会造成大面积的缓存重组即rehash.
0x06 扩展阅读
memcached完全剖析
使用 libevent 和 libev 提高网络应用性能
高性能IO模型浅析
备注:资源和图片等均来自网络
原文作者:我才是二亮
原文链接:http://blog.2liang.me/2016/11/28/learn-memcached-principle/
转载请在正文中标注并保留原文链接、作者等信息。