一、memcached入门
-
采用libevent的事件通知实现数据的发送
-
高并发环境下,大量的读、写请求涌向数据库,此时磁盘IO将成为瓶颈,从而导致过高的响应延迟,因此缓存应运而生。无论是单机缓存还是分布式缓存都有其适应场景和优缺点,当今存在的缓存产品也是数不胜数,最常见的有redis和memcached等,既然是分布式,那么他们是怎么实现分布式的呢?本文主要介绍分布式缓存服务mencached的分布式实现原理。
-
缓存本质
计算机体系缓存
什么是缓存,我们先看看计算机体系结构中的存储体系,根据冯·诺依曼计算机体系结构模型,计算机分为五大部分:运算器、控制器、存储器、输入设备、输出设备。结合现代计算机,CPU包含运算器和控制器两个部分,CPU负责计算,其需要的数据由存储提供,存储分为几个级别,就拿我当前的PC举个例子,我的机器存储清单如下:
1. 356G的磁盘
2. 4G的内存
3. 3MB三级缓存
4. 256KB二级缓存(pre core)
除了上述部分,还有CPU内的寄存器,当然有的计算机还有一级缓存等。CPU运算器工作的时候需要数据,数据哪里来?首先从距离CPU最近的二级缓存去拿,这块缓存速度最快,通常也是体积最小,因为价格最贵
(4)存储金字塔
如上图所示,存储体系就像个金子塔,最上层最快,价格最贵,最下层最慢,价格也最便宜,CPU的数据源优先级一层层从上到下去寻找数据。
很显然,除了最慢的那块存储,在计算机体系中,相对较快的那些存储都可以被称为缓存,他们解决的问题是让存储访问更快。
(5)缓存应用系统
计算机体系存储系统模型扩展到应用也是一样,应用需要数据,数据哪里来?缓存(更快的存储)->DB(较慢的存储),他们的工作流程大致如下图所示
(6)带缓存的存储访问一般模型
如上图所示,缓存应用系统一般存储访问流程:首先访问缓存较快的存储介质,如果命中且未失效则返回内容,如果未命中或失效则访问较慢的存储介质将内容返回同时更新缓存。
(7)memcached简介
(8)memcached缓存应用
1. 协议简单
2. 基于libevent的事件处理
3. 内置内存存储方式
4. memcached不相互通信的分布式
(9)memcached分布式原理
memcached特点的第四条,memcached不相互通信,那么memcached是如何实现分布式的呢?memcached的分布式实现主要依赖客户端的实现
当数据到达客户端,客户端实现的算法就会根据“键”来决定保存的memcached服务器,服务器选定后,命令他保存数据。取的时候也一样,客户端根据“键”选择服务器,使用保存时候的相同算法就能保证选中和存的时候相同的服务器。
(10)余数计算分散法
余数计算分散法是memcached标准的memcached分布式方法,算法如下:
CRC($key)%N
该算法下,客户端首先根据key来计算CRC,然后结果对服务器数进行取模得到memcached服务器节点,对于这种方式有两个问题值得说明一下:
1. 当选择到的服务器无法连接的时候,一种解决办法是将尝试的连接次数加到key后面,然后重新进行hash,这种做法也叫rehash。
2. 第二个问题也是这种方法的致命的缺点,尽管余数计算分散发相当简单,数据分散也很优秀,当添加或者移除服务器的时候,缓存重组的代价相当大。
Consistent Hashing算法
ConsistentHashing算法描述如下:首先求出memcached服务器节点的哈希值,并将其分配到0~2^32的圆上,这个圆我们可以把它叫做值域,然后用同样的方法求出存储数据键的哈希值,并映射到圆上。然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上,如果超过0~2^32仍找不到,就会保存在第一台memcached服务器上:
(11)memcachd基本原理
Memcachd是一个自由开源的,高性能,分布式内存对象缓存系统。再抛出上面的问题,如果新添加或移除一台机器,在consistentHashing算法下会有什么影响。上图中假设有四个节点,我们再添加一个节点叫node5
添加了node节点之后
node5被放在了node4与node2之间,本来映射到node2和node4之间的区域都会找到node4,当有node5的时候,node5和node4之间的还是找到node4,而node5和node2之间的此时会找到node5,因此当添加一台服务器的时候受影响的仅仅是node5和node2区间。
优化的ConsistentHashing算法
上面可以看出使用consistent Hashing最大限度的抑制了键的重新分配,且有的consistent Hashing的实现方式还采用了虚拟节点的思想。问题起源于使用一般hash函数的话,服务器的映射地点的分布非常不均匀,从而导致数据库访问倾斜,大量的key被映射到同一台服务器上。为了避免这个问题,引入了虚拟节点的机制,为每台服务器计算出多个hash值,每个值对应环上的一个节点位置,这种节点叫虚拟节点。而key的映射方式不变,就是多了层从虚拟节点再映射到物理机的过程。这种优化下尽管物理机很少的情况下,只要虚拟节点足够多,也能够使用得key分布的相对均匀。
(12)总结
本文介在理解缓存基本概念的情况下介绍了memcached的分布式算法实现原理,memcached的分布式是由客户端函数库实现的。
二、memcached的数据存储方式
1.数据存储方式称为SlabAllocator
(1)先把内存分成很多个Slab,这个大小是预先规定好的,以解决内存碎片的问题。启动参数的时候配置进去的不懂得可以参考memcached启动参数配置章节。
分配给Slab的内存空间被称为Page,默认是1M。一个Slab下可以有多个Page。
(2)然后把一个Page分成很多个chunk块,chunk块是用于缓存记录的空间。Chunk的
大小是先有一个基本值,然后根据增长因子来增大。每一个page中chunk是相等的空间大小。
(3)slab class:内存区类别(48byte-1M),每个类别有一个slabclassId,图左边的,类似索引方便管理记录。
(4)Memcached里面保存着slab内空闲的chunk列表,当收到要保存的item的时候,它
会根据item的大小,去选择一个最合适的slab,然后找到空闲的chunk,把数据存放进去。
比如我们存放120字节的值,有个chunk值为100还有一个chunk是130,存到100的chunk是没有足够空间存储的,存储到130这个chunk是可以的,最近的原则存储。但是存储到130chunk里面,也有一个问题就是浪费了10字节内存。所以合理的分配空间也是很重要的。
(5)Slab是一个内存块,是memcached一次申请内存的最小单位。
(6)Memcached内存管理采取预分配、分组管理的方式。
三、Memcached与Redis对比
(1)Memcached与Redis都属于内存内、键值数据存储方案。它们都从属于数据管理解决方案中的NoSQL家族,而且都基于同样的键值数据模型。双方都选择将全部数据保存在内存当中,这自然也就让它们成为非常理想的缓冲层实现方案。从性能表现的角度来看,两类数据存储机制也具备诸多共通性,包括拥有几乎相同的特征(与指标)表现、而且高度关注工作负载的数据吞吐量与延迟状况。
(2)Memcached与Redis还都是相当成熟而且极具人气的开源项目;Redis有时候会被人们称为“强化版的Memcached”。。Redis在功能多样性方面要胜过Memcached;
(3)极为简便的上手难度。相对Memcached而言,Redis的面世时间更晚且具备更多功能,因此开发人员通常将其视为默认性首选方案
(4)使用memcached的场景
对小型静态数据进行缓存处理,最具代表性的例子就是HTML代码片段。Memcached的内部内存管理机制虽然不像Redis的那样复杂,但却更具实际效率——这是因为Memcached在处理元数据时所消耗的内存资源相对更少。作为Memcached所支持的惟一一种数据类型,字符串非常适合用于保存那些只需要进行读取操作的数据,因为字符串本身无需进行进一步处理。Memcached在横向扩展方面也比Redis更具优势。由于其在设计上的思路倾向以及相对更为简单的功能设置,Memcached在实现扩展时的难度比Redis低得多。不过根据我们了解到的情况,目前已经有多种经过测试且切实有效的方案能够将Redis扩展至多台服务器之上,而其即将发布的3.0版本(感兴趣的朋友可以点击此处查看其候选版本说明)将包含专门针对横向扩展场景的内置集群化机制。
(5)使用Redis的场景
除非大家需要考虑某种限定性条件(例如处理传统应用程序)对于Memcached的特殊依赖性,或者自己的实际用例属于前面提到的两类场景中的一种,否则请直接选择Redis并加以运用。凭借着Redis所带来的卓越缓存方案,我们将拥有强大的处理能力——例如对缓存内容及持久性进行细节调整的能力——以及出色的整体执行效率。采用所谓数据回收机制,能够将陈旧数据从内存中删除以提供新数据所必需的缓存空间。Memcached的数据回收机制使用的是LRU(即最低近期使用量)算法,而且往往会比较武断地直接删除掉与新数据体系相近的原有内容。相比之下,Redis允许用户更为精准地进行细化控制,利用六种不同回收策略确切提高缓存资源的实际利用率。Redis还采用更为复杂的内存管理与回收对象备选方案。
相对于将对象保存为序列化字符串,Redis允许开发人员以散列方式将对象域及值加以保存,并利用单一键对其进行管理。Redis散列机制的存在保证开发人员无需经历获取完整字符串、反序列化、更新值、对象重新序列化并在每次值更新后利用其替代缓存内完整字符串这一系列复杂的流程——这也意味着资源消耗量得以降低、性能表现迎来显著提升。Redis所支持的其它数据类型,例如Lists以及Sets——也可被用于实现更加复杂的缓存管理模式。
Redis的另一大重要优势在于,它所保存的数据具备透明化特性,也就是说服务器能够直接对这些数据进行操作。Redis当中提供160多种可用命令,其中大部分用于实现数据处理操作并通过服务器端脚本将逻辑嵌入至数据存储体系当中。这些内置命令及用户脚本带来了极大的灵活性优势,足以帮助大家直接在Redis内部完成数据处理任务——而不必将数据在网络中的其它专门处理系统之间来回移动。
Redis还提供可选而且能够具体调整的数据持久性方案,其设计目的在于在发生规划内停机或者计划外故障之后对缓存内容进行重新引导。这种机制能够在设备重启之后快速将保存在磁盘上的数据重新载入至缓存当中,从而大大缩短缓存预热周期并根据主数据存储内容对当前缓存内容进行重新评估。这种机制能够在设备重启之后快速将保存在磁盘上的数据重新载入至缓存当中,从而大大缩短缓存预热周期并根据主数据存储内容对当前缓存内容进行重新评估。
Redis能够提供复制功能。复制功能旨在帮助缓存体系实现高可用性配置方案,从而在遭遇故障的情况下继续为应用程序提供不间断的缓存服务。
-
Redis与Memcached的区别
(2)特性说明
a.内存内:Redis将键值存储在主内存中,旨在加快读取与写入数据
b.复制:Redis支持主-从复制。相关数据访问可由从节点实现,而写入则可由主节点执行。复制过程具备可扩展性与可用性。如果任一从节点发生故障,其它从节点则继续提供数据访问支持。
c.数据结构:Redis不仅存储字符串,同时亦包含列表、集、散列以及排序集等。
d.虚拟内存:Redis利用RAM作为内存内存储机制。不过在RAM存储过程中,其实际使用虚拟内存进行数据承载。
e.发布/订阅模式:Redis能够创建发布与订阅频道,各Redis客户端能够订阅任意频道以消费数据,而且订阅任意频道的客户端都能够进行数据发布。
f.数据持久性:Redis会将内存内数据保留在文件系统当中以备定期检索。当Redis节点发生故障时,相关数据可由Redis Data文件进行恢复。
四、memcached原理
(1)分布式实现
Memcached的分布式,是由程序实现,比如有多个memcached服务器server1,server2,server3和server4等,
(1)使用addserver将这些服务加入
$host:主机;$port:端口$persistent:控制是否持久化连接默认true;$weight:存储权重;$timeout:控制超时时间默认1s;$retry_interval:控制超时重连时间,默认15s值为-1时表示放弃重连;
(2)添加函数 add|set
$key:键名;$var:值;$flag:对值进行压缩一般取值MEMCACHE_COMPRESSED;$expire:以秒计算的过期时间0表示不过期但是最长时间30天后仍然会过期
(3)常用命令
(4)查询存储结果
其他的分别1 条 3条和 4条数据,我们使用 get 命令查看每一条的值都是不相同的,这就保证了数据的唯一性,为啥4个memcached存入的条数不一样呢,原来我们在 addServer中添加了第四个字段权重字段。根据总的权重分布,和各自的占比然后存入不同权重的数据量
(5)session中使用memcached
(6)memcached在Laravel中的使用
其实框架中,所有的东西都封装好了,不必我们自己动手操作,只需要配置
很明显,我们在 servers 中添加对应的多台memcached服务器就好了。如果需要启动这个作为缓存,在.env文件中添加CACHE_DRIVER=memcached即可。对了,肿么多了个参数 sasl ?里面还有用户名和密码,详情请点击这里进行安装配置
(7)memcached的特点和弊端
a. 保存的item数量没有限制只要内存足够
b.32位系统中使用的最大存储空间是 2GB 64位无限制
c.key最长250超过无法存储
d. 单个key存储数据最大1M超过无法存储
e. 算法 hash存储(例如取余增加服务器会导致命中失败) 一致性存储(增加服务器不会影响)
f. 不能遍历所有key操作会引起阻塞