分布式缓存原理----Hash环/一致性Hash原理/Hash槽

Memcached:为分布式客户端做分发,hash环

TWY Redis:为分布式客户端做分发 ,hash环

Redis Cluster:点对点                      ,2Khash槽

当前,Memcached、Redis这类分布式kv缓存已经非常普遍。从本篇开始,本系列将分析分布式缓存相关的原理、使用策略和最佳实践。

我们知道Memcached的分布式其实是一种“伪分布式”,也就是它的服务器结点之间其实是相互无关联的,之间没有网络拓扑关系,由客户端来决定一个key是存放到哪台机器。

具体来讲,假设我有多台memcached服务器,编号分别为m0,m1,m2,…。对于一个key,由客户端来决定存放到哪台机器,那最简单的hash公式就是 key % N,其中N是机器的总数。

但这有个问题,一旦机器数变少,或者增加机器,N发生变化,那之前存放的数据就全部无效了。因为你按照新的N值取模计算出的机器编号,和当时按旧的N值取模算出的机器编号肯定是不等的,也就意味着绝大部分缓存会失效。

这个问题的解决办法就是用1种特别的Hash函数,尽可能使得,增加机器/减少机器时,缓存失效的数目降到最低,这就是Hash环,或者叫一致性Hash。

Hash环

上面说的Hash函数,只经过了1次hash,即把key hash到对应的机器编号。 
而Hash环有2次Hash: 
(1)把所有机器编号hash到这个环上 
(2)把key也hash到这个环上。然后在这个环上进行匹配,看这个key和哪台机器匹配。

具体来讲,如下:

假定有这样一个Hash函数,其值空间为(0到2的32次方-1) ,也就是说,其hash值是个32位无整型数字 ,这些数字组成一个环。

然后,先对机器进行hash(比如根据机器的ip),算出每台机器在这个环上的位置; 再对key进行hash,算出该key在环上的位置,然后从这个位置往前走,遇到的第一台机器就是该key对应的机器,就把该(key, value) 存储到该机器上。

数据不均匀问题

当你机器不多的时候,很可能出现几台机器在环上面贴的很近,不是在环上均匀分布。这将会导致大部分数据,都会集中在某1台机器上。

为了解决这个问题,可以引入“虚拟机器”的概念,也就是说:1台机器,我在环上面计算出多个位置。怎么弄呢? 假设用机器的ip来hash,我可以在ip后面加上几个编号, ip_1, ip_2, ip_3, .. 把1台物理机器生个多个虚拟机器的编号。

数据首先映射到“虚拟机器上”,再从“虚拟机器”映射到物理机器上。因为虚拟机器可以很多,在环上面均匀分布,从而保证数据均匀分布到物理机器上面。

上面我们提到了服务器的机器增加、减少,问题是客户端怎么知道呢?

一种笨办法就是手动的,当服务器机器增加、减少时候,重新配置客户端,重启客户端。

另外一种,就是引入ZK,服务器的节点列表注册到ZK上面,客户端监听ZK。发现结点数发生变化,自动更新自己的配置。

当然,不用ZK,用一个其他的中心结点,只要能实现这种更改的通知,也是可以的。

但从Redis 3.0开始,引入了Redis Cluster,从此Redis进入了真正的“分布式集群“时代。而在“集群角度“,可以说Redis已经和Memcached有了很多重大的区别。

面这个表,从“集群角度“比较了2者的重大区别:

分布式缓存原理----Hash环/一致性Hash原理/Hash槽_第1张图片


P2P架构

P2P模式,无中央结点,结点之间通过一个称之为Gossip的协议进行通信。

16384个hash槽

不同于Memcached的一致性Hash,Redis准备了16384个hash槽,类似于Memcached Hash环上的一个个位置。 
这16384个hash槽被分配给不同节点,存放数据时,根据数据的key计算出所在的槽,再根据槽找到对应的机器。hash函数为:CRC16(key) % 16384。

为什么是16384?

很显然,我们需要维护节点和槽之间的映射关系,每个节点需要知道自己有哪些槽,并且需要在结点之间传递这个消息。

为了节省存储空间,每个节点用一个Bitmap来存放其对应的槽: 
2k = 2*1024*8 = 16384,也就是说,每个结点用2k的内存空间,总共16384个比特位,就可以存储该结点对应了哪些槽。然后这2k的信息,通过Gossip协议,在结点之间传递。

客户端存储路由信息

对于客户端来说,维护了一个路由表:每个槽在哪台机器上。这样存储(key, value)时,根据key计算出槽,再根据槽找到机器。

无损扩容

虽然Hash环可以减少扩容时失效的key的数量,但毕竟有丢失。而在redis-cluster中,当新增机器之后,槽会在机器之间重新分配,同时被影响的数据会自动迁移,从而做到无损扩容。

主从复制

redis-cluster也引入了master-slave机制,从而提供了fail-over机制,这很大程度上解决了“缓存雪崩“的问题。关于这个,后面有机会再详细阐述。



你可能感兴趣的:(分布式缓存)