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所有的知 ...
随机推荐
- (Beta)团队贡献分
Beta阶段团队每个成员都积极响应一起完成了开发, 所以最后我们一致决定各个成员的贡献分相同. 林珣玙 53 康家华 52 张启东 51 刘彦熙 49 马瑶华 48 仇栋民 47
- Elasticsearch 5.0Head插件
Elasticsearch 5.0 —— Head插件部署指南 使用ES的基本都会使用过head,但是版本升级到5.0后,head插件就不好使了.下面就看看如何在5.0中启动Head插件吧! 官方 ...
- 记第一次多用户在Git提交代码
今天第一次进行了多用户(其实就两人)在自建Git服务器提交代码. 先记录碰到的问题:首先是本地提交代码时,进行了add,commit后,在push时碰到服务器故障,待设置好服务器后,再push时,却p ...
- 单例模式及设计url分发
1.单例模式 2.admin源码解析 3.注册源码流程图 3.admin之url方法的使用 4.admin源码之url设计 5.设计url源码流程 6.总结 1.单例模式 https://www. ...
- Eclipse Todo Tasks 任务试图
java - Find TODO tags in Eclipse - Stack Overflowhttps://stackoverflow.com/questions/16903046/find-t ...
- react render
实际上react render方法返回一个虚拟dom 并没有去执行渲染dom 渲染的过程是交给react 去完成的 这就说明了为什么要在所有数据请求完成后才去实现render 这样做也提高了性能.只调 ...
- Jquery ajax传递xml方式在ie8下兼容问题
主要问题就是ie8把xml格式在打开的时候转换成了string,我们只用把其转换回xml就可以了. $.ajax({ type:’GET’, url:’list.php?pagenow=’+count ...
- spring 注解 之 AOP基于@Aspect的AOP配置
Spring AOP面向切面编程,可以用来配置事务.做日志.权限验证.在用户请求时做一些处理等等.用@Aspect做一个切面,就可以直接实现. 1.首先定义一个切面类,加上@Component @A ...
- Java HashMap的put操作(Java1.6)
https://www.cnblogs.com/skywang12345/p/3310835.html // 存储数据的Entry数组,长度是2的幂. // HashMap是采用拉链法实现的,每一个E ...
- 存储过程中的 SET XACT_ABORT ON 和事务
在存储过程中写SET XACT_ABORT ON 有什么用? SET XACT_ABORT ON是设置事务回滚的!当为ON时,如果你存储中的某个地方出了问题,整个事务中的语句都会回滚为OFF时,只回滚 ...