1. Snowflake算法
1.1 使用场景
雪花算法广泛应用于分布式系统中的唯一ID生成,它可以保证在分布式环境中生成的ID是唯一且有序的。常见的应用场合包括订单号生成、分布式数据库中的数据主键、分布式锁等。通过使用雪花算法生成全局唯一ID,可以方便地进行分布式系统的数据管理和查询。
Snowflake算法使用一个64位的二进制数字作为ID。这64位long型ID被分割成四个部分:符号位、时间戳、工作机器ID、序列号。通过这几部分来表示不同的信息,将数据映射到具有特定结构的分布式系统中,实现数据的存储和查询。
1.2 算法原理
雪花算法将64位的long型ID分为四个部分:
- 符号位(1位):始终为0,用于标识ID是正数。
- 时间戳(41位):占据了整个ID的41位,精确到毫秒级,可以支持69年的时间戳。这使得雪花算法能够支持未来数十年的唯一性。时间戳部分还提供了排序的功能,可以根据时间戳来对数据进行排序。
- 机器ID(10位):工作机器ID占据了ID的10位,可以支持最多1024个工作节点。这使得在同一台机器上运行的不同应用程序实例可以使用不同的工作机器ID来生成唯一的ID。
- 序列号(12位):序列号占据了ID的12位,可以支持每个节点每毫秒产生4096个唯一的ID。这使得在同一台机器上运行的不同应用程序实例可以生成唯一的ID,即使在毫秒级别内也能保证唯一性。
这样的划分之后相当于在一毫秒一个数据中心的一台机器上可产生4096个有序的不重复的ID。但是我们 IDC 和机器数肯定不止一个,所以毫秒内能生成的有序ID数是翻倍的。
2. 一致性hash算法
2.1 使用场景
在分布式集群中,对机器的添加删除,或者机器故障后自动脱离集群这些操作是分布式集群管理最基本的功能。如果采用常用的hash(object)%N算法,那么在有机器添加或者删除后,很多原有的数据就无法找到了,这样严重的违反了单调性原则。
所以出现了一致性哈希算法,它是在哈希算法基础上提出的,在动态变化的分布式环境中,哈希算法应该满足的几个条件:平衡性、单调性和分散性
- 平衡性:是指hash的结果应该平均分配到各个节点,这样从算法上解决了负载均衡问题。
- 单调性:是指在新增或者删减节点时,不影响系统正常运行。
- 分散性是指数据应该分散地存放在分布式集群中的各个节点(节点自己可以有备份),不必每个节点都存储所有的数据
2.2 简单一致性哈希
1. 把一致哈希算法是对 2^32 进行取模运算的结果值虚拟成一个圆环,环上的刻度对应一个 0~2^32 - 1 之间的数值,如下图:
2. 节点入环 ,比如有三个节点(A/B/C),经过哈希计算放入下面环中(一般我们会根据服务器的IP或者唯一别名进行哈希计算):
3. 接下来如果有数据进来,将key值经过哈希之后结果映射到哈希环上,然后将结果值按顺时针方向找到离自己最近的节点上,将value存储到那个节点上。如图(k1、k2、k3经过哈希计算后在哈希环的位置,顺时针方向找到离自己最近的节点,比如k1最近的节点是A,节点A就是存储 k1数据value的节点):
4. 如果这个时候进行扩容,将三个节点增加到四个节点,而此时k2最近的节点是D就会迁移到D,k1和k3不受影响。
5. 或者缩容,删除一个节点,原来存储在B节点上的k2,将会重新映射找到离它最近的节点C,此时k2的数据存储在C节点上,其他k1、k3不受影响。
2.3 不平衡问题
上述的简单一致性哈希的算法看起来很好的在分布式系统中去扩容缩容,但是假设某个节点宕机,那么它的数据就会落到它后面节点上,导致下个节点数据量暴增,可能导致雪崩,服务挂掉。
因此引入了虚拟节点的概念:虚拟节点可以理解为是作为实际节点的一个copy,多个虚拟节点映射一个实际节点,因为在哈希环上节点越多就分布的越均匀,即使我们现实中不会有那么多真实节点。
假设真实节点A被移除,A对应虚拟节点也会移除,但是多虚拟节点方式可以映射更多真实节点,让剩余的节点更好的承担节点变化的请求压力。如图(真实节点A被移除,那么对应的虚拟节点移除,那么此时k1的重新映射到C-1、k3重新映射到B-3,也就是说被迁移到真实节点B和C,由此可见节点被移除会被更均衡的分散到其他节点上):