相同之处:都解决了数据缓存系统中数据如何存储与路由。
不同之处:区别在于虚拟节点和物理节点的映射办法不同
由于一般的哈希函数返回一个int(32bit)型的hashCode。因此,可以将该哈希函数能够返回的hashCode表示成一个范围为0---(2^32)-1 环
数据和节点使用相同的hash函数来保证 把数据和节点映射到相同的hash空间上。这样,按照顺时针方向,数据存放在它所在的顺时针方向上的那个机器上。这就是一致性哈希算法分配数据的方式!
物理节点: 使用ip或者唯一机器标识为key 映射到环上,hash算法CRC32, MD5,SHA-1等加密算法或者更高效的 MurMurHash非加密算法。
虚拟节点: 使用ip+"#"+num(“192.168.0.1#1”),不同的虚拟节点(i不同)有不同的hash值,但都对应同一个实际机器node
数据: 使用对象名(全路径名)称为key,算法同样是MD5
均衡性:引入虚拟节点(相当于ceph中的pg)方法来保证, 副本的个数*实际节点数,副本必须保持在不同的物理节点
虚拟节点”( virtual node )是实际节点(机器)在 hash 空间的复制品( replica ),一实际个节点(机器)对应了若干个“虚拟节点”,这个对应个数也成为“复制个数”,“虚拟节点”在 hash 空间中以hash值排列。
单调性:映入hash环的方法来保证。
一致性哈希采用的做法如下:引入一个环的概念,如上面的第一个图。先将机器映射到这个环上,再将数据也通过相同的哈希函数映射到这个环上,数据存储在它顺时针走向的那台机器上。以环为中介,实现了数据与机器数目之间的解藕。这样,当机器的数目变化时,只会影响到增加或删除的那台机器所在的环的邻接机器的数据存储,而其他机器上的数据不受影响。
ceph中pg值设置参考: 2的次方。
《learning ceph》这本书里的计算公式也差不多:
Total PGs = ((Total_number_of_OSD * 100) / max_replication_count) / pool_count
结算的结果往上取靠近2的N次方的值。比如总共OSD数量是160,复制份数3,pool数量也是3,那么按上述公式计算出的结果是1777.7。取跟它接近的2的N次方是2048,那么每个pool分配的PG数量就是2048。
一致性hash算法中虚拟节点的设置:
当前节点个数*副本数
数据的路由过程/算法: ceph 中叫CRUSH
object-->virtual node-->machine
对于一个实际机器节点 node, 对应 numberOfReplicas 个虚拟节点,
不同的虚拟节点(i不同)有不同的hash值,但都对应同一个实际机器node,
虚拟node一般是均衡分布在环上的,数据存储在顺时针方向的虚拟node上,
获得一个最近的顺时针节点,根据给定的key 取Hash,
然后再取得顺时针方向上最近的一个虚拟节点对应的实际节点,
查看MD5算法生成的hashCode值---表示整个哈希环中各个虚拟节点位置
代码参考: 下面第一个链接。
一致性hash算法实现有两个关键问题需要解决,一个是用于结点存储和查找的数据结构的选择,另一个是结点hash算法的选择。
首先来谈一下一致性hash算法中用于存储结点的数据结构。通过了解一致性hash的原理,我们知道结点可以想象为是存储在一个环形的数据结构上(如下图),结点A、B、C、D按hash值在环形分布上是有序的,也就是说结点可以按hash值存储在一个有序的队列里。如下图所示,当一个hash值为-2^20的请求点P查找路由结点时,一致性hash算法会按hash值的顺时针方向路由到第一个结点上(B),也就是相当于要在存储结点的有序结构中,按查询的key值找到大于key值中的最小的那个结点。因此,我们应该选择一种数据结构,它应该高效地支持结点频繁地增删,也必须具有理想的查询效率。那么,红黑树可以满足这些要求。红黑树是一颗近似平衡的一颗二叉查找树,因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。 因此,我们选择使用红黑树作为结点的存储结构,除了需要实现红黑树基本的插入、删除、查找的基本功能,我们还应该增加另一个查询lookup函数,用于查找大于key中最小的结点。
C++map 内部实现方式即为红黑树,即直接使用STL::map 就可以。
代码参考:
参考:
每天进步一点点——五分钟理解一致性哈希算法(consistent hashing)