mirror of
https://github.com/apache/rocketmq.git
synced 2026-08-30 18:10:44 +08:00
* docs(controller): add chinese docs about persistent-unique-broker-id 1. add chinese docs about persistent-unique-broker-id * docs(controller): optimize style in docs: persistent-unique-broker-id.md 1. optimize style in docs: persistent-unique-broker-id.md * docs(controller): remove test in docs: persistent-unique-broker-id.md 1. remove test in docs: persistent-unique-broker-id.md
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
# 持久化的唯一BrokerId
|
||||
|
||||
## 现阶段问题
|
||||
|
||||
现在采用`BrokerAddress`作为Broker在Controller模式下的唯一标识。导致如下情景出现问题:
|
||||
|
||||
- 容器环境下,每次Broker的重启或升级都可能会导致IP发生变化,导致之前的`BrokerAddress`留下的记录没办法和重启后的Broker联系起来,比如说`ReplicaInfo`, `SyncStateSet`等数据。
|
||||
|
||||
## 改进方案
|
||||
|
||||
在Controller侧采用`BrokerName:BrokerId`作为唯一标识,不再以`BrokerAddress`作为唯一标识。并且需要对`BrokerId`进行持久化存储,由于`ClusterName`和`BrokerName`都是启动的时候在配置文件中配置好的,所以只需要处理`BrokerId`的分配和持久化问题。
|
||||
Broker第一次上线的时候,只有配置文件中配置的`ClusterName`和`BrokerName`,以及自身的`BrokerAddress`。那么我们需要和`Controller`协商出一个在整个集群生命周期中都唯一确定的标识:`BrokerId`,该`BrokerId`从1开始分配。当Broker被选为Master的时候,它会在Name Server中重新注册,此时为了兼容之前的无HA的Master-Slave架构,那么需要在这一步暂时更改为`BrokerId`为0(之前的逻辑里面id为0代表着Broker是Master身份)。
|
||||
|
||||
### 上线流程
|
||||
|
||||

|
||||
|
||||
#### 1. GetNextBrokerId Request
|
||||
|
||||
这时候发起一个`GetNextBrokerId`的请求到Controller,为了拿到当前的下一个待分配的`BrokerId`(从1开始分配)。
|
||||
|
||||
#### 1.1 ReadFromDLedger
|
||||
|
||||
此时Controller接收到请求,然后走DLedger去获取到状态机的`NextBrokerId`数据。
|
||||
|
||||
#### 2. GetNextBrokerId Response
|
||||
|
||||
Controller将`NextBrokerId`返回给Broker。
|
||||
|
||||
#### 2.1 CreateTempMetaFile
|
||||
|
||||
Broker拿到`NextBrokerId`之后,创建一个临时文件`.broker.meta.temp`,里面记录了`NextBrokerId`(也就是期望应用的`BrokerId`),以及自己生成一个`RegisterCode`(用于之后的身份校验)也持久化到临时文件中。
|
||||
|
||||
#### 3. ApplyBrokerId Request
|
||||
|
||||
Broker携带着当前自己的基本数据(`ClusterName`、`BrokerName`和`BrokerAddress`)以及此时期望应用的`BrokerId`和`RegisterCode`,发送一个`ApplyBrokerId`的请求到Controller。
|
||||
|
||||
#### 3.1 CASApplyBrokerId
|
||||
|
||||
Controller通过DLedger写入该事件,当该事件(日志)被应用到状态机的时候,判断此时是否可以应用该`BrokerId`(若`BrokerId`已被分配并且也不是分配给该Broker时则失败)。并且此时会记录下来该`BrokerId`和`RegisterCode`之间的关系。
|
||||
|
||||
#### 4. ApplyBrokerId Response
|
||||
|
||||
若上一步成功应用了该`BrokerId`,此时则返回成功给Broker,若失败则返回当前的`NextBrokerId`。
|
||||
|
||||
#### 4.1 CreateMetaFileFromTemp
|
||||
|
||||
若上一步成功的应用了该`BrokerId`,那么此时可以视为Broker侧成功的分配了该BrokerId,那么此时我们也需要彻底将这个BrokerId的信息持久化,那么我们就可以直接原子删除`.broker.meta.temp`并创建`.broker.meta`。删除和创建这两步需为原子操作。
|
||||
|
||||
> 经过上述流程,第一次上线的broker和controller成功协商出一个双方都认同的brokeId并持久化保存起来。
|
||||
|
||||
#### 5. RegisterBrokerToController Request
|
||||
|
||||
之前的步骤已经正确协商出了`BrokerId`,但是这时候有可能Controller侧保存的`BrokerAddress`是上次Broker上线的时候的`BrokerAddress`,所以现在需要更新一下`BrokerAddress`,发送一个`RegisterBrokerToController` 请求并带上当前的`BrokerAddress`。
|
||||
|
||||
#### 5.1 UpdateBrokerAddress
|
||||
|
||||
Controller比对当前该Broker在Controller状态机中保存的`BrokerAddress`,若和请求中携带的不一致则更新为请求中的`BrokerAddress`。
|
||||
|
||||
#### 6. RegisterBrokerToController Response
|
||||
|
||||
Controller侧在更新完`BrokerAddress`之后可携带着当前该Broker所在的`Broker-set`的主从信息返回,用于通知Broker进行相应的身份转变。
|
||||
|
||||
### 注册状态轮转
|
||||
|
||||

|
||||
|
||||
### 故障容错
|
||||
|
||||
> 如果在正常上线流程中出现了各种情况的宕机,则以下流程保证正确的`BrokerId`分配
|
||||
|
||||
#### 正常重启后的节点上线
|
||||
|
||||
若是正常重启,那么则已经在双方协商出唯一的`BrokerId`,并且本地也在`broker.meta`中有该`BrokerId`的数据,那么就该注册流程不需要进行,直接继续后面的流程即可。即从`RegisterBrokerToController`处继续上线即可。
|
||||
|
||||

|
||||
|
||||
#### CreateTempMetaFile失败
|
||||
|
||||

|
||||
|
||||
如果是上图中的流程失败的话,那么Broker重启后,Controller侧的状态机本身也没有分配任何`BrokerId`。Broker自身也没有任何数据被保存。因此直接重新按照上述流程从头开始走即可。
|
||||
|
||||
#### CreateTempMetaFile成功,ApplyBrokerId未成功
|
||||
|
||||
若是Controller侧已经认为本次`ApplyBrokerId`请求不对(请求去分配一个已被分配的`BrokerId`并且该 `RegisterCode`不相等),并且此时返回当前的`NextBrokerId`给Broker,那么此时Broker直接删除`.broker.meta.temp`文件,接下来回到第2步,重新开始该流程以及后续流程。
|
||||
|
||||

|
||||
|
||||
#### ApplyBrokerId成功,CreateMetaFileFromTemp未成功
|
||||
|
||||
上述情况可以出现在`ApplyResult`丢失、CAS删除并创建`broker.meta`失败,这俩流程中。
|
||||
那么重启后,Controller侧是已经认为我们`ApplyBrokerId`流程是成功的了,而且也已经在状态机中修改了BrokerId的分配数据,那么我们这时候重新直接开始步骤3,也就是发送`ApplyBrokerId`请求的这一步。
|
||||
|
||||

|
||||
|
||||
因为我们有`.broker.meta.temp`文件,可以从中拿到我们之前成功在Controller侧应用的`BrokerId`和`RegisterCode`,那么直接发送给Controller,如果Controller中存在该`BrokerId`并且`RegisterCode`和请求中的`RegisterCode`相等,那么视为成功。
|
||||
|
||||
### 正确上线后使用BrokerId作为唯一标识
|
||||
|
||||
当正确上线之后,之后Broker的请求和状态记录都以`BrokerId`作为唯一标识。心跳等数据的记录都以`BrokerId`为标识。
|
||||
同时Controller侧也会记录当前该`BrokerId`的`BrokerAddress`,在主从切换等时候用于通知Broker状态变化。
|
||||
|
||||
## 升级方案
|
||||
|
||||
4.x版本升级遵守5.0升级文档流程即可。
|
||||
5.x非持久化BrokerId版本升级到持久化BrokerId版本按照如下流程:
|
||||
|
||||
### 升级Controller
|
||||
|
||||
1. 将旧版本Controller组停机。
|
||||
2. 清除Controller数据,即默认在`~/DLedgerController`下的数据文件。
|
||||
3. 上线新版Controller组。
|
||||
|
||||
> 在上述升级Controller流程中,Broker仍可正常运行,但无法切换。
|
||||
|
||||
### 升级Broker
|
||||
|
||||
1. 将Broker从节点停机。
|
||||
2. 将Broker主节点停机。
|
||||
3. 将所有的Broker的Epoch文件删除,即默认为`~/store/epochFileCheckpoint`和`~/store/epochFileCheckpoint.bak`。
|
||||
4. 将原先的主Broker先上线,等待该Broker当选为master。(可使用`admin`命令的`getSyncStateSet`来观察)
|
||||
5. 将原来的从Broker全部上线。
|
||||
|
||||
> 建议停机时先停从再停主,上线时先上原先的主再上原先的从,这样可以保证原来的主备关系。
|
||||
若需要改变升级前后主备关系,则需要停机时保证主、备的CommitLog对齐,否则可能导致数据被截断而丢失。
|
||||
|
||||
### 兼容性
|
||||
|
||||
| | 5.0旧Controller | 新Controller |
|
||||
| --- | --- | --- |
|
||||
| 5.0旧Broker | 正常运行,可切换 | 若已主备确定则可正常运行,不可切换。若broker重新启动则无法上线 |
|
||||
| 新Broker | 无法正常上线 | 正常运行,可切换 |
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 8.8 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 129 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 92 KiB |
Reference in New Issue
Block a user