Vert.x系列(三)--ClusteredEventBus源码分析
前言:因为ClusteredEventBus涉及集群,有必产生网络问题,从而引入了NetServer、ServerID等涉及网络,端口的类。在之前的EventBusImpl中, 使用的数据结构是以address-List<Handler>作为k-v的map容器。作为EventBusImpl的子类,ClusteredEventBus的逻辑结构上一样的。 不过把address-List<ServerID>作为k-v。
原理:在start方法中,利用第三方框架(默认hazelcast)实现的集群同步map(变量subs) ,获取已有的节点信息。然后根据参数,对自身服务器的端口实现监听,把自身服务器信息放入前面的map,让其他节点感知。调用consumer方法时,以address-List<ServerID>作为k-v存在一个map的容器中。调用send方法时,以address为k从map里取出ServerID.然后把消息利用TCP协议发送给对应的服务器。
代码:
public static final String CLUSTER_PUBLIC_HOST_PROP_NAME = "vertx.cluster.public.host";// 这2个字段是为了从System.getProperty()取值,优先级//1.System.getProperty()2.EventBusOptions
public static final String CLUSTER_PUBLIC_PORT_PROP_NAME = "vertx.cluster.public.port";
private static final Buffer PONG = Buffer.buffer(new byte[]{(byte) 1});
private static final String SERVER_ID_HA_KEY = "server_id";
private static final String SUBS_MAP_NAME = "__vertx.subs"; //集群数据存放在集群同步的map中,需要约定一个固定的key统一存取。
private final ClusterManager clusterManager;
private final HAManager haManager;
private final ConcurrentMap<ServerID, ConnectionHolder> connections = new ConcurrentHashMap<>();//根据socket长链接
private final Context sendNoContext;
private EventBusOptions options; // 创建时的参数
private AsyncMultiMap<String, ClusterNodeInfo> subs; // 集群核心数据 k是address,value是HazelcastClusterNodeInfo
private Set<String> ownSubs = new ConcurrentHashSet<>();// 自身订阅(Subscribe)的addrees
private ServerID serverID; // 自身服务器信息(IP和port)
private ClusterNodeInfo nodeInfo; // 自身集群信息(NodeID、IP和port)
private NetServer server;//
在 public void start(Handler<AsyncResult<Void>> resultHandler) 方法中。
做了很多事件,很多逻辑。
1.subs = ar2.result(); 获取集群数据。从集群拉取数据,ar2.succeeded() 为前置判断。直接排除网络、配置等错误的可能。
2.创建底层的端口监听。这里端口有大坑,有2个概念:
actualPort 和 publicPort
actualPort是值真正监听的端口,从option传值过来,没有则随机产生。
publicPort是放到共享给集群的端口,为了通知别的节点让它们往这里发数据。官方的解释是为了容器情况考虑。在容器里运行时,和主机的端口是通过代理访问的。对于这2个port ,因为这里有好几个变量可以赋值,所有里面有优先级:
actualPort:
1.VertxOptions 也是 EventBusOptions 的setClusterPublicHost,查看VertxOptions.setClusterPort() / VertxOptions.setClusterPublicHost() 方法,发现其实就是对EventBusOptions操作。
2.随机产生。
publicPort
1.系统变量CLUSTER_PUBLIC_PORT_PROP_NAME
2.VertxOptions 也是 EventBusOptions 的setClusterPublicHost
3.上面的actualPort
这因为端口直接涉及到通信,设置不对就无法使用。如果是集群内多节点的情况,需要设置host,不需要设置port. 因为host默认值是 "localhost",port默认值是随机产生的可用端口(假设为51854),host和port会产生ServerID。如果不设置host,A节点就会把 "localhost:51854"传到集群上。其他B节想要访问A时,会根据这个信息去访问 localhost:51854,结果访问到自身去了。
下面重点就是consumer 和 send/poblish方法。
调用consumer方法时,会依次调用到addRegistration(),往集群共享的subs中放入信息,达到传播的目的。
@Override
protected <T> void addRegistration(boolean newAddress, String address,boolean replyHandler, boolean localOnly,Handler<AsyncResult<Void>> completionHandler) {
if (newAddress && subs != null &&www.yigou521.com !replyHandler && !localOnly) {
// Propagate the information
subs.add(address, nodeInfo, completionHandler);
ownSubs.add(address);
} else {
completionHandler.handle(www.yongshiyule178.com Future.succeededFuture());
}
}
调用send/poblish方法时,会依次调用到sendOrPub(),
@Override
protected <T> void sendOrPub(SendContextImpl<T> sendContext) {
String address = sendContext.message.address();
// 这里只是定义resultHandler,没有执行,如果要执行,还需
//要resultHandler.handler(AsyncResult)
Handler<AsyncResult<ChoosableIterable<ClusterNodeInfo>>> resultHandler = asyncResult -> {
if (asyncResult.succeeded()) {
// 重要的 server
ChoosableIterable<ClusterNodeInfo> serverIDs = asyncResult.result();
if (serverIDs != null && !serverIDs.isEmpty(www.gaozhuoyiqi.com)) {
sendToSubs(serverIDs, sendContext);
} else {
if (metrics != null) {
metrics.messageSent(address, !sendContext.message.isSend(www.dfgjyl.cn), true, false);
}
deliverMessageLocally(sendContext);
}
} else {
log.error("Failed to send message"www.gouyiflb.cn/, asyncResult.cause());
}
};
// 这里才是处理 。subs存的是k-v是 address-List<HazelcastClusterNodeInfo>
// get(k)就是把List<HazelcastClusterNodeInfo>取出来,交给上面的handler
if (Vertx.currentContext(www.qwert888.com) == null) {
// Guarantees the order when there is no current context
sendNoContext.runOnContext(v -> {
subs.get(address, resultHandler);
});
} else {
subs.get(address, resultHandler);
}
}
sendToSubs()方法是包含了 send/publish 的判断,这个逻辑本来是在deliverMessageLocally(MessageImpl msg)完成的。
protected MessageImpl createMessage(boolean send, String address, MultiMap headers, Object body, String codecName)方法里,单机版产生的是 MessageImpl, 集群版产生ClusteredMessage。 ClusteredMessage此类包含了对Buffer 的操作,帮助socket通信。
Vert.x系列(三)--ClusteredEventBus源码分析的更多相关文章
- java多线程系列(九)---ArrayBlockingQueue源码分析
java多线程系列(九)---ArrayBlockingQueue源码分析 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 j ...
- Java集合系列[4]----LinkedHashMap源码分析
这篇文章我们开始分析LinkedHashMap的源码,LinkedHashMap继承了HashMap,也就是说LinkedHashMap是在HashMap的基础上扩展而来的,因此在看LinkedHas ...
- Java并发系列[2]----AbstractQueuedSynchronizer源码分析之独占模式
在上一篇<Java并发系列[1]----AbstractQueuedSynchronizer源码分析之概要分析>中我们介绍了AbstractQueuedSynchronizer基本的一些概 ...
- Java并发系列[3]----AbstractQueuedSynchronizer源码分析之共享模式
通过上一篇的分析,我们知道了独占模式获取锁有三种方式,分别是不响应线程中断获取,响应线程中断获取,设置超时时间获取.在共享模式下获取锁的方式也是这三种,而且基本上都是大同小异,我们搞清楚了一种就能很快 ...
- SequoiaDB 系列之七 :源码分析之catalog节点
这一篇紧接着上一篇SequoiaDB 系列之六 :源码分析之coord节点来讲 在上一篇中,分析了coord转发数据包到catalog节点(也有可能是data节点,视情况而定).这一次,我们继续分析上 ...
- SequoiaDB 系列之六 :源码分析之coord节点
好久不见. 在上一篇SequoiaDB 系列之五 :源码分析之main函数,有讲述进程开始运行时,会根据自身的角色,来初始化不同的CB(控制块,control block). 在之前的一篇Sequ ...
- Java并发系列[5]----ReentrantLock源码分析
在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可 ...
- java集合系列之LinkedList源码分析
java集合系列之LinkedList源码分析 LinkedList数据结构简介 LinkedList底层是通过双端双向链表实现的,其基本数据结构如下,每一个节点类为Node对象,每个Node节点包含 ...
- java集合系列之ArrayList源码分析
java集合系列之ArrayList源码分析(基于jdk1.8) ArrayList简介 ArrayList时List接口的一个非常重要的实现子类,它的底层是通过动态数组实现的,因此它具备查询速度快, ...
- 详解Tomcat系列(一)-从源码分析Tomcat的启动
在整个Tomcat系列文章讲解之前, 我想说的是虽然整个Tomcat体系比较复杂, 但是Tomcat中的代码并不难读, 只要认真花点功夫, 一定能啃下来. 由于篇幅的原因, 很难把Tomcat所有的知 ...
随机推荐
- 用PhoneGap创建第一个项目
1.在eclipse中新建Android Project2.在项目的目录下,建两个文件夹:/libs/assets/www3.进入将刚刚下载并解压的PhoneGap包里Anroid目录,我们需要的资源 ...
- (FZU 2150) Fire Game (bfs)
题目链接:http://acm.fzu.edu.cn/problem.php?pid=2150 Problem Description Fat brother and Maze are playing ...
- 多线程系列之三:Immutable 模式
一,什么是Immutable模式?immutable就是不变的,不发生改变的.Immutable模式中存在着确保实例状态不发生变化改变的类.这些实例不需要互斥处理.String就是一个Immutabl ...
- 【问题解决方案】The MathType Dll cannot be found 问题解决方案
先贴几个可能的方法: 如何解决MathPage.wll或MathType.dll文件找不到问题 The MathType Dll cannot be found 问题解决办法 如果还搞不定,试试卸载重 ...
- apache benchmark 的简单安装与测试
1. 下载apache benchmark Copy From https://blog.csdn.net/fyqaccpt96/article/details/43272001 yum instal ...
- HDU 5782 Cycle —— KMP
题目:Cycle 链接:http://acm.hdu.edu.cn/showproblem.php?pid=5782 题意:给出两个字符串,判断两个字符串的每一个前缀是否循环相等(比如abc 和 ca ...
- bootstrap模态框关闭后清除模态框的数据
https://segmentfault.com/q/1010000008789123 bootstrap模态框第二次打开时如何清除之前的数据? 我用了bootstrap模态框的remote功能,在弹 ...
- Day1 基础知识
数据类型,字符编码 二进制: 定义:二进制数据是用0和1两个数码来表示的数.它的基数为2,进位规则是“逢二进一”,借位规则是“借一当二”.当前的计算机系统使用的基本上是二进制系统,数据在计算机中主要是 ...
- uwsgi加nginx部署django restframework前后端分离项目
一.uwsgi和nginx简介 1.uwsgi(摘抄于百度百科): uWSGI是一个Web服务器,它实现了WSGI协议.uwsgi.http等协议.Nginx中HttpUwsgiModule的作用是与 ...
- linux ps命令用法
-A 列出所有的进程-w 显示加宽可以显示较多的资讯-au 显示较详细的资讯-aux 显示所有包含其他使用者的行程 -A 显示所有进程(等价于-e)(utility)-a 显示 ...