0
3
3
1
博客/.../

TiDB 7.5 业务切换后的节点故障测试记录

 拍脑袋小助手  发表于  2026-09-01
原创测试

业务切换后还要验证节点故障

前面的测试已经把 MySQL 数据通过 DM 迁到了 TiDB,也做了业务切换和回退。业务切到 TiDB 后,还要确认节点发生故障时会有什么影响。实际生产中在节点故障时,主要考虑的是挂号、收费和医嘱能不能继续,已有连接和事务是否受影响。这些问题都需要结合业务操作来检查。

TiDB Server 是无状态 SQL 层,PD 通常部署三个或更多的奇数节点,TiKV 默认保存三份数据副本。少数副本故障时,集群可以自动进行故障转移,但应用不一定完全无感。如果 JDBC 直连某一台 TiDB Server,该节点停止后当前连接仍会断开。TiKV Region Leader 发生变化时,TiDB 会在内部重试;恢复时间超过 backoff 阈值后,错误仍可能返回客户端。

一、测试环境

继续使用前面已经搭好的 TiDB 7.5 集群。

组件 节点
TiDB Server 192.168.56.101:4000192.168.56.102:4000
PD 192.168.56.101:2379192.168.56.102:2379192.168.56.103:2379
TiKV 192.168.56.101:20160192.168.56.102:20160192.168.56.103:20160
TiDB 版本 v7.5.7
测试数据库 his_source

业务表继续使用前文已经迁移到 TiDB 的几张表:

outpatient_visit    门诊就诊
charge_detail       收费明细
doctor_order        医嘱

测试前先看集群状态:

tiup cluster display tidb75-lab

数据库里也查一下实际拓扑:

SELECT
    TYPE,
    INSTANCE,
    STATUS_ADDRESS,
    VERSION,
    UPTIME
FROM information_schema.CLUSTER_INFO
ORDER BY TYPE, INSTANCE;

CLUSTER_INFO 可以直接看到 TiDB、PD、TiKV 的实例地址、版本和运行时间,比只看操作系统进程方便一些。

二、先准备一笔完整的模拟门诊业务

这次不单独建探针表,直接使用门诊、收费和医嘱三张业务表。

先生成一条测试就诊:

INSERT INTO his_source.outpatient_visit
(
    visit_no,
    patient_no,
    dept_code,
    visit_type,
    visit_time,
    visit_status,
    update_time
)
VALUES
(
    'TEST-MZ-0901-37',
    'TEST-PAT-037',
    'CARD',
    'OUTPATIENT',
    NOW(),
    'WAITING',
    NOW()
);

TEST-MZ-0901-37 是本次故障测试使用的模拟门诊号,TEST-PAT-037 是专门生成的测试患者编号,不使用真实患者姓名、身份证号、住院号或医保信息。

确认记录已经存在:

SELECT
    visit_no,
    patient_no,
    dept_code,
    visit_time,
    visit_status
FROM his_source.outpatient_visit
WHERE visit_no = 'TEST-MZ-0901-37';

后面的收费和医嘱都挂在这次测试就诊下面。故障结束后除了检查数据是否写入,还要核对门诊、收费和医嘱之间的关联关系。

三、TiDB Server 停一台以后会发生什么

上一篇做业务切换时,测试程序直接连接 192.168.56.101:4000。这种方式方便查看迁移过程,不能作为正式的高可用接入设计。

先直接连接第一台 TiDB:

mysql -h 192.168.56.101 -P 4000 \
  -u his_app -p his_source

保持这个会话,再从 TiUP 中控机人为停止这一台 TiDB Server:

tiup cluster stop tidb75-lab \
  -N 192.168.56.101:4000

-N 后面使用的是 tiup cluster display 第一列显示的节点 ID。TiUP 官方支持通过这个参数只停止指定服务。

这条命令只模拟单个 TiDB Server 服务不可用,不包含服务器断电、网络中断或进程崩溃。原来直接连接 192.168.56.101:4000 的客户端会失去这条连接。

这时候改连第二台:

mysql -h 192.168.56.102 -P 4000 \
  -u his_app -p his_source

如果集群状态正常,第二台 TiDB Server 仍可提供 SQL 服务。TiDB Server 本身不保存业务数据,多台 TiDB Server 通常通过 LVS、HAProxy、F5 等负载均衡组件提供统一入口。这个操作只能确认集群还有其他 SQL 节点可用,不能证明原有应用连接不会中断。

四、通过第二台 TiDB 做一笔收费

第一台 TiDB Server 仍然保持停止状态,通过 192.168.56.102:4000 写入一笔测试收费:

INSERT INTO his_source.charge_detail
(
    charge_no,
    visit_no,
    item_type,
    item_code,
    item_name,
    qty,
    unit_price,
    amount,
    charge_time,
    charge_status
)
VALUES
(
    'TEST-SF-0901-06',
    'TEST-MZ-0901-37',
    'REG',
    'TEST-REG-FEE',
    '普通门诊诊查费',
    1,
    15.00,
    15.00,
    NOW(),
    'PAID'
);

查询:

SELECT
    charge_no,
    visit_no,
    item_type,
    amount,
    charge_status,
    charge_time
FROM his_source.charge_detail
WHERE charge_no = 'TEST-SF-0901-06';

这里按 charge_novisit_no 的关联检查业务数据。TiDB Server 不保存业务数据,两个 TiDB Server 访问的是同一个 TiKV 存储集群,无需按 TiDB Server 区分数据。

第一台 TiDB 恢复:

tiup cluster start tidb75-lab \
  -N 192.168.56.101:4000

再从第一台查询:

SELECT
    charge_no,
    visit_no,
    amount,
    charge_status
FROM his_source.charge_detail
WHERE charge_no = 'TEST-SF-0901-06';

这一步用于确认两个 TiDB Server 入口查到的是同一条收费记录。

五、PD 测试先找到 Leader,不把地址写死

PD 和 TiDB Server 的情况不一样。PD 保存集群元信息、数据分布信息,并负责时间戳分配和调度。TiDB 官方建议 PD 部署不少于三个节点,并使用奇数节点组成高可用集群。

测试前先找当前 PD Leader:

tiup ctl:v7.5.7 pd \
  -u http://192.168.56.101:2379 \
  member leader show

member leader show 是 PD Control 提供的 Leader 查询命令。Leader 会动态变化,不能提前指定 192.168.56.101 一定是 PD Leader。实际返回哪一台,就停哪一台。例如查询结果为 192.168.56.102:2379,测试命令为:

tiup cluster stop tidb75-lab \
  -N 192.168.56.102:2379

停止以后,从另一个在线 PD 再查 Leader:

tiup ctl:v7.5.7 pd \
  -u http://192.168.56.101:2379 \
  member leader show

三节点 PD 集群失去一个节点后仍满足多数派条件,但这个操作不能证明业务完全无感。Leader 重新选举需要时间,现场还要记录业务 SQL 是否报错、延迟是否有明显变化,不能只看 PD 是否选出新的 Leader。

六、PD Leader 切换期间做一次医嘱写入

PD Leader 停止以后,通过 TiDB 写一条模拟医嘱:

INSERT INTO his_source.doctor_order
(
    order_no,
    visit_no,
    order_type,
    order_code,
    order_name,
    start_time,
    order_status,
    update_time
)
VALUES
(
    'TEST-YZ-0901-03',
    'TEST-MZ-0901-37',
    'LAB',
    'TEST-LAB-CBC',
    '血常规测试项目',
    NOW(),
    'ACTIVE',
    NOW()
);

确认:

SELECT
    order_no,
    visit_no,
    order_type,
    order_code,
    order_status,
    start_time
FROM his_source.doctor_order
WHERE order_no = 'TEST-YZ-0901-03';

这里同样不使用真实医嘱数据,TEST-LAB-CBC 只是测试项目编码。

测试结束后恢复刚才停止的 PD:

tiup cluster start tidb75-lab \
  -N 192.168.56.102:2379

实际执行时要使用前面查到的 Leader 地址,不要直接复制示例地址。

七、停 TiKV 之前,先看副本是不是健康

TiKV 默认三副本,但停节点前仍要确认各个 Region 是否有足够的健康副本。事务在数据成功写入 Raft 多数副本后才能提交,少数副本故障时可以继续提供服务。故障测试前先检查 Region 状态。

tiup ctl:v7.5.7 pd \
  -u http://192.168.56.101:2379 \
  region check miss-peer

再查:

tiup ctl:v7.5.7 pd \
  -u http://192.168.56.101:2379 \
  region check down-peer

以及:

tiup ctl:v7.5.7 pd \
  -u http://192.168.56.101:2379 \
  region check pending-peer

PD Control 对这几个状态的定义如下:

  • miss-peer:Region 缺副本;
  • down-peer:存在已经 Down 的副本;
  • pending-peer:存在暂时不可用的副本。

如果已经存在异常 Region,应先处理原有副本问题,不再继续停止 TiKV。tiup cluster display 显示三台 TiKV 都是 Up,也不能代替 Region 副本状态检查。

八、再看一下 TiKV 当前分布

数据库里可以直接查询 TiKV Store:

SELECT
    STORE_ID,
    ADDRESS,
    STORE_STATE_NAME,
    LEADER_COUNT,
    REGION_COUNT,
    LAST_HEARTBEAT_TS,
    UPTIME
FROM information_schema.TIKV_STORE_STATUS
ORDER BY STORE_ID;

TIKV_STORE_STATUS 可以看到 Store 地址、Region 数量、Leader 数量和最近心跳等信息。

Region Peer 也可以查:

SELECT
    STATUS,
    COUNT(*) AS peer_count
FROM information_schema.TIKV_REGION_PEERS
GROUP BY STATUS
ORDER BY STATUS;

TIKV_REGION_PEERS 中的 Peer 状态包括 NORMALPENDINGDOWN。这里先记录故障前的 Store、Region 和 Peer 状态,停止 TiKV 后再作比较。

九、模拟单 TiKV 节点不可用

确认副本状态没有异常以后,选择一个 TiKV 做测试。以下以 192.168.56.103:20160 为例:

tiup cluster stop tidb75-lab \
  -N 192.168.56.103:20160

这里仍然只是服务级故障模拟,与服务器断电、交换机故障或磁盘损坏不同。

停止后先看:

tiup cluster display tidb75-lab

同时持续执行查询:

SELECT
    visit_no,
    patient_no,
    visit_status
FROM his_source.outpatient_visit
WHERE visit_no = 'TEST-MZ-0901-37';

再查收费:

SELECT
    charge_no,
    amount,
    charge_status
FROM his_source.charge_detail
WHERE charge_no = 'TEST-SF-0901-06';

如果这些数据所在 Region 仍然有 Raft 多数副本可用,TiDB 可以继续完成读取和写入。

如果故障节点上存在 Region Leader,Leader 需要重新选举。TiDB 遇到 not leaderepoch not match、请求超时等 Region 暂时不可用情况时,会在内部进行 backoff 重试,不能预设停一台 TiKV 后业务完全无感。

官方故障排查文档说明,如果 Region 在默认 backoff 阈值内恢复,客户端可以不感知;超过阈值后,则可能返回 Region is Unavailable。文档给出的默认阈值是约 20 秒。

实际医院系统还受 JDBC、连接池和应用超时配置影响。如果应用超时时间比数据库内部重试时间短,业务侧可能先报超时。节点测试要记录 SQL 报错、延迟变化和应用超时,不能只看数据库最后是否恢复。

十、TiKV 少一个节点期间,再做一次收费状态更新

收费业务不适合为了测试反复插入同一张收费单,这里对前面的测试收费做一次状态变更。先改成待确认:

UPDATE his_source.charge_detail
SET charge_status = 'CHECKING'
WHERE charge_no = 'TEST-SF-0901-06';

确认:

SELECT
    charge_no,
    visit_no,
    amount,
    charge_status
FROM his_source.charge_detail
WHERE charge_no = 'TEST-SF-0901-06';

再恢复成:

UPDATE his_source.charge_detail
SET charge_status = 'PAID'
WHERE charge_no = 'TEST-SF-0901-06';

这组操作用于检查 TiKV 节点停止期间已有收费记录能否正常更新。

十一、TiKV 恢复以后还要检查 Region

恢复节点:

tiup cluster start tidb75-lab \
  -N 192.168.56.103:20160

等待服务恢复后:

tiup cluster display tidb75-lab

然后重新做副本检查:

tiup ctl:v7.5.7 pd \
  -u http://192.168.56.101:2379 \
  region check miss-peer
tiup ctl:v7.5.7 pd \
  -u http://192.168.56.101:2379 \
  region check down-peer
tiup ctl:v7.5.7 pd \
  -u http://192.168.56.101:2379 \
  region check pending-peer

TiKV 进程重新显示为 Up 后,还要等 Region 副本状态恢复正常。如果生产环境发生硬件损坏,节点无法继续使用,需要按 TiKV 缩容、替换和补副本的流程处理。

十二、故障期间不能看到数据库报错就直接重做收费

故障测试还要检查业务重试逻辑。假设应用正在提交收费:

INSERT INTO charge_detail ...

如果这时发生网络异常,客户端看到数据库错误后,不能直接认定“收费肯定没有成功”,也不能立即把原 SQL 再发一次。收费系统一般使用业务流水号控制重复提交,例如收费流水号、支付流水号或结算流水号。本次测试使用的 TEST-SF-0901-06 在表里有唯一约束。

应用异常以后,先按业务流水查询:

SELECT
    charge_no,
    visit_no,
    amount,
    charge_status
FROM his_source.charge_detail
WHERE charge_no = 'TEST-SF-0901-06';

确认业务状态以后,再决定补做还是继续后面的处理。

TiDB 返回错误后,需要按错误码和具体报错内容处理,不能把所有异常都改成自动重试。

错误码 v7.5 文档中的处理要点
8022 事务提交失败且已经回滚,应用可以安全地重新执行整个事务。
8028 与事务期间的表结构变化有关,处理方式还受元数据锁状态和 DDL 类型影响。
9007 表示写冲突,需要继续查看报错中的具体原因,不能直接套用 8022 的处理方式。

对于悲观事务,也不能套用乐观事务自动重试参数。tidb_disable_txn_auto_retrytidb_retry_limit 只作用于乐观事务。

收费、退费、医嘱和发药业务仍要有自己的幂等控制,不能只依赖数据库重试。

十三、所有节点恢复后,再从业务关系检查一次

节点都恢复以后:

tiup cluster display tidb75-lab

数据库侧重新确认拓扑:

SELECT
    TYPE,
    INSTANCE,
    VERSION,
    UPTIME
FROM information_schema.CLUSTER_INFO
ORDER BY TYPE, INSTANCE;

然后检查这次测试使用的门诊记录:

SELECT
    visit_no,
    patient_no,
    dept_code,
    visit_status,
    visit_time
FROM his_source.outpatient_visit
WHERE visit_no = 'TEST-MZ-0901-37';

收费:

SELECT
    charge_no,
    visit_no,
    item_name,
    amount,
    charge_status
FROM his_source.charge_detail
WHERE visit_no = 'TEST-MZ-0901-37';

医嘱:

SELECT
    order_no,
    visit_no,
    order_name,
    order_status
FROM his_source.doctor_order
WHERE visit_no = 'TEST-MZ-0901-37';

再检查业务关联:

SELECT
    v.visit_no,
    COUNT(DISTINCT c.charge_no) AS charge_count,
    COUNT(DISTINCT o.order_no) AS order_count
FROM his_source.outpatient_visit v
LEFT JOIN his_source.charge_detail c
       ON c.visit_no = v.visit_no
LEFT JOIN his_source.doctor_order o
       ON o.visit_no = v.visit_no
WHERE v.visit_no = 'TEST-MZ-0901-37'
GROUP BY v.visit_no;

这条 SQL 检查测试就诊下的收费和医嘱数量,用于确认三张业务表之间的关联记录是否完整。

十四、数据库入口还缺一层高可用

上一篇使用的连接方式是:

JDBC
  ↓
192.168.56.101:4000

第一台 TiDB Server 停止后,应用正在使用的连接会断开。集群里还有其他 TiDB Server,不代表应用能够自动找到新的节点。多台 TiDB Server 前面需要通过 LVS、HAProxy、F5 等负载均衡组件提供统一入口。

后续准备完善统一入口,再检查 TiDB Server 计划重启时连接池如何迁移、未完成事务如何处理,以及统一入口自身故障时应用能否重新建连。

0
3
3
1

版权声明:本文为 TiDB 社区用户原创文章,遵循 CC BY-NC-SA 4.0 版权协议,转载请附上原文出处链接和本声明。

评论
暂无评论