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所有的知 ...
随机推荐
- ARC 066D Xor Sum AtCoder - 2272 (打表找规律)
Problem Statement You are given a positive integer N. Find the number of the pairs of integers u and ...
- Django之admin中管理models中的表格
Django之admin中管理models中的表格 django中使用admin管理models中的表格时,如何将表格注册到admin中呢? 具体操作就是在项目文件夹中的app文件夹中的admin中注 ...
- mysql常用命令行操作(一):登陆、退出、查看端口、修改密码、刷新
一.登陆和退出mysql mysql -u root -p # 登陆exit # 退出 二.查看当前mysql的端口号 show global variables like 'port'; 三.查看用 ...
- Codeforces Round #546 (Div. 2)
http://codeforces.com/contest/1136 A #include <bits/stdc++.h> using namespace std; ; int N, K; ...
- pip Read timed out 和 pip 源
解决方法,设置超时时间 pip --default-timeout=100 install -U Pillow 安装时指定源(--index-url) #例如安装scipy时使用豆瓣的源 pip in ...
- node错误中间件处理 express类 带有路由操作
let express = require('express'); let app = new express(); let bodyParser = require('body-parser'); ...
- Azure系列2.1.10 —— CloudBlobClient
(小弟自学Azure,文中有不正确之处,请路过各位大神指正.) 网上azure的资料较少,尤其是API,全是英文的,中文资料更是少之又少.这次由于公司项目需要使用Azure,所以对Azure的一些学习 ...
- mybatis出现NoSuchMethodException异常
今天在idea中调试项目(ssm搭建的项目)的时候,mybatis突然出现了NoSuchMethodException异常,具体的异常时: java.lang.NoSuchMethodExceptio ...
- [转帖] SS, SP, BP 三个寄存器
SS, SP, BP 三个寄存器 https://blog.csdn.net/vspiders/article/details/55669265 这么看 计算机组成原理 还有 考试的很多题目非常有用啊 ...
- 【学亮IT手记】jQuery text()/html()回调函数实例
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script sr ...