注册
MAL 链路检测与故障判定机制
培训园地/ 文章详情 /

MAL 链路检测与故障判定机制

悬铃木 2025/12/19 247 0 0

1. MAL 链路检测与故障判定机制

本测试旨在验证达梦数据库 MAL 系统在不同网络异常场景下的行为表现。MAL 系统作为集群内部通信的基础,其链路检测机制直接决定了集群的高可用响应速度与稳定性。

1.1 基础检测参数(被动检测)

根据配置文档说明,MAL 系统通过心跳机制维护链路状态,其核心行为由 dmmal.ini 中的以下两个参数控制:

  • MAL_CHECK_INTERVAL (检测间隔)
    • 含义:MAL 链路检测的时间间隔。
    • 缺省值:30s。
    • 作用机制:设置系统每隔多少秒发起一次链路通畅性检查。若配置为 0,则不进行检测,这在数据守护环境中是不建议的,因为可能导致网络故障时服务长时间阻塞。
  • MAL_CONN_FAIL_INTERVAL (断开判定阈值)
    • 含义:判定实例之间 MAL 链路断开的时间。
    • 缺省值:10s。
    • 作用机制:仅当 MAL_CHECK_INTERVAL 不为 0 时有效。在发起检测后,如果在此设定的时间内无法连通,则认定链路断开。

1.2 故障认定时间计算逻辑

当发生物理断网(如拔除网线)或严重丢包导致网络不可达时,系统检测到链路断开的时间并非立即触发,而是由上述两个参数共同决定。

理论上的链路故障发现时间 T_malbreak 计算逻辑如下:

  1. 等待检测触发:在最坏情况下,故障发生在上一次检测刚结束之后,系统需要等待一个完整的 MAL_CHECK_INTERVAL 才会发起下一次检测。
  2. 确认断开:发起检测后,系统等待响应。若网络不通,需等待 MAL_CONN_FAIL_INTERVAL 耗尽以确认超时。

因此,MAL 层面的最大故障认定时间公式为:

  • T_malbreak = MAL_CHECK_INTERVAL + MAL_CONN_FAIL_INTERVAL

注意: MAL 链路断开并不等于立即执行故障切换。在数据守护环境中,守护进程(dmwatcher)在得知 MAL 链路断开后,还需经过 DW_ERROR_TIME (配置在 dmwatcher.ini 中) 的超时判断,才会最终认定远程节点故障并启动 Failover 流程。

根据您提供的技术资料,现将其整理为规范的总结报告格式,作为 1.3节 的内容:


1.3 MAL 底层通信机制与故障判定逻辑

本节补充当DM检测到MAL链路中断时,底层的发生机制。内容主要是达梦MAL 系统的底层通信协议、故障检测的归责逻辑,以及例举极端网络隔离场景下的系统行为。

1.3.1 底层通信协议基础

MAL(Message Agency Layer)系统是集群内部通信的基础,其底层机制如下:

  • 通信协议: MAL 系统完全基于 TCP/IP 协议 构建。自 V2.0 版本起,为确保数据传输的可靠性,达梦已全面取消 UDP 协议支持。
  • 连接方式: 数据库实例启动时,会依据 dmmal.ini 配置文件,在各节点间建立长效的 TCP 连接。
  • 心跳检测物理表现: 所谓的链路检测(由 MAL_CHECK_INTERVAL 控制),在物理层面上表现为在 TCP 通道上发送探测数据包,并等待对端的 TCP ACK(确认应答)

1.3.2 故障检测主体与归责逻辑

在链路出现异常时,系统如何判定是“对方故障”还是“自身故障”,取决于检测主体的机制及配置策略。

1. 故障发现主体:

  • 检测进程: 发现 MAL 链路问题的核心进程是 数据库实例进程(dmserver)内部的 MAL 线程(如 dm_mal_thd),而非守护进程(dmwatcher)或监视器(dmmonitor)。
  • 触发流程: MAL 线程检测到连接断开 -> 在日志中打印 MAL link broken -> 修改内存中的链路状态为 DISCONNECTED -> 守护进程(dmwatcher)轮询到此状态后介入处理。

2.故障归责逻辑

系统对链路中断的判定逻辑分为两种情况:

  • 情况 A:默认配置(未配置 MAL_CHECK_IP)—— “默认对方故障”
    • 判定逻辑: 当主库 A 无法联系备库 B 时,主库 A 默认判定自身网络正常,归责于备库 B 失联。
    • 潜在风险: 若实际上是主库 A 自身网卡故障(网络孤岛),且未配置确认监视器或监视器不可达,主库可能误认为自己仍是健康的,从而引发“脑裂”风险。
    • 后果: 此逻辑必须依赖确认监视器进行第三方仲裁,以确认节点真实状态。
  • 情况 B:配置主动检测(配置 MAL_CHECK_IP)—— “自我反省机制”
    • 见1.4节内容

1.3.3 极端场景分析

完全网络隔离(无第三方检测)

前置条件: 实时主备(Realtime) + 故障自动切换模式 + 未配置 MAL_CHECK_IP + 物理断网(主库同时失去与备库、监视器的连接)。

在此场景下,系统不会立即“踢出”备库,而是陷入逻辑死锁(僵死状态),具体推演如下:

1. 归档阻塞与状态保护(dmserver 层)

  • 触发: 物理断网导致主库向备库发送 RLOG_PKG 失败。
  • 机制: 根据实时归档的强一致性要求,主库必须收到备库的确认才能将日志写入本地磁盘。因无法收到确认,写事务线程被阻塞。
  • 动作: 为了防止数据在未同步的情况下写入本地(导致主备不一致),主库实例被迫切换为 SUSPEND(挂起) 状态。

2. 仲裁请求与逻辑锁死(dmwatcher 层)

  • 意图: 守护进程检测到归档失败,意图启动故障处理流程(Failover),即“将备库归档标记为 Invalid,恢复主库 Open”。
  • 约束:自动切换模式下,主库守护进程没有单方面裁决权。为了防止“脑裂”(即防止实际上是自己断网,而误把活着的备库踢出),它必须先进入 CONFIRM(确认) 状态,向确认监视器求证备库是否真的故障。
  • 等待:
    • 通信失败: 主库守护进程尝试向监视器发起状态确认请求。受限于物理网络完全中断,该请求无法送达。
    • **结果:**由于缺乏监视器的仲裁响应,守护进程无法满足 Failover 的前置条件。系统既无法执行备库剔除操作(受限于脑裂保护机制),也无法恢复业务写入(受限于数据一致性保护机制),导致守护进程无限期滞留于 CONFIRM 状态。
    • 接下来的处理取决于守护进程配置文件 dmwatcher.ini 中的参数 DW_FAILOVER_FORCE默认配置(DW_FAILOVER_FORCE = 1)-> 业务自动恢复
    • 达梦考虑到了这种“无监视器且断网”的极端孤岛场景。
      • 机制:主库守护进程进入 CONFIRM 状态,尝试联系监视器。
      • 超时判定:如果联系不上监视器,主库守护进程会等待 3 倍的 DW_ERROR_TIME(故障认定时间,默认为 10-15秒)。
      • 结果:超时后,主库守护进程会强制将主库 Open,并将备库归档标记为 Invalid(失效)。
      • 业务影响:业务只会被阻塞约 30-45 秒(视 DW_ERROR_TIME 配置而定),之后主库降级为单机模式继续服务,不会无限期死锁

3. 最终状态僵死(DW_FAILOVER_FORCE = 0):

  • 如果DW_FAILOVER_FORCE = 0,那么主库将不会进行自动恢复。

  • 主库 A:

    • 状态表现: 实例处于 SUSPEND,守护进程处于 CONFIRM
    • 业务表现: 客户端连接显示成功,但执行写操作(Insert/Update/Commit)时会无限挂起,无响应。
    • 不触发 HALT : 由于未配置 MAL_CHECK_IP 参数,主库缺乏基于第三方参考点(如网关 Ping 检测)的自检机制。系统无法区分“自身网络隔离”与“对端故障”,因此保留进程存活状态以待网络恢复。
  • 备库 B: 若备库网络正常,确认监视器会判定主库 A 失联,将备库 B 提升为新主库。

1.4 主动检测机制

除了上述针对伙伴节点的检测外,MAL 系统还提供了针对自身网络环境的“主动检测”机制,用于防止因自身网卡假死或交换机故障导致的“脑裂”风险。该机制涉及以下参数:

  • MAL_CHECK_IP:配置第三方确认机器的 IP(通常为网关或独立外网机器)。
  • MAL_CHECK_TIMEOUT:单个实例的 MAL 网络最大延迟时间。

工作机制:

  • 数据库实例会定期 Ping MAL_CHECK_IP
  • 如果在检测周期内,实例既无法连接 MAL 伙伴节点,也无法连接 MAL_CHECK_IP(耗时超过 MAL_CHECK_TIMEOUT),系统将判定为自身网络环境故障(而非对方故障)。
  • 此时,为了避免产生脑裂,该实例会主动执行 HALT(停机)操作,从而保护集群数据的一致性。

2. 测试方案

本节规划了详细的测试环境、参数分组、故障模拟手段及日志观测点,旨在验证 MAL_CHECK_INTERVALMAL_CONN_FAIL_INTERVAL 在不同网络恶劣条件下的实际表现。

2.1 测试环境准备

  • 架构:基于 Data Watch 搭建的一主一备实时数据守护环境。
  • 操作系统:Kylin V10
    • iptables:用于模拟网络完全阻断(防火墙层拦截)。
    • tc (Traffic Control):Linux 内核自带流量控制工具,用于模拟网络延迟(Delay)和丢包(Packet Loss)。
    • dmmonitor:达梦监视器(在备库上),用于实时观察集群状态变化。

2.2 测试分组设计

为了对比参数对故障发现时间的影响,设计以下三组对照实验。修改 dmmal.ini 后需重启集群生效。

测试组别 MAL_CHECK_INTERVAL (秒) MAL_CONN_FAIL_INTERVAL (秒) 理论故障认定时间 预期行为特征
A组 (默认/宽松) 30 (缺省值) 10 (缺省值) ≈ 40秒 反应较慢。适合网络质量较差的环境,能容忍较大的网络抖动,但故障发生时业务中断时间较长。
B组 (推荐/标准) 10 10 ≈ 20秒 反应适中。官方搭建文档示例中常用的配置,平衡了灵敏度与稳定性。
C组 (激进/敏捷) 2 2 ≈ 4秒 反应极快。任何轻微的连续丢包都可能导致主备连接断开,极易造成误切换。

2.3 故障模拟方法

针对每一组参数,依次执行以下三种网络故障模拟。

场景 1:完全断网 (Network Partition)

  • 目的:验证 MAL 链路在物理中断下的最大故障发现时间。

  • 操作:使用 iptables 丢弃来自对端 IP 的 TCP 包(沉默无回复,模拟拔网线)。

    # 在备库机器执行,拦截来自主库(IP为192.168.79.141)的MAL端口(61141)
    iptables -I INPUT -s 192.168.79.141 -p tcp --dport 61141 -j DROP
    
  • 恢复iptables -F

场景 2:严重丢包 (Packet Loss)

  • 目的:验证 MAL 协议在丢包情况下的重试机制与连接保持能力。

  • 操作:模拟 50% 的随机丢包率。loss 50% 表示每个发送的数据包都会以 独立 50% 随机概率被 drop

    • TCP 协议是可靠传输协议。如果包丢了,TCP 协议栈会自动重传,导致达梦的数据包传输时间变长(因为在反复重传)。
  • 验证点: 达梦是否会因为重传耗时太久,误以为连接断开。或者达梦的 MAL_CONN_FAIL_INTERVAL 设置得太短,导致在还没有重传成功之前,就判定对方挂了。

    # 在网卡设备(如ens33)上添加规则
    tc qdisc add dev ens33 root netem loss 50%
    
  • 恢复tc qdisc del dev ens33 root

2.4 日志与分析策略

本测试的核心目标是验证 MAL 参数的实际生效机制。由于故障检测是层层递进的(链路层 -> 守护层 -> 全局视图),我们需要通过多窗口实时监控,捕捉故障传导的精确时间戳。

2.4.1 关键日志源

测试期间需同时开启三个终端窗口进行 tail -f 监控。

**1. 实例日志 (dmserver log) **

  • 角色定义: MAL 线程驻留在数据库实例进程中,它是最早感知网络异常的组件。
  • 文件路径: ../log/dm_实例名_年月.log
  • 核心关注点:
    • 检测阶段: 出现 send mal msg failedwait mal response timeout。这表明心跳包发送受阻或超时。
    • 判定阶段(关键): 寻找关键字 set link status to DISCONNECTClose mal connectionMAL link broken
      • 此时内存中将链路状态修改为DISCONNECT
    • 检测耗时: 此时刻的时间戳减去故障注入时间,即为 MAL 链路实际故障认定耗时

**2. 守护进程日志 (dmwatcher log) **

  • 角色定义: 守护进程轮询实例状态,一旦读到 DISCONNECT 状态,即启动计时器(DW_ERROR_TIME)并决定是否切换。
  • 文件路径: ../log/dm_dmwatcher_实例名_年月.log
  • 核心关注点:
    • 接收通知: Receive notify from dmserver, mal link [...] 在·broken
    • 状态切换: WSTATUSOPEN 切换为 ERROR(表示认定远程节点故障)或 CONFIRM(自动模式下的仲裁请求)。
    • 切换耗时: 顺便验证 DW_ERROR_TIME(默认 10s-15s)的超时逻辑是否生效。

3. 监视器界面 (dmmonitor)

  • 角色定义: 展示集群最终的宏观状态变化。
  • 核心关注点: 主备库状态颜色的变化、WSTATUS 字段变化,以及是否出现 Switchover successTakeover success 提示。
  • 分析: 确认故障是否最终触发了业务层面的倒换(Failover)。

2.4.2 场景日志预判

基于 MAL 的通信原理,针对前文设计的三个测试场景,预判日志中将出现的关键信息特征:

场景 1:完全断网 (iptables DROP)

  • 原理: TCP 数据包被静默丢弃,没有任何回执(ACK/RST)。
  • dmserver 日志预判:
    • 不会立即报错,而是出现一段时间的沉默(等待 CHECK_INTERVAL)。
    • 随后出现 wait mal response timeout(等待 CONN_FAIL_INTERVAL)。
    • 最终打印 set link status to DISCONNECT
  • 分析重点:
    • 检测耗时: 此时刻的时间戳减去故障注入时间,即为 MAL 链路实际故障认定耗时

场景 2:严重丢包 (tc loss 50%)

  • 原理: TCP 协议栈会尝试重传丢失的包,导致通信耗时增加。
  • dmserver 日志预判:
    • 日志中可能会频繁交替出现 send mal msg failed(发送失败)和 MAL connection recovery(重连成功)。
    • 若丢包导致连续失败时间超过 MAL_CONN_FAIL_INTERVAL,则会打印 DISCONNECT
  • 分析重点: 观察是否存在“链路震荡”(Flapping),即反复断开又重连,这表明参数设置过于敏感,无法容忍丢包。

场景 3:高延迟 (tc delay 3000ms)

  • 原理: 物理链路是通的,但往返时间(RTT = 6s)超过了判定阈值(假设 MAL_CONN_FAIL_INTERVAL = 5s)。
  • dmserver 日志预判:
    • 必然打印 wait mal response timeout,因为 6s > 5s。
    • 紧接着打印 DISCONNECT,判定对方故障。
  • 分析重点: 验证是否发生了“误判”——即明明网络是通的,但因为超时设置不合理导致了强制断开。

3. 测试过程:

以下是针对 A 组参数 的完整测试步骤(B、C 组只需重复此流程,修改参数即可)。


3.1 参数配置与生效

目标: 将集群配置为测试目标状态(A 组:Check=30s, Fail=10s)。

  1. 修改配置文件 (dmmal.ini)

    • 主库备库 机器上,分别编辑 dmmal.ini 文件。

    • 修改内容:

      vi /dm8/data/DAMENG/dmmal.ini
      
      MAL_CHECK_INTERVAL = 30
      MAL_CONN_FAIL_INTERVAL = 10
      
  2. 重启生效

    • 先停监视器,再停守护进程,最后停数据库。
    • systemctl stop DmMonitorServiceGRP1
    • systemctl stop DmWatcherServiceGRP1
    • systemctl stop DmServiceGRP1_RT_01/DmServiceGRP1_RT_02
    • 启动主备库守护进程,而后启动确认监视器:
    • systemctl start DmWatcherServiceGRP1
    • systemctl start DmMonitorServiceGRP1
  3. 确认生效

    • 在监视器执行 show,确保 WSTATUSOPENRSTATVALID
    • 记录当前主库 LSN,作为数据一致性基准。

4.开启监控窗口 (准备 3 个终端) 在执行故障模拟前,先打开日志监控

  • 窗口 1 (备库实例日志): 捕捉 MAL 链路断开

    # 实时监控实例日志,只看 MAL 相关的断开/错误信息
    tail -f /dm8/log/dm_GRP1_RT_02_202512.log | grep -iE "MAL.*disconnect|link.*broken|free link"
    
  • 窗口 2 (备库守护进程日志): 捕捉守护进程认定故障的时间

    tail -f /dm8/log/dm_dmwatcher_GRP1_RT_02_202512.log | grep -iE "WSTATUS|switch|failover|error"
    
  • 窗口 3 (备库操作窗口): 用于执行下述故障模拟命令。

    • 在备库上配置防火墙规则(iptables)或流量控制(tc),拦截来自主库的数据包。这在逻辑上等同于“主库对备库不可见”或“主库断网”。

3.2 场景测试:

3.2.1 完全断网

1.注入故障 (时间锚点)

在 备库 终端执行:

# 打印当前时间作为 T0,随后立即阻断来自主库的包
echo "====== TEST START: T0 = $(date '+%H:%M:%S.%N') ======" >> test_result.txt && \
iptables -I INPUT -s 192.168.79.141 -j DROP
  • 记录: 终端打印的时间 T_0

    • [root@localhost dm8]# cat test_result.txt ====== TEST START: T0 = 16:56:00.482257722 ====== [root@localhost dm8]#

2. 观察与记录 (Observation)

  • **总结:**守护进程先发现对方守护进程(12s)失联,在故障第25s与监视器协调完毕进行状态机制,收到监视器切换命令。show查看,原备库已切换为新主库。

    • 观测对象 耗时 对应参数 结论分析
      守护进程 11s DW_ERROR_TIME (10s) 符合预期。断网后约 11-12秒 认定远程守护进程故障,触发状态切换逻辑。
      数据库实例 18s MAL_CHECK (30s) + MAL_FAIL (10s) 符合预期。耗时介于 10s ~ 40s 之间。说明故障发生在下一次心跳检测周期的前 8秒 左右,导致检测提前触发。
  • 实例日志: 等待并记录出现 [ERROR]: MAL link brokenset link status to DISCONNECT 的时间 T_1

    • 预期耗时: T_1 - T_0 =30s + 10s = 40s (最坏情况)。

    • **实际耗时:**18s

    • [root@localhost ~]# tail -f /dm8/log/dm_GRP1_RT_02_202512.log | grep -iE "MAL.*disconnect|link.*broken|free link" 2025-12-09 16:56:18.472 [WARNING] database P0000052213 T0000000000000052690 [!!!DSC INFO!!!]Site(1) or site(0) interface with IP address no longer running or dsc_ep service on mal_site[192.168.79.141:61141] has broken.It cause network disconnection. #报告断联 2025-12-09 16:56:19.473 [WARNING] database P0000052213 T0000000000000052690 [!!!DSC INFO!!!]Site(1) or site(0) interface with IP address no longer running or dsc_ep service on mal_site[192.168.79.141:61141] has broken.It cause network disconnection.
  • 守护日志: 记录 WSTATUS 变为 ERRORFAILOVER 的时间 T_2

    • 预期耗时: T_2 - T_1=DW_ERROR_TIME

    • **分析:**守护进程之间的 TCP 连接(走 52141 端口)也断了。

      • 间隔(11)s,DW_ERROR_TIME 是默认的 10s。11秒 > 10秒,所以立即判定对方 ERROR。(每秒轮询)
      • 状态更新 (16:56:12):对方(主库)守护进程:ERROR。本地(备库)实例状态:OK。归档状态:INVALID
      • 执行切换 (16:56:25):
        • process_switchover_msg:说明备库守护进程收到了来自监视器(Monitor)的切换指令
        • 时间差: 16:56:25,距离发现故障(12秒)过去了 13秒。在这 13秒 里,守护进程向监视器汇报了故障,监视器确认后,下达了“备库接管(Takeover)”的命令。这是故障自动切换流程的体现。
    • 2025-12-09 16:56:12.341 [INFO] dmwatcher P0000050209 T0000000000000050213 没有收到远程守护进程(GRP1_RT_01)消息,原状态为(OPEN),距上次接收消息时间间隔(11)s, 设置远程守护进程为ERROR状态 2025-12-09 16:56:12.341 [INFO] dmwatcher P0000050209 T0000000000000055151 dw2_group_tcp_recv_thread, receive tcp msg failed, close tcp port, vio:0, mid:-1, from_flag:0, from_name:GRP1_RT_01, dw_closed:1, ip:::ffff:192.168.79.141, port:45092, errno:0, error:Failure occurs in data_recv_inet_once, code(0) len(8128, 0), code:-6007 2025-12-09 16:56:12.392 [INFO] dmwatcher P0000050209 T0000000000000050213 Instance: 守护进程状态(ERROR) 实例状态(OK) 实例名(GRP1_RT_01) 模式(PRIMARY) 实例状态(OPEN) 归档状态(INVALID) POCNT(6) FLSN(47514) CLSN(47514) SLSN(47514) SSLSN(47514) 2025-12-09 16:56:25.261 [INFO] dmwatcher P0000050209 T0000000000000057540 dw2_group_process_switchover_msg, set mid, old mid:256182020, from mid:256182020 2025-12-09 16:56:25.261 [INFO] dmwatcher P0000050209 T0000000000000050213 switch sub_state to sub_stat_start! 2025-12-09 16:56:33.441 [INFO] dmwatcher P0000050209 T0000000000000050213 After monitor execute SWITCHOVER/TAKEOVER/OPEN INSTANCE command, reset all standby instance recover info 2025-12-09 16:56:33.441 [INFO] dmwatcher P0000050209 T0000000000000050213 switch sub_state to sub_stat_start!

4. 恢复环境

iptables -F
  • 验证: 观察监视器,确认集群恢复 Open/Valid 状态,且发生了主备切换

  • **日志:**故障恢复后,备库实例没有打印新日志。守护进程打印新日志如下:

  • 分析:

    • 17:09:13.370:MAL 与守护进程链路恢复,新主库(02)的守护进程首次获取到原主库(01)的状态信息。日志显示 实例名(GRP1_RT_01) 模式(PRIMARY)。这意味着原主库在断网期间并未停机(Halt),且在网络恢复的瞬间,它依然认为自己是主库。
    • 2025-12-09 17:09:16.662状态变更: 原主库(01)的状态被识别为 SUSPEND。说明原主库在断网期间因无法收到备库的归档确认,受限于实时归档(Realtime)机制,被迫挂起所有写操作。
    • 2025-12-09 17:09:34.24417:09:36.288:守护进程检测到“双主”冲突及原主库的 SUSPEND 状态,结合监视器的仲裁,触发了自动**故障恢复(Recovery)**流程。
    2025-12-09 17:09:13.370 [INFO] dmwatcher P0000050209 T0000000000000560008 Instance: 守护进程状态(ERROR) 实例状态(OK) 实例名(GRP1_RT_01) 模式(PRIMARY) 实例状态(OPEN) 归档状态(INVALID) POCNT(6) FLSN(47514) CLSN(47514) SLSN(47514) SSLSN(47514) 2025-12-09 17:09:16.662 [INFO] dmwatcher P0000050209 T0000000000000560008 Instance: 守护进程状态(STARTUP) 实例状态(ERROR) 实例名(GRP1_RT_01) 模式(PRIMARY) 实例状态(SUSPEND) 归档状态(INVALID) POCNT(6) FLSN(47514) CLSN(47514) SLSN(47514) SSLSN(47514) 2025-12-09 17:09:17.724 [INFO] dmwatcher P0000050209 T0000000000000057540 dw2_group_tcp_recv_thread, receive tcp msg failed, close tcp port, vio:8, mid:256182020, from_flag:1, from_name:dmmonitor, dw_closed:0, ip:::ffff:192.168.79.142, port:42198, errno:2019, error:msg too long to 3385379273, code:-6007 2025-12-09 17:09:33.578 [INFO] dmwatcher P0000050209 T0000000000000560008 Instance: 守护进程状态(STARTUP) 实例状态(ERROR) 实例名(GRP1_RT_01) 模式(PRIMARY) 实例状态(SUSPEND) 归档状态(INVALID) POCNT(6) FLSN(47514) CLSN(47514) SLSN(47514) SSLSN(47514) 2025-12-09 17:09:34.244 [INFO] dmwatcher P0000050209 T0000000000000050213 switch sub_state to pre_set_dw_stat! 2025-12-09 17:09:36.288 [INFO] dmwatcher P0000050209 T0000000000000050213 switch sub_state to sub_stat_start!

3.2.2 严重丢包

  • 目的: 验证 MAL 在 50% 丢包下的震荡情况。
  • 操作节点: 备库机器。(自动切换后为192.168.79.141)

1. 注入故障 (时间锚点)

在 备库 终端执行:

# 记录 T0 并设置备库对主库出站流量 50% 丢包 tc qdisc add dev ens33 root handle 1: prio tc qdisc add dev ens33 parent 1:1 handle 10: netem loss 50% date; tc filter add dev ens33 protocol ip parent 1:0 prio 1 u32 match ip dst 192.168.79.142/32 flowid 1:1 #时间点: 17:43:37 CST

2. 观察与记录 (Observation)

  • 实例日志:

    • **50%丢包预期:**观察是否出现 MAL connection recovery。 A 组参数(30s/10s)很宽容,可能不会断开——结果:无错误日志打印

    • 将丢包率提升为90%:17:49:16 CST

      • **链路中断:**30s

      • 2025-12-09 17:49:46.022 [WARNING] database P0000050194 T0000000000000050277 [!!!DSC INFO!!!]Site(0) or site(1) interface with IP address no longer running or dsc_ep service on mal_site[192.168.79.142:61142] has broken.It cause network disconnection. 2025-12-09 17:49:47.023 [WARNING] database P0000050194 T0000000000000050277 [!!!DSC INFO!!!]Site(0) or site(1) interface with IP address no longer running or dsc_ep service on mal_site[192.168.79.142:61142] has broken.It cause network disconnection.
  • 守护日志:

    • **50%丢包预期:**无错误日志打印

    • 将丢包率提升为90%:17:49:16 CST

    • 分析:

      • 频繁的 Socket 物理报错 (-6007)。90% 的丢包率极易导致 TCP 连接在传输数据时发生重传超时或 RST 复位。达梦底层的网络库捕捉到了这些 Socket 异常,直接抛出 -6007 错误。

      • 自动重连:日志在 17:49:33 报错断开后,到了 17:50:03 又再次报错断开。只有连上了才能再次断开,说明发生了典型的**“链路震荡”**。守护进程发现断了 -> 立即重连 -> 90%丢包下侥幸连上了 -> 试图发消息 -> 又丢包报错 -> 又断开。

      • 2025-12-09 17:49:26.452 [INFO] dmwatcher P0000038840 T0000000000000050422 dw2_group_tcp_recv_thread, receive tcp msg failed, close tcp port, vio:6, mid:1664017214, from_flag:1, from_name:dmmonitor, dw_closed:0, ip:::ffff:192.168.79.142, port:39670, errno:0, error:Failure occurs in data_recv_inet_once, code(0) len(8128, 0), code:-6007 2025-12-09 17:49:28.174 [INFO] dmwatcher P0000038840 T0000000000000118162 dw2_group_tcp_recv_thread, receive tcp msg failed, close tcp port, vio:7, mid:256182020, from_flag:1, from_name:dmmonitor, dw_closed:0, ip:::ffff:192.168.79.142, port:56842, errno:0, error:Failure occurs in data_recv_inet_once, code(0) len(8128, 0), code:-6007 2025-12-09 17:49:33.234 [INFO] dmwatcher P0000038840 T0000000000000113457 dw2_group_tcp_recv_thread, receive tcp msg failed, close tcp port, vio:4, mid:-1, from_flag:0, from_name:GRP1_RT_02, dw_closed:0, ip:192.168.79.142, port:52142, errno:104, error:Failure occurs in data_recv_inet_once, code(104) len(8128, -1), code:-6007 2025-12-09 17:49:33.634 [INFO] dmwatcher P0000038840 T0000000000000038844 没有收到远程守护进程(GRP1_RT_02)消息,原状态为(OPEN),距上次接收消息时间间隔(9)s, 设置远程守护进程为ERROR状态 2025-12-09 17:49:33.634 [INFO] dmwatcher P0000038840 T0000000000000038844 Instance: 守护进程状态(ERROR) 实例状态(OK) 实例名(GRP1_RT_02) 模式(PRIMARY) 实例状态(OPEN) 归档状态(INVALID) POCNT(7) FLSN(47568) CLSN(47568) SLSN(47568) SSLSN(47568) 2025-12-09 17:49:39.237 [ERROR] dmwatcher P0000038840 T0000000000000038846 Can't connect to DM server on '192.168.79.142' port(52142) errno(115) 2025-12-09 17:49:46.798 [INFO] dmwatcher P0000038840 T0000000000000325587 Instance: 守护进程状态(ERROR) 实例状态(OK) 实例名(GRP1_RT_02) 模式(PRIMARY) 实例状态(OPEN) 归档状态(INVALID) POCNT(7) FLSN(47568) CLSN(47568) SLSN(47568) SSLSN(47568) 2025-12-09 17:49:58.180 [INFO] dmwatcher P0000038840 T0000000000000323945 dw2_group_tcp_recv_thread, receive tcp msg failed, close tcp port, vio:6, mid:256182020, from_flag:1, from_name:dmmonitor, dw_closed:0, ip:::ffff:192.168.79.142, port:55592, errno:0, error:Failure occurs in data_recv_inet_once, code(0) len(8128, 0), code:-6007 2025-12-09 17:50:03.253 [INFO] dmwatcher P0000038840 T0000000000000325587 dw2_group_tcp_recv_thread, receive tcp msg failed, close tcp port, vio:4, mid:-1, from_flag:0, from_name:GRP1_RT_02, dw_closed:0, ip:192.168.79.142, port:52142, errno:0, error:Failure occurs in data_recv_inet_once, code(0) len(8128, 0), code:-6007 2025-12-09 17:50:03.654 [INFO] dmwatcher P0000038840 T0000000000000038844 没有收到远程守护进程(GRP1_RT_02)消息,原状态为(OPEN),距上次接收消息时间间隔(1)s, 设置远程守护进程为ERROR状态

4. 恢复环境

tc qdisc del dev ens33 root
  • 验证: 日志不再报错,集群状态稳定。

3.3 数据总结与对比分析

本节汇总了 A、B、C 三组参数在不同故障场景下的表现。数据取自每组三次测试的平均值,以消除单次测试的随机误差。

3.3.1 物理断网检测

测试场景:完全断网

统计口径:

  • 实例认定时间:从故障注入 T_0到实例日志打印 DISCONNECT/BROKEN T_1 的平均耗时。
  • 守护进程认定时间:从故障注入 T_0到守护进程日志打印 ERROR/FAILOVER T_2的平均耗时。
测试组别 参数配置 (Check / Fail) 实例认定耗时 (Avg) 守护进程认定耗时 (Avg) 理论预期 (实例/守护) 结论
A组 (宽松) 30s / 10s 25s 11s 40s / 10s 错误认定时间较长
B组 (标准) 10s / 10s 13.5s 11s 10s / 10s 表现均衡
C组 (激进) 2s / 2s 3s 10s 4s / 10s 出现“守护进程瓶颈”。实例在 3s 内认定链路断开,但守护进程仍需等待默认的 10s才做出决定

:守护进程的故障认定时间主要受 dmwatcher.ini 中的 DW_ERROR_TIME (默认10s) 控制,理论上各组应基本一致,主要观察实例层面的差异。


3.3.2 丢包耐受测试

本测试验证不同参数组在网络质量恶化时的临界崩溃点。

测试策略

  1. 所有组优先测试 50% 丢包
  2. 若 50% 表现稳定(无报错、无链路震荡),则进阶测试 90% 丢包
  3. 若 50% 已出现异常(频繁断连、震荡),则不再测试更高丢包率,标记为“无法耐受”。
测试组别 场景 A:50% 丢包表现 场景 B: 耐受度
A组 (30/10) 稳定 (无错误日志) 90% 丢包表现:13s后出现震荡,30s后出现链路中断 (日志频繁交替报错与重连,Socket -6007) 极强,仅在极端丢包下异常
B组 (10/10) 稳定 (无错误日志) 70% 丢包表现:21s后出现震荡 (日志频繁交替报错与重连,Socket -6007) 中等
C组 (2/2) 50% 丢包表现:5s后出现链路中断,10s出现震荡 跳过 较低,对网络质量要求极高,不具备抗抖动能力。

3.3.3 综合结论

基于上述定量与定性测试数据,得出以下关键结论:

1. 参数敏感度与“木桶效应”

  • 时效性分析:MAL_CHECK_INTERVALMAL_CONN_FAIL_INTERVAL 的缩减确实能显著降低数据库实例(Instance)发现故障的时间(从 A 组的 25s 降至 C 组的 3s)。
  • 木桶效应:C 组测试揭示,即使 MAL 链路在 3s 内断开,整体集群的故障切换仍需等待守护进程的 DW_ERROR_TIME (10s)。因此,单纯激进地调整 dmmal.ini 而不配套调整 dmwatcher.ini,无法有效降低 RTO,反而徒增网络抖动导致的误判风险。

2. 丢包耐受度阈值

  • A 组 (30s/10s) 显示了极强的鲁棒性,在 50% 丢包率下依然保持连接稳定,仅在 90% 这种极端不可用网络下才会断开。
  • C 组 (2s/2s) 极其脆弱,50% 的丢包即导致链路在 5s 内中断。证明激进配置在广域网或网络质量一般的局域网中极易引发“脑裂”或频繁切换。

3. 生产环境配置建议

  • 稳健型(推荐 - 对应 A/B 组之间)
    • 建议配置:MAL_CHECK_INTERVAL=10, MAL_CONN_FAIL_INTERVAL=10
    • 适用场景:大多数生产环境、云环境或跨机房部署。实测数据显示其能耐受 50% 丢包,且故障发现时间约 13.5s,在稳定性与响应速度间取得了最佳平衡。
  • 敏捷型(对应 C 组优化版)
    • 建议配置:MAL_CHECK=2, MAL_FAIL=2且必须同步调整 dmwatcher.ini 中的 DW_ERROR_TIME 为 3~5s。
    • 适用场景:仅限于全光纤直连、网络质量极高且对 RTO 有秒级要求的核心金融交易系统。必须警惕网络抖动风险。

4. 主动检测机制

测试目的:验证当节点自身网络完全隔离(既连不上伙伴,也连不上网关)时,MAL_CHECK_IP 机制能否触发实例主动停机 (HALT),从而防止脑裂。

4.1 前置配置 (需重启生效)

修改主备库dmmal.ini,在原有配置基础上增加主动检测参数:

  • MAL_CHECK_IP = 192.168.79.1 (假设这是你的网关IP,或者一个局域网内始终在线的第三方IP)
  • MAL_CHECK_TIMEOUT = 5000 (检测超时时间,单位ms,建议设大一点以免误判,文档单位是ms,请注意确认,通常配置为 2000-5000)

注意:根据文档,MAL_CHECK_TIMEOUT 缺省为 0,表示不检测。必须配置有效值配合 MAL_CHECK_IP 使用。

Linux前置环境准备:

  • 机制: 当配置了 MAL_CHECK_IP 后,数据库进程(dmserver)会尝试通过 ICMP 协议(Ping) 去探测目标 IP。

  • Linux 限制: 在 Linux 中,发送 ICMP 包(Ping)需要创建 RAW Socket。出于安全考虑,默认情况下,只有 root 用户 才有权限创建 RAW Socket。

  • 问题: 达梦数据库是由普通用户(通常是 dmdba)启动的,因此操作系统内核一般会拒绝了 dmserver 创建 RAW Socket 的请求。

  • 解决方案:

    • 赋予 dmserver 网络特权

    • su - root
      setcap cap_net_raw+ep /dm8/bin/dmserver
      

4.2 故障模拟:自身孤岛化

故障模拟机器:备库(192.168.79.141)

这次不仅要切断到达主库的路,还要切断到达 MAL_CHECK_IP (网关) 的路,模拟“拔网线”的最真实效果。

1.监控命令 (在备库执行)

# 实例日志:重点捕捉 HALT 关键字。
tail -f /dm8/log/dm_GRP1_RT_01_202512.log | grep -iE "HALT|check ip|failed"

# 守护进程日志:捕捉重启命令、状态检测和重启限制告警
tail -f /dm8/log/dm_dmwatcher_GRP1_RT_01_202512.log | grep  -iE "Start instance|Startup command|Restart count|limit|mode change"

2. 注入故障 (双重阻断)备库 (.141) 终端执行:

# 记录时间 T0
echo "=== TEST START: T0 = $(date '+%H:%M:%S.%N') ===" >> test_result.txt

# 1. 切断与主库 (.142) 的联系
iptables -I INPUT -s 192.168.79.142 -j DROP

# 2. 切断与网关 (.1) 的联系 (模拟自身网卡彻底挂掉)。Ping需要 INPUT 和 OUTPUT 都通
# 只丢弃来自网关的 ICMP (Ping) 包,但不影响 SSH (TCP)
iptables -I INPUT -s 192.168.79.1 -p icmp -j DROP

4.3 日志分析

  1. 观察 dmserver.log

    • 预期会出现类似:Mal check ip [...] failed, instance will halt 的严重错误信息。

    • 随后实例会执行 shutdown 流程或直接退出。

    • 如下:

    • 025-12-09 23:54:06.318 [INFO] database P0002312265 T0000000000002312978  mal_site_link_check->mal_recv_force_wait failed, code:-6010!, wait_time:2
      2025-12-09 23:54:07.319 [INFO] database P0002312265 T0000000000002312978  mal_site_link_check->mal_recv_force_wait failed, code:-6010!, wait_time:1
      2025-12-09 23:54:07.319 [INFO] database P0002312265 T0000000000002312978  mal_site_link_check from mal_site(0) to mal_site(1) failed, call mal_site_port_close!
      2025-12-09 23:54:07.319 [WARNING] database P0002312265 T0000000000002312953  mal_site_letter_recv code=-6007, errno=0, site(0) recv from site(1) failed, socket handle = 0
      2025-12-09 23:54:07.319 [WARNING] database P0002312265 T0000000000002312953  site(0) data_link mal_site_letter_recv from site(1) failed, socket handle = 0, mal sys status is 0, try to get mal_port again
      2025-12-09 23:54:07.320 [WARNING] database P0002312265 T0000000000002312952  mal_site_letter_recv code=-6007, errno=0, site(0) recv from site(1) failed, socket handle = 0
      2025-12-09 23:54:07.320 [WARNING] database P0002312265 T0000000000002312952  site(0) ctl_link mal_site_letter_recv from site(1) failed, socket handle = 0, mal sys status is 0, try to get mal_port again
      2025-12-09 23:54:15.427 [FATAL] database P0002312265 T0000000000002312978  code = -8708, dm_sys_halt now!!!
      2025-12-09 23:54:15.428 [WARNING] database P0002312265 T0000000000002313612  utsk_dw_tcp_recv_thread, dmserver receive TCP message from dmwatcher(seqno: 0, name: )failed, close tcp port, code: -6007, errno: 0
      2025-12-09 23:54:15.434 [WARNING] database P0002312265 T0000000000002312949  mal_site_letter_recv code=-6007, errno=0, site(0) recv from site(0) failed, socket handle = 0
      2025-12-09 23:54:15.434 [WARNING] database P0002312265 T0000000000002312949  site(0) data_link mal_site_letter_recv from site(0) failed, socket handle = 0, mal sys status is 0, try to get mal_port again
      2025-12-09 23:54:15.434 [FATAL] database P0002312265 T0000000000002312949  MAL link self lost, halt now!!
      
  2. 观察 dmmonitor

    • 备库状态会变为 SHUTDOWNERROR,且无法再连接。

4.4 恢复环境

由于实例已经 HALT(挂掉),恢复步骤如下:

  1. 恢复网络 iptables -F

  2. 重启数据库:自动切换模式下不用手动重启

    • [monitor]         2025-12-09 23:56:19: 守护进程(GRP1_RT_01)状态切换 [STARTUP-->UNIFY EP]
                        WTIME                WSTATUS        INST_OK   INAME            ISTATUS     IMODE     RSTAT    N_OPEN   FLSN            CLSN            
                        2025-12-09 23:56:19  UNIFY EP       OK        GRP1_RT_01       MOUNT       STANDBY   VALID    12       47855           47855           
      
      [monitor]         2025-12-09 23:56:19: 守护进程(GRP1_RT_01)状态切换 [UNIFY EP-->STARTUP]
                        WTIME                WSTATUS        INST_OK   INAME            ISTATUS     IMODE     RSTAT    N_OPEN   FLSN            CLSN            
                        2025-12-09 23:56:19  STARTUP        OK        GRP1_RT_01       OPEN        STANDBY   VALID    12       47855           47855           
      
      [monitor]         2025-12-09 23:56:19: 守护进程(GRP1_RT_01)状态切换 [STARTUP-->OPEN]
                        WTIME                WSTATUS        INST_OK   INAME            ISTATUS     IMODE     RSTAT    N_OPEN   FLSN            CLSN            
                        2025-12-09 23:56:19  OPEN           OK        GRP1_RT_01       OPEN        STANDBY   VALID    12       47855           47855           
      
  3. 检查集群状态:确保备库重新加入并恢复 OPEN/VALID 状态。

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服