前言:因为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源码分析的更多相关文章

  1. java多线程系列(九)---ArrayBlockingQueue源码分析

    java多线程系列(九)---ArrayBlockingQueue源码分析 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 j ...

  2. Java集合系列[4]----LinkedHashMap源码分析

    这篇文章我们开始分析LinkedHashMap的源码,LinkedHashMap继承了HashMap,也就是说LinkedHashMap是在HashMap的基础上扩展而来的,因此在看LinkedHas ...

  3. Java并发系列[2]----AbstractQueuedSynchronizer源码分析之独占模式

    在上一篇<Java并发系列[1]----AbstractQueuedSynchronizer源码分析之概要分析>中我们介绍了AbstractQueuedSynchronizer基本的一些概 ...

  4. Java并发系列[3]----AbstractQueuedSynchronizer源码分析之共享模式

    通过上一篇的分析,我们知道了独占模式获取锁有三种方式,分别是不响应线程中断获取,响应线程中断获取,设置超时时间获取.在共享模式下获取锁的方式也是这三种,而且基本上都是大同小异,我们搞清楚了一种就能很快 ...

  5. SequoiaDB 系列之七 :源码分析之catalog节点

    这一篇紧接着上一篇SequoiaDB 系列之六 :源码分析之coord节点来讲 在上一篇中,分析了coord转发数据包到catalog节点(也有可能是data节点,视情况而定).这一次,我们继续分析上 ...

  6. SequoiaDB 系列之六 :源码分析之coord节点

    好久不见. 在上一篇SequoiaDB 系列之五   :源码分析之main函数,有讲述进程开始运行时,会根据自身的角色,来初始化不同的CB(控制块,control block). 在之前的一篇Sequ ...

  7. Java并发系列[5]----ReentrantLock源码分析

    在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可 ...

  8. java集合系列之LinkedList源码分析

    java集合系列之LinkedList源码分析 LinkedList数据结构简介 LinkedList底层是通过双端双向链表实现的,其基本数据结构如下,每一个节点类为Node对象,每个Node节点包含 ...

  9. java集合系列之ArrayList源码分析

    java集合系列之ArrayList源码分析(基于jdk1.8) ArrayList简介 ArrayList时List接口的一个非常重要的实现子类,它的底层是通过动态数组实现的,因此它具备查询速度快, ...

  10. 详解Tomcat系列(一)-从源码分析Tomcat的启动

    在整个Tomcat系列文章讲解之前, 我想说的是虽然整个Tomcat体系比较复杂, 但是Tomcat中的代码并不难读, 只要认真花点功夫, 一定能啃下来. 由于篇幅的原因, 很难把Tomcat所有的知 ...

随机推荐

  1. (Beta)团队贡献分

    Beta阶段团队每个成员都积极响应一起完成了开发, 所以最后我们一致决定各个成员的贡献分相同. 林珣玙 53 康家华 52 张启东 51 刘彦熙 49 马瑶华 48 仇栋民 47

  2. Elasticsearch 5.0Head插件

    Elasticsearch 5.0 —— Head插件部署指南   使用ES的基本都会使用过head,但是版本升级到5.0后,head插件就不好使了.下面就看看如何在5.0中启动Head插件吧! 官方 ...

  3. 记第一次多用户在Git提交代码

    今天第一次进行了多用户(其实就两人)在自建Git服务器提交代码. 先记录碰到的问题:首先是本地提交代码时,进行了add,commit后,在push时碰到服务器故障,待设置好服务器后,再push时,却p ...

  4. 单例模式及设计url分发

      1.单例模式 2.admin源码解析 3.注册源码流程图 3.admin之url方法的使用 4.admin源码之url设计 5.设计url源码流程 6.总结 1.单例模式 https://www. ...

  5. Eclipse Todo Tasks 任务试图

    java - Find TODO tags in Eclipse - Stack Overflowhttps://stackoverflow.com/questions/16903046/find-t ...

  6. react render

    实际上react render方法返回一个虚拟dom 并没有去执行渲染dom 渲染的过程是交给react 去完成的 这就说明了为什么要在所有数据请求完成后才去实现render 这样做也提高了性能.只调 ...

  7. Jquery ajax传递xml方式在ie8下兼容问题

    主要问题就是ie8把xml格式在打开的时候转换成了string,我们只用把其转换回xml就可以了. $.ajax({ type:’GET’, url:’list.php?pagenow=’+count ...

  8. spring 注解 之 AOP基于@Aspect的AOP配置

    Spring AOP面向切面编程,可以用来配置事务.做日志.权限验证.在用户请求时做一些处理等等.用@Aspect做一个切面,就可以直接实现. 1.首先定义一个切面类,加上@Component  @A ...

  9. Java HashMap的put操作(Java1.6)

    https://www.cnblogs.com/skywang12345/p/3310835.html // 存储数据的Entry数组,长度是2的幂. // HashMap是采用拉链法实现的,每一个E ...

  10. 存储过程中的 SET XACT_ABORT ON 和事务

    在存储过程中写SET XACT_ABORT ON 有什么用? SET XACT_ABORT ON是设置事务回滚的!当为ON时,如果你存储中的某个地方出了问题,整个事务中的语句都会回滚为OFF时,只回滚 ...