*/
public class ConsistentHashingWithoutVirtualNode
{
/**
- 待添加入Hash环的服务器列表
*/
private static String[] servers = {“192.168.0.0:111”, “192.168.0.1:111”, “192.168.0.2:111”,
“192.168.0.3:111”, “192.168.0.4:111”};
/**
- key表示服务器的hash值,value表示服务器的名称
*/
private static SortedMap<Integer, String> sortedMap =
new TreeMap<Integer, String>();
/**
- 程序初始化,将所有的服务器放入sortedMap中
*/
static
{
for (int i = 0; i < servers.length; i++)
{
int hash = getHash(servers[i]);
System.out.println(“[” + servers[i] + “]加入集合中, 其Hash值为” + hash);
sortedMap.put(hash, servers[i]);
}
System.out.println();
}
/**
- 得到应当路由到的结点
*/
private static String getServer(String node)
{
// 得到带路由的结点的Hash值
int hash = getHash(node);
// 得到大于该Hash值的所有Map
SortedMap<Integer, String> subMap =
sortedMap.tailMap(hash);
// 第一个Key就是顺时针过去离node最近的那个结点
Integer i = subMap.firstKey();
// 返回对应的服务器名称
return subMap.get(i);
}
public static void main(String[] args)
{
String[] nodes = {“127.0.0.1:1111”, “221.226.0.1:2222”, “10.211.0.1:3333”};
for (int i = 0; i < nodes.length; i++)
System.out.println(“[” + nodes[i] + “]的hash值为” +
getHash(nodes[i]) + “, 被路由到结点[” + getServer(nodes[i]) + “]”);
}
}
带虚拟节点的一致性Hash算法
上面的hash算法可能会造成数据分布不均匀的情况,也就是 说大多数访问请求都会集中少量几个节点上。所以我们可以通过虚拟节点的方式解决数据分布不均的情况。
其实,就是对每一个服务器节点计算多个哈希值,在每个计算结果位置上,都放置一个虚拟 节点,并将虚拟节点映射到实际节点。比如,可以在主机名的后面增加编号,分别计算 “Node-A-01”,“Node-A-02”,“Node-B-01”,“Node-B-02”,“Node-C01”,“Node-C-02”的哈希值,于是形成 6 个虚拟节点:
增加了节点后,节点在哈希环上的分布就相对均匀了。这时,如果有访 问请求寻址到“Node-A-01”这个虚拟节点,将被重定位到节点 A。
具体代码实现如下:
/**
- 带虚拟节点的一致性Hash算法
*/
public class ConsistentHashingWithVirtualNode
{
/**
- 待添加入Hash环的服务器列表
*/
private static String[] servers = {“192.168.0.0:111”, “192.168.0.1:111”, “192.168.0.2:111”,
“192.168.0.3:111”, “192.168.0.4:111”};
/**
- 真实结点列表,考虑到服务器上线、下线的场景,即添加、删除的场景会比较频繁,这里使用LinkedList会更好
*/
private static List realNodes = new LinkedList();
/**
- 虚拟节点,key表示虚拟节点的hash值,value表示虚拟节点的名称
*/
private static SortedMap<Integer, String> virtualNodes =
new TreeMap<Integer, String>();
/**
- 虚拟节点的数目,这里写死,为了演示需要,一个真实结点对应5个虚拟节点
*/
private static final int VIRTUAL_NODES = 5;
static
{
// 先把原始的服务器添加到真实结点列表中
for (int i = 0; i < servers.length; i++)
realNodes.add(servers[i]);
// 再添加虚拟节点,遍历LinkedList使用foreach循环效率会比较高
for (String str : realNodes)
{
for (int i = 0; i < VIRTUAL_NODES; i++)
{
String virtualNodeName = str + “&&VN” + String.valueOf(i);
int hash = getHash(virtualNodeName);
System.out.println(“虚拟节点[” + virtualNodeName + “]被添加, hash值为” + hash);
virtualNodes.put(hash, virtualNodeName);
}
}
System.out.println();
}
/**
- 得到应当路由到的结点
*/
private static String getServer(String node)
{
// 得到带路由的结点的Hash值
int hash = getHash(node);
// 得到大于该Hash值的所有Map
SortedMap<Integer, String> subMap =
virtualNodes.tailMap(hash);
// 第一个Key就是顺时针过去离node最近的那个结点
Integer i = subMap.firstKey();
// 返回对应的虚拟节点名称,这里字符串稍微截取一下
String virtualNode = subMap.get(i);
return virtualNode.substring(0, virtualNode.indexOf(“&&”));
}
public static void main(String[] args)
{
String[] nodes = {“127.0.0.1:1111”, “221.226.0.1:2222”, “10.211.0.1:3333”};
for (int i = 0; i < nodes.length; i++)
System.out.println(“[” + nodes[i] + “]的hash值为” +
getHash(nodes[i]) + “, 被路由到结点[” + getServer(nodes[i]) + “]”);
}
}
Gossip 协议,顾名思义,就像流言蜚语一样,利用一种随机、带有传染性的方式,将信息 传播到整个网络中,并在一定时间内,使得系统内的所有节点数据一致。Gossip 协议通过上面的特性,可以保证系统能在极端情况下(比如集群中只有一个节点在运行)也能运行。
Gossip数据传播方式
Gossip数据传播方式分别有:直接邮寄(Direct Mail)、反熵(Anti-entropy)和谣言传播 (Rumor mongering)。
直接邮寄(Direct Mail):就是直接发送更新数据,当数据发送失败时,将数据缓存下来,然后重传。直接邮寄虽然实现起来比较容易,数据同步也很及时,但可能会因为 缓存队列满了而丢数据。也就是说,只采用直接邮寄是无法实现最终一致性的。
反熵(Anti-entropy):反熵指的是集群中的节点,每隔段时间就随机选择某个其他节点,然后通过互相交换自己的 所有数据来消除两者之间的差异,实现数据的最终一致性。
在实现反熵的时候,主要有推、拉和推拉三种方式。推方式,就是将自己的所有副本数据,推给对方,修复对方副本中的熵,拉方式,就是拉取对方的所有副本数据,修复自己副本中的熵。
谣言传播 (Rumor mongering):指的是当一个节点有了新数据后,这个节点变成活跃状态,并周期性地联系其他节点向其发送新数据,直到所有的节点都存储了该新数据。由于谣言传播非常具有传染性,它适合动态变化的分布式系统
Quorum NWR 中有三个要素,N、W、R。
N 表示副本数,又叫做复制因子(Replication Factor)。也就是说,N 表示集群中同一份 数据有多少个副本,就像下图的样子:
在这个三节点的集群中,DATA-1 有 2 个副本,DATA-2 有 3 个副 本,DATA-3 有 1 个副本。也就是说,副本数可以不等于节点数,不同的数据可以有不同 的副本数。
W,又称写一致性级别(Write Consistency Level),表示成功完成 W 个副本更新。
R,又称读一致性级别(Read Consistency Level),表示读取一个数据对象时需要读 R 个副本。
通过 Quorum NWR,你可以自定义一致性级别,通过临时调整写入或者查询的方式,当 W + R > N 时,就可以实现强一致性了。
所以假如要读取节点B,我们再假设W(2) + R(2) > N(3)这个公式,也就是当写两个节点,读的时候也同时读取两个节点,那么读取数据的时候肯定是读取返回给客户端肯定是最新的那份数据。
关于 NWR 需要你注意的是,N、W、R 值的不同组合,会产生不同的一致性效 果,具体来说,有这么两种效果:
当 W + R > N 的时候,对于客户端来讲,整个系统能保证强一致性,一定能返回更新后的那份数据。
当 W + R < N 的时候,对于客户端来讲,整个系统只能保证最终一致性,可能会返回旧数据。
PBFT 算法非常实用,是一种能在实际场景中落地的拜占庭容错算法。
我们从一个例子入手,看看PBFT 算法的具体实现:
假设苏秦再一次带队抗秦,这一天,苏秦和 4 个国家的 4 位将军赵、魏、韩、楚商量军机 要事,结果刚商量完没多久苏秦就接到了情报,情报上写道:联军中可能存在一个叛徒。这 时,苏秦要如何下发作战指令,保证忠将们正确、一致地执行下发的作战指令,而不是被叛 徒干扰呢?
需要注意的是,所有的消息都是签名消息,也就是说,消息发送者的身份和消息内容都是 无法伪造和篡改的(比如,楚无法伪造一个假装来自赵的消息)。
首先,苏秦联系赵,向赵发送包含作战指令“进攻”的请求(就像下图的样子)。
当赵接收到苏秦的请求之后,会执行三阶段协议(Three-phase protocol)。
赵将进入预准备(Pre-prepare)阶段,构造包含作战指令的预准备消息,并广播给其他 将军(魏、韩、楚)。
因为魏、韩、楚,收到消息后,不能确认自己接收到指令和其他人接收到的指令是相同的。所以需要进入下一个阶段。
接收到预准备消息之后,魏、韩、楚将进入准备(Prepare)阶段,并分别广播包含作战 指令的准备消息给其他将军。
比如,魏广播准备消息给赵、韩、楚(如图所示)。为了 方便演示,我们假设叛徒楚想通过不发送消息,来干扰共识协商(你能看到,图中的楚 是没有发送消息的)。
因为魏不能确认赵、韩、楚是否收到了 2f(这里的 2f 包括自己,其中 f 为叛徒数,在我的演示中是 1) 个一致的包含作战指令的准备消 息。所以需要进入下一个阶段Commit。
进入提交阶段后,各将军分别广播提交消息给其他将军,也就是告诉其他将军,我已经准备好了,可以执行指令了。
最后,当某个将军收到 2f + 1 个验证通过的提交消息后,大部分的将军们已经达成共识,这时可以执行作战指 令了,那么该将军将执行苏秦的作战指令,执行完毕后发送执行成功的消息给苏秦。
最后,当苏秦收到 f+1 个相同的响应(Reply)消息时,说明各位将军们已经就作战指令达 成了共识,并执行了作战指令。
在上面的这个例子中:
可以将赵、魏、韩、楚理解为分布式系统的四个节点,其中赵是主节点(Primary node),魏、韩、楚是从节点(Secondary node);
将苏秦理解为业务,也就是客户端;
将消息理解为网络消息;
将作战指令“进攻”,理解成客户端提议的值,也就是希望被各节点达成共识,并提交 给状态机的值。
最终的共识是否达成,客户端是会做判断的,如果客户端在指定时间内未 收到请求对应的 f + 1 相同响应,就认为集群出故障了,共识未达成,客户端会重新发送请 求。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
![img](https://i-blog.csdnimg.cn/blog_migrate/5fa27996d6899b31f2084c80db9fd253.jpeg)
最后
针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。
上述的面试题答案都整理成文档笔记。 也还整理了一些面试资料&最新2021收集的一些大厂的面试真题(都整理成文档,小部分截图)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
取)**
![img](https://i-blog.csdnimg.cn/blog_migrate/5fa27996d6899b31f2084c80db9fd253.jpeg)
最后
针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。
[外链图片转存中…(img-9YrNRvwN-1713538060832)]
上述的面试题答案都整理成文档笔记。 也还整理了一些面试资料&最新2021收集的一些大厂的面试真题(都整理成文档,小部分截图)
[外链图片转存中…(img-S0e8mtep-1713538060832)]
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!