RocketMQ 源码分析(三) —— 高可用

  1. 概述
    本文主要解析 Namesrv、Broker 如何实现高可用,Producer、Consumer 怎么与它们通信保证高可用。

  2. Namesrv 高可用
    启动多个 Namesrv 实现高可用。
    相较于 Zookeeper、Consul、Etcd 等,Namesrv 是一个超轻量级的注册中心,提供命名服务。

2.1 Broker 注册到 Namesrv
📌 多个 Namesrv 之间,没有任何关系(不存在类似 Zookeeper 的 Leader/Follower 等角色),不进行通信与数据同步。通过 Broker 循环注册多个 Namesrv。

···
1: // ⬇️⬇️⬇️【BrokerOuterAPI.java】
2: public RegisterBrokerResult registerBrokerAll(
3: final String clusterName,
4: final String brokerAddr,
5: final String brokerName,
6: final long brokerId,
7: final String haServerAddr,
8: final TopicConfigSerializeWrapper topicConfigWrapper,
9: final List filterServerList,
10: final boolean oneway,
11: final int timeoutMills) {
12: RegisterBrokerResult registerBrokerResult = null;
13:
14: List nameServerAddressList = this.remotingClient.getNameServerAddressList();
15: if (nameServerAddressList != null) {
16: for (String namesrvAddr : nameServerAddressList) { // 循环多个 Namesrv
17: try {
18: RegisterBrokerResult result = this.registerBroker(namesrvAddr, clusterName, brokerAddr, brokerName, brokerId,
19: haServerAddr, topicConfigWrapper, filterServerList, oneway, timeoutMills);
20: if (result != null) {
21: registerBrokerResult = result;
22: }
23:
24: log.info("register broker to name server {} OK", namesrvAddr);
25: } catch (Exception e) {
26: log.warn("registerBroker Exception, {}", namesrvAddr, e);
27: }
28: }
29: }
30:
31: return registerBrokerResult;
32: }

···

2.2 Producer、Consumer 访问 Namesrv

···
1: // ⬇️⬇️⬇️【NettyRemotingClient.java】
2: private Channel getAndCreateNameserverChannel() throws InterruptedException {
3: // 返回已选择、可连接Namesrv
4: String addr = this.namesrvAddrChoosed.get();
5: if (addr != null) {
6: ChannelWrapper cw = this.channelTables.get(addr);
7: if (cw != null && cw.isOK()) {
8: return cw.getChannel();
9: }
10: }
11: //
12: final List addrList = this.namesrvAddrList.get();
13: if (this.lockNamesrvChannel.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
14: try {
15: // 返回已选择、可连接的Namesrv
16: addr = this.namesrvAddrChoosed.get();
17: if (addr != null) {
18: ChannelWrapper cw = this.channelTables.get(addr);
19: if (cw != null && cw.isOK()) {
20: return cw.getChannel();
21: }
22: }
23: // 从【Namesrv列表】中选择一个连接的返回
24: if (addrList != null && !addrList.isEmpty()) {
25: for (int i = 0; i < addrList.size(); i++) {
26: int index = this.namesrvIndex.incrementAndGet();
27: index = Math.abs(index);
28: index = index % addrList.size();
29: String newAddr = addrList.get(index);
30:
31: this.namesrvAddrChoosed.set(newAddr);
32: Channel channelNew = this.createChannel(newAddr);
33: if (channelNew != null)
34: return channelNew;
35: }
36: }
37: } catch (Exception e) {
38: log.error("getAndCreateNameserverChannel: create name server channel exception", e);
39: } finally {
40: this.lockNamesrvChannel.unlock();
41: }
42: } else {
43: log.warn("getAndCreateNameserverChannel: try to lock name server, but timeout, {}ms", LOCK_TIMEOUT_MILLIS);
44: }
45:
46: return null;
47: }
···

  1. Broker 高可用
    启动多个 Broker分组 形成 集群 实现高可用。
    Broker分组 = Master节点x1 + Slave节点xN。
    类似 MySQL,Master节点 提供读写服务,Slave节点 只提供读服务。

3.2 Broker 主从
每个分组,Master节点 不断发送新的 CommitLog 给 Slave节点。 Slave节点 不断上报本地的 CommitLog 已经同步到的位置给 Master节点。
Broker分组 与 Broker分组 之间没有任何关系,不进行通信与数据同步。
消费进度 目前不支持 Master/Slave 同步。
集群内,Master节点 有两种类型:Master_SYNC、Master_ASYNC:前者在 Producer 发送消息时,等待 Slave节点 存储完毕后再返回发送结果,而后者不需要等待。

3.1.1 配置
目前官方提供三套配置:

2m-2s-async
brokerClusterName brokerName brokerRole brokerId
DefaultCluster broker-a ASYNC_MASTER 0
DefaultCluster broker-a SLAVE 1
DefaultCluster broker-b ASYNC_MASTER 0
DefaultCluster broker-b SLAVE 1
2m-2s-sync
brokerClusterName brokerName brokerRole brokerId
DefaultCluster broker-a SYNC_MASTER 0
DefaultCluster broker-a SLAVE 1
DefaultCluster broker-b SYNC_MASTER 0
DefaultCluster broker-b SLAVE 1
2m-noslave
brokerClusterName brokerName brokerRole brokerId
DefaultCluster broker-a ASYNC_MASTER 0
DefaultCluster broker-b ASYNC_MASTER 0

3.1.3 通信协议
Master节点 与 Slave节点 通信协议很简单,只有如下两条。

对象 用途 第几位 字段 数据类型 字节数 说明
Slave=>Master 上报CommitLog已经同步到的物理位置
0 maxPhyOffset Long 8 CommitLog最大物理位置
Master=>Slave 传输新的 CommitLog 数据
0 fromPhyOffset Long 8 CommitLog开始物理位置
1 size Int 4 传输CommitLog数据长度
2 body Bytes size 传输CommitLog数据

转自:http://www.iocoder.cn/RocketMQ/high-availability/

posted on 2018-06-04 23:25  西界-X  阅读(1039)  评论(0编辑  收藏  举报

导航