架构师训练营 第五周 作业
作业一:
用你熟悉的编程语言实现一致性 hash 算法。
编写测试用例测试这个算法,测试 100 万 KV 数据,10 个服务器节点的情况下,计算这些 KV 数据在服务器上分布数量的标准差,以评估算法的存储负载不均衡性。
哈希算法
首先,一致性哈希算法依赖于普通的哈希算法。大多数同学对哈希算法的理解可能都停留在 JDK 的 hashCode
函数上。其实哈希算法有很多种实现,它们在不同方面都各有优劣,针对不同的场景可以使用不同的哈希算法实现。
下面,我们会介绍一下几款比较常见的哈希算法,并且了解一下它们在分布均匀程度,哈希碰撞概率和性能等方面的优劣。
MD5 算法:
全称为 Message-Digest Algorithm 5,用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一,主流编程语言普遍已有 MD5 实现。MD5 的作用是把大容量信息压缩成一种保密的格式(就是把一个任意长度的字节串变换成定长的16进制数字串)。常见的文件完整性校验就是使用 MD5。
CRC 算法:
全称为 CyclicRedundancyCheck,中文名称为循环冗余校验。它是一类重要的,编码和解码方法简单,检错和纠错能力强的哈希算法,在通信领域广泛地用于实现差错控制。
MurmurHash 算法:
高运算性能,低碰撞率,由 Austin Appleby 创建于 2008 年,现已应用到 Hadoop、libstdc++、nginx、libmemcached 等开源系统。Java 界中 Redis,Memcached,Cassandra,HBase,Lucene和Guava 都在使用它。
FNV 算法:
全称为 Fowler-Noll-Vo 算法,是以三位发明人 Glenn Fowler,Landon Curt Noll,Phong Vo 的名字来命名的,最早在 1991 年提出。 FNV 能快速 hash 大量数据并保持较小的冲突率,它的高度分散使它适用于 hash 一些非常相近的字符串,比如 URL,hostname,文件名,text 和 IP 地址等。
Ketama 算法:
一致性哈希算法的实现之一,其他的哈希算法有通用的一致性哈希算法实现,只不过是替换了哈希映射函数而已,但 Ketama 是一整套的流程,我们将在后面介绍。
一致性哈希算法
首先将缓存服务器( ip + 端口号)进行哈希,映射成环上的一个节点,计算出缓存数据 key 值的 hash key,同样映射到环上,并顺时针选取最近的一个服务器节点作为该缓存应该存储的服务器。具体实现见后续的章节。
比如说,当存在 A,B,C,D 四个缓存服务器时,它们及其 key 值为1的缓存数据在一致性哈希环上的位置如下图所示,根据顺时针取最近一个服务器节点的规则,该缓存数据应该存储在服务器 B 上。
当要存储一个 key 值为4的缓存数据时,它在一致性哈希环上的位置如下所示,所以它应该存储在服务器 C 上。
类似的,key 值为5,6的数据应该存在服务 D 上,key 值为7,8的数据应该存储在服务 A 上。
此时,服务器 B 宕机下线,服务器 B 中存储的缓存数据要进行迁移,但由于一致性哈希环的存在,只需要迁移key 值为1的数据,其他的数据的存储服务器不会发生变化。这也是一致性哈希算法比取余映射算法出色的地方。
由于服务器 B 下线,key 值为1的数据顺时针最近的服务器是 C ,所以数据存迁移到服务器 C 上。
现实情况下,服务器在一致性哈希环上的位置不可能分布的这么均匀,导致了每个节点实际占据环上的区间大小不一。
这种情况下,可以增加虚节点来解决。通过增加虚节点,使得每个节点在环上所“管辖”的区域更加均匀。这样就既保证了在节点变化时,尽可能小的影响数据分布的变化,而同时又保证了数据分布的均匀。
实现方式如下:
StatisticsUtil
KeyUtil
HashAlgorithm.java
DefaultHashAlgorithm
ServerNode
NodeLocator
ConsistentHashNodeLocator
main
更改ConsistentHashNodeLocator虚拟节点大小
12个虚拟节点
方差:5.845460454E8
标准差:24177.387067257703
100个虚拟节点
方差:1.3559987E8
标准差:11644.735720487606
1000个虚拟节点
方差:2.02807308E7
标准差:4503.413238866716
理解了一致性哈希算法。下来继续看看增加节点及,删除节点后,命中率如何.
评论