
# 两地三中心跨Region容灾计划内倒换switchover流程异常
#### 问题现象
**现象一：**
计划内switchover中主数据库实例执行命令返回如下错误，提示主数据库实例产生一致性点失败。
```
Result exception error : Failed to generate switchover barrier before switchover
```
**现象二：**
计划内switchover中主数据库实例执行命令返回如下错误，提示主数据库实例业务截断出现失败。
```
Result exception error : Failed to truncate service before switchover
```
**现象三：**
计划内switchover中灾备数据库实例执行命令返回如下错误，提示灾备数据库实例核查数据一致性点出现超时。
```
Result exception error : Failed to do check switchover_barrier on all main standby dn and cn. Because check timeout: XXs
```
**现象四：**
计划内switchover启用快速倒换模式后，容灾倒换出现失败。
**现象五：**
主备倒换过程中，有故障节点未参与容灾倒换。
**现象六：**
计划内switchover成功，但倒换过程中，原主数据库实例的原主DN发生进程退出。
#### 原因分析
**现象一原因：**
在主数据库实例接收到计划内switchover命令，主数据库实例降为灾备数据库实例前会产生一致性点switchover barrier。这是执行switchover的前提，用于保证主备数据库实例所有DN分片的日志停止在一致性点。由于主数据库实例内网络抖动等原因导致主实例内产生switchover barrier失败将放弃本次计划内switchover。
**现象二原因：**
在主数据库实例接收到计划内switchover命令，主数据库实例降为灾备数据库实例前会产生一致性点switchover barrier，并进行业务截断终止日志写入操作。这是执行switchover的前提，用于保证主备数据库实例所有DN分片的日志停止在一致性点。由于主数据库实例内DN实例异常，异地网络异常，灾备数据库实例不会响应等原因导致主数据库实例业务截断失败将放弃本次计划内switchover。
**现象三原因：**
在灾备数据库实例接收到计划内switchover命令，灾备数据库实例升为主数据库实例前会在首备DN上查询是否收到一致性点switchover barrier。这是执行switchover的前提，用于保证主备数据库实例所有DN分片的日志停止在一致性点。由于异地网络异常等原因，灾备数据库实例在超时时间内无法获得switchover barrier将放弃执行本次计划内switchover。
**现象四原因：**
容灾倒换过程中因为主备数据库实例之间网络异常等导致容灾倒换失败。
**现象五原因：**
因服务器宕机，网络中断等原因导致节点未参与主备倒换。
**现象六原因：**
在原主DN日志中搜索关键字"abort switchover"，如果有该关键字，说明是因为降备超时，DN进程主动退出，属于正常现象，待DN被CM重新拉起即可。如果没有，则需要进一步排查日志确定原因。
#### 处理方法
常规容灾倒换流程故障处理步骤：
1. 主数据库实例执行switchover主降备命令，灾备数据库实例执行switchover灾备升主命令超时或者失败会回滚为倒换前状态，计划内倒换switchover可在主数据库实例和灾备数据库实例重新执行。
2. 若多次执行switchover均出现失败，需进一步分析流式容灾相关日志文件。
快速倒换流程故障处理步骤：
1. 通过cm_ctl工具确认数据库实例是否完成倒换或者回滚，实例状态是否正常，异常节点可使用节点修复功能。 
   ```
   cm_ctl query -Cvp
   ```
   主数据库normal态示例：
   ```
   [  CMServer State   ]
   node             instance state
   ---------------------------------
   1  <IP> 1        Standby
   2  <IP> 2        Primary
   3  <IP> 3        Standby
   4  <IP> 4        Standby
   [    ETCD State     ]
   node             instance state
   ---------------------------------------
   1  <IP> 7001     StateLeader
   2  <IP> 7002     StateFollower
   3  <IP> 7003     StateFollower
   4  <IP> 7004     StateFollower
   5  <IP> 7005     StateFollower
   [   Cluster State   ]
   cluster_state   : Normal
   redistributing  : No
   balanced        : No
   current_az      : AZ_ALL
   [  Datanode State   ]
   node             instance        state            | node             instance        state            | node             instance        state            | node             instance state
   ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   1  <IP> 6001 <PORT>       P Standby Normal | 2  <IP> 6002 <PORT>        S Standby Normal | 3  <IP> 6003 <PORT>        S Primary Normal | 4  <IP> 6004 <PORT>        S Standby Normal
   ```
   灾备数据库normal态示例：
   ```
   [  CMServer State   ]
   node             instance state
   ---------------------------------
   1  <IP> 1        Primary
   2  <IP> 2        Standby
   3  <IP> 3        Standby
   [    ETCD State     ]
   node             instance state
   ---------------------------------------
   1  <IP> 7001     StateFollower
   2  <IP> 7002     StateLeader
   3  <IP> 7003     StateFollower
   [   Cluster State   ]
   cluster_state   : Degraded
   redistributing  : No
   balanced        : No
   current_az      : AZ_ALL
   [  Datanode State   ]
   node             instance        state            | node             instance        state            | node             instance state
   ------------------------------------------------------------------------------------------------------------------------------------------------------------
   1  <IP> 6001 <PORT>       P Cascade Standby Normal | 2  <IP> 6002 <PORT>       S Cascade Standby Normal | 3  <IP> 6003 <PORT>       S Main Standby Normal
   ```
   
   
2. 倒换失败数据库实例参数，使用gs_om工具进行查询。 
   ```
   gs_om -t dr_post_check -c [switchover|failover|query] -m [primary|disaster_standby] --dr_type streaming_cluster
   ```
   - 主数据库实例相关参数：
     - cmserver参数backup_open=0，dn_arbitrate_mode=quorum，enable_transaction_read_only=on，cm_hadr_process_type=none。
     
     - cmagent参数agent_backup_open=0，enable_auto_start=1，cm_hadr_process_type=none。
     
     - etcd参数/xxxx/CMServer/backup_open=0。
     
     - DN参数stream_cluster_run_mode=cluster_primary，hadr_process_type=none，default_transaction_read_only=off。
      
   
   - 灾备数据库实例相关参数：
     - cmserver参数backup_open=2，dn_arbitrate_mode=quorum，enable_transaction_read_only=on，cm_hadr_process_type=none。
     
     - cmagent参数agent_backup_open=2，enable_auto_start=1，cm_hadr_process_type=none。
     
     - etcd参数/xxxx/CMServer/backup_open=2。
     
     - DN参数stream_cluster_run_mode=cluster_standby，hadr_process_type=none，default_transaction_read_only=off。
      
   
   
   
   
3. 出现双灾备数据库实例状态的极端场景，需人工介入修复。
   
   - 出现双灾备数据库实例场景，一般指主数据库实例降为灾备数据库实例并且未回滚，灾备数据库实例升主流程出现回滚。此时两个数据库实例均不可写入。
   
   - 使用gs_om工具对原主数据库实例进行修复，目标恢复为主数据库实例。
     ```
     echo "password" | gs_om -t dr_cluster_manual_recovery -m primary --dr_type streaming_cluster [--time-out=SECS]
     ```
     
   
   
   
   - 修复成功，关闭只读，相关参数default_transaction_read_only置为off。
   
   
   
   
4. 出现双主数据库实例状态极端场景，需人工介入修复。
   
   - 出现双主数据库实例场景，一般指灾备数据库实例升主成功并且关闭了只读；主数据库实例降为灾备流程出现失败并且执行了回滚，保持只读打开状态。
   
   - 数据库实例使用gs_om工具对原主数据库实例进行修复，目标变为灾备数据库实例。
     ```
     echo "password" | gs_om -t dr_cluster_manual_recovery -m disaster_standby --dr_type streaming_cluster [--time-out=SECS]
     ```
     
   
   
   
   - 原主数据库实例因为开了只读，不会有客户数据进入，但是日志依然会分叉，修复过程较长。修复成功，关闭只读，相关参数default_transaction_read_only置为off。
   
   
   ![](https://support.huaweicloud.com/centralized-devg-v10-gaussdb/public_sys-resources/note_3.0-zh-cn.png)
   - 当使用[3]、[4]中描述的修复工具（dr_cluster_manual_recovery）对数据库实例进行修复时，若数据库实例存在日志堆积，修复的具体时长受数据库实例重启后待回放的日志量影响。
   
   - 可通过排查对应数据库实例节点的gs_log日志确认，若日志中持续打印"xlog redo at lsn X/XXX"，且节点为STARTING状态，可以判断节点正在回放堆积的日志，等待修复流程结束即可。
    
   
   
5. 基于数据库实例管理模式的容灾关系时，修复完成后可通过数据库实例刷新容灾序列接口POST /v1/om/agent/mgr/cluster/dr_cluster_serial_change 指定"opt_type"为"set_dr_repl_dest_conf"修改日志接收端数据库实例信息。
6. 通过后置检查接口查询未参与容灾倒换的实例，使用cm_ctl stop停掉未参与容灾倒换的datanode实例。 
   ```
   gs_om -t dr_post_check -c switchover -m primary|disaster_standby --dr_type streaming_cluster
   cm_ctl stop -n NODEID -D DATADIR
   ```
   
   
7. 对未参与倒换的实例进行节点修复。
8. 删除残留的归档槽。 
   - 排查DN是否存在归档槽残留。
     ```
     SELECT slot_name FROM pg_catalog.pg_get_replication_slots() where slot_type='physical' and slot_name not in ('gs_roach_full', 'gs_roach_inc', 'gs_roach_table_full', 'gs_roach_table_inc') and slot_name not like 'cn_%' and slot_name not like 'dn_%';
     ```
     
   
   - 若存在归档槽，则执行如下SQL删除（slot_name为查询到的归档槽名）。
     ```
     SELECT * FROM pg_catalog.pg_drop_replication_slot('slot_name');
     ```
     
   
   
   
   
 
