分布式一致性算法(面试)以及一致性hash算法

什么是分布式系统的副本一致性?有哪些?

分布式系统通过副本控制协议,使得从系统外部读取系统内部各个副本的数据在一定的约束条件下相同,称之为副本一致性(consistency)。副本一致性是针对分布式系统而言的,不是针对某一个副本而言。

强一致性(strong consistency):任何时刻任何用户或节点都可以读到最近一次成功更新的副本数据。强一致性是程度最高的一致性要求,也是实践中最难以实现的一致性。

单调一致性(monotonic consistency):任何时刻,任何用户一旦读到某个数据在某次更新后的值,这个用户不会再读到比这个值更旧的值。单调一致性是弱于强一致性却非常实用的一种一致性级别。因为通常来说,用户只关心从己方视角观察到的一致性,而不会关注其他用户的一致性情况。

会话一致性(session consistency):任何用户在某一次会话内一旦读到某个数据在某次更新后的值,这个用户在这次会话过程中不会再读到比这个值更旧的值。会话一致性通过引入会话的概念,在单调一致性的基础上进一步放松约束,会话一致性只保证单个用户单次会话内数据的单调修改,对于不同用户间的一致性和同一用户不同会话间的一致性没有保障。实践中有许多机制正好对应会话的概念,例如php 中的session 概念。

最终一致性(eventual consistency):最终一致性要求一旦更新成功,各个副本上的数据最终将达 到完全一致的状态,但达到完全一致状态所需要的时间不能保障。对于最终一致性系统而言,一个用户只要始终读取某一个副本的数据,则可以实现类似单调一致性的效果,但一旦用户更换读取的副本,则无法保障任何一致性。

弱一致性(week consistency):一旦某个更新成功,用户无法在一个确定时间内读到这次更新的值,且即使在某个副本上读到了新的值,也不能保证在其他副本上可以读到新的值。弱一致性系统一般很难在实际中使用,使用弱一致性系统需要应用方做更多的工作从而使得系统可用。

# 在分布式系统中有哪些常见的一致性算法?

  • 分布式算法 - 一致性Hash算法
    • 一致性Hash算法是个经典算法,Hash环的引入是为解决单调性(Monotonicity)的问题;虚拟节点的引入是为了解决平衡性(Balance)问题
  • 分布式算法 - Paxos算法
    • Paxos算法是Lamport宗师提出的一种基于消息传递的分布式一致性算法,使其获得2013年图灵奖。自Paxos问世以来就持续垄断了分布式一致性算法,Paxos这个名词几乎等同于分布式一致性, 很多分布式一致性算法都由Paxos演变而来
  • 分布式算法 - Raft算法
    • Paxos是出了名的难懂,而Raft正是为了探索一种更易于理解的一致性算法而产生的。它的首要设计目的就是易于理解,所以在选主的冲突处理等方式上它都选择了非常简单明了的解决方案
  • 分布式算法 - ZAB算法
    • ZAB 协议全称:Zookeeper Atomic Broadcast(Zookeeper 原子广播协议), 它应该是所有一致性协议中生产环境中应用最多的了。为什么呢?因为他是为 Zookeeper 设计的分布式一致性协议!

一致性Hash算法详述

算法原理

一致性哈希算法在 1997 年由麻省理工学院提出,是一种特殊的哈希算法,在移除或者添加一个服务器时,能够尽可能小地改变已存在的服务请求与处理请求服务器之间的映射关系;
一致性哈希解决了简单哈希算法在分布式 哈希表(Distributed Hash Table,DHT)中存在的动态伸缩等问题;

一致性hash算法本质上也是一种取模算法;

不过,不同于上边按服务器数量取模,一致性hash是对固定值2^32取模

IPv4的地址是4组8位2进制数组成,所以用2^32可以保证每个IP地址会有唯一的映射;

① hash环

我们可以将这2^32个值抽象成一个圆环⭕️,圆环的正上方的点代表0,顺时针排列,以此类推:1、2、3…直到2^32-1,而这个由2的32次方个点组成的圆环统称为hash环

② 服务器映射到hash环

在对服务器进行映射时,使用hash(服务器ip)% 2^32,即:

使用服务器IP地址进行hash计算,用哈希后的结果对2^32取模,结果一定是一个0到2^32-1之间的整数;

而这个整数映射在hash环上的位置代表了一个服务器,依次将node0node1node2三个缓存服务器映射到hash环上;

③ 对象key映射到服务器

在对对应的Key映射到具体的服务器时,需要首先计算Key的Hash值:hash(key)% 2^32

注:此处的Hash函数可以和之前计算服务器映射至Hash环的函数不同,只要保证取值范围和Hash环的范围相同即可(即:2^32);

将Key映射至服务器遵循下面的逻辑:

从缓存对象key的位置开始,沿顺时针方向遇到的第一个服务器,便是当前对象将要缓存到的服务器;

假设我们有 "semlinker"、"kakuqo"、"lolo"、"fer" 四个对象,分别简写为 o1、o2、o3 和 o4;

首先,使用哈希函数计算这个对象的 hash 值,值的范围是 [0, 2^32-1]:

图中对象的映射关系如下:

hash(o1) = k1; hash(o2) = k2;
hash(o3) = k3; hash(o4) = k4;

同时 3 台缓存服务器,分别为 CS1、CS2 和 CS3:

则可知,各对象和服务器的映射关系如下:

K1 => CS1
K4 => CS3
K2 => CS2
K3 => CS1

即:

以上便是一致性Hash的工作原理;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
一致性哈希算法 (Consistent Hashing) 是一种用于分布式系统中数据的负载均衡策略。它可以有效地解决传统哈希算法在节点增减时需要重新映射大量数据的问题。 在 Java 中实现一致性哈希算法可以使用以下步骤: 1. 创建一个哈希环,用于表示节点的位置。可以使用 TreeMap 或 SortedMap 来实现有序的哈希环。 2. 将节点的标识进行哈希计算,并将其映射到哈希环上的位置。 3. 对于要存储的数据,计算其哈希值,并找到离该哈希值最近的节点位置。可以使用 TreeMap 的 ceilingEntry 方法来查找大于等于给定哈希值的最小键。 4. 将数据存储到相应的节点上。 5. 当节点增加或删除时,只需要重新计算受影响的数据的哈希值,并将其映射到新的节点位置上。 下面是一个简单的 Java 示例代码实现一致性哈希算法: ```java import java.util.SortedMap; import java.util.TreeMap; public class ConsistentHashing { private final SortedMap<Integer, String> hashRing = new TreeMap<>(); private final int virtualNodes; public ConsistentHashing(int virtualNodes) { this.virtualNodes = virtualNodes; } public void addNode(String node) { for (int i = 0; i < virtualNodes; i++) { int hash = getHash(node + i); hashRing.put(hash, node); } } public void removeNode(String node) { for (int i = 0; i < virtualNodes; i++) { int hash = getHash(node + i); hashRing.remove(hash); } } public String getNode(String data) { if (hashRing.isEmpty()) { return null; } int hash = getHash(data); SortedMap<Integer, String> tailMap = hashRing.tailMap(hash); int nodeHash = tailMap.isEmpty() ? hashRing.firstKey() : tailMap.firstKey(); return hashRing.get(nodeHash); } private int getHash(String key) { // 使用合适的哈希算法计算哈希值 // 这里简单使用 key 的 hashCode return key.hashCode(); } } ``` 使用示例: ```java public static void main(String[] args) { ConsistentHashing hashing = new ConsistentHashing(3); hashing.addNode("NodeA"); hashing.addNode("NodeB"); hashing.addNode("NodeC"); String data1 = "Data1"; String data2 = "Data2"; System.out.println(hashing.getNode(data1)); // Output: NodeA System.out.println(hashing.getNode(data2)); // Output: NodeB hashing.addNode("NodeD"); System.out.println(hashing.getNode(data1)); // Output: NodeA System.out.println(hashing.getNode(data2)); // Output: NodeD hashing.removeNode("NodeB"); System.out.println(hashing.getNode(data1)); // Output: NodeA System.out.println(hashing.getNode(data2)); // Output: NodeD } ``` 这是一个简单的一致性哈希算法的实现示例,你可以根据具体的需求来进行扩展和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陪妳去流浪丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值