达梦DM8主备切换故障演练:从环境搭建到自动切换与回切实践

发布时间:2026/9/18 0:34:10
达梦DM8主备切换故障演练:从环境搭建到自动切换与回切实践 上个月凌晨两点值班电话把我从床上拽起来生产环境的DM主库进程没了应用连接池瞬间被打满报错短信刷了几百条。我打开监视器一看备库状态还是“Normal”数据也没断但就是没人敢点那个“切换”按钮——因为之前从没在真实环境里验证过这套主备到底能不能自动顶上。等我们人工走完确认、切换、拉起应用的流程时间已经过去了二十多分钟业务投诉早就飞过来了。那晚之后我做了个决定不能等故障真来了才练必须在测试环境里把DM数据库的实时主备故障模拟成固定科目反复打、反复看切换过程到底靠不靠谱。这篇文章就是我从环境搭建、故障注入、切换观察到数据校验的完整记录。我用的是DM8一主一备一监视器的经典部署把主库进程杀掉、断网隔离、整机宕机三类典型故障都模拟了一遍还做了原主库回归后的回切测试。如果你也在维护达梦数据库或者正准备给核心系统做高可用验证这套演练思路可以直接抄作业。先说清楚不同版本、不同操作系统环境下的命令和参数名可能有细微差异本文以DM8为基准你操作前最好对着自己环境的版本手册核对一下。另外文中的IP、目录、实例名都是测试环境的示例别直接往生产上套。1. 先把主备切换的“决策机制”弄明白否则演练就是瞎按做故障模拟之前我建议你先花点时间把DM数据守护系统的角色关系搞清楚。很多同学把主备搭起来、看到数据能同步就觉得万事大吉真到切换的时候才发现整个决策链路上有几个关键节点任何一个配置不对自动切换都起不来。1.1 主库、备库、守护进程、监视器这四类角色谁说了算一套正经的DM实时主备环境里至少有四类角色在协同工作主库Primary对外提供读写服务的数据库实例业务请求都打在它身上。备库Standby实时接收主库的Redo日志并持续应用正常情况下只读不对外提供写入。守护进程dmwatcher跑在主备库所在机器上的常驻进程负责监控本机实例的健康状态并向监视器上报心跳。监视器dmmonitor整个集群的“决策中枢”收集所有守护进程上报的状态判断是否有实例故障并在确认条件满足后自动发起切换。打个比方dmserver是被守护的对象相当于运动员dmwatcher是队医跟着运动员实时摸脉搏dmmonitor是总教练看到运动员倒地了喊替补上场。这里面最容易被人忽略的角色是守护进程很多人只在主备库机器上装了dmserver没装dmwatcher结果监视器根本收不到状态自动切换自然无从谈起。1.2 监视器靠什么判断“主库真的挂了”达梦的自动切换不是主库一没心跳就立刻切而是要通过多重判定来避免误判。整个判断链路主要落在三个参数上MAL_CONN_FAIL_INTERVALMAL系统连接故障判定时间默认通常是10秒左右。如果超过这个时间还无法和某个节点建立MAL连接就认为连接异常。MAL_INST_FAIL_INTERVALMAL实例故障判定时间默认15秒左右。连接异常持续累计达到这个阈值才判定对应实例不可用。DW_ERROR_TIME守护进程的错误容忍时间常见配置为30秒。守护进程发现本机实例异常后会持续观察这么久如果还不能恢复才向监视器上报故障。这三个时间叠加起来基本决定了故障切换的“感知速度”。比如默认配置下从主库真挂到监视器发起切换往往要三十秒到一分钟量级。如果你的业务对RTO要求特别高这几项就得根据实际硬件能力和业务容忍度谨慎调小但也不能调得太激进否则网络抖动就可能触发误切换。这里还牵扯到一个容易被忽视的点监视器分为确认监视器和普通监视器。确认监视器是集群里唯一有权发起自动切换的节点它一挂集群就失去自动决策能力所以生产环境至少要有两个监视器或者把确认监视器单独放在一台与主备库网络都连通、但又不承担数据库业务的机器上。我后面的演练就是按“确认监视器独立部署”的架构来做的。1.3 一个很关键的认知进程挂、断网、宕机是三种完全不同的故障为什么我要把故障分门别类去模拟因为它们的表现形态完全不同主库进程崩溃dmserver没了但操作系统还活着网卡还通。这时主库机器上的dmwatcher能立刻发现实例异常监视器也还能和守护进程通信整个链路的信息传递是畅通的。主库网络被隔离主库其实还活着dmserver还在正常服务但是和备库、监视器之间的链路断了。这时候主库侧和备库侧会形成“信息孤岛”最容易出现误判或者脑裂风险。整机宕机进程和网络同时消失故障最彻底但也最“干净”反而最不容易出现双主问题。不同故障形态对切换策略的要求完全不同这也是后面所有演练动作的设计基础。2. 演练前环境搭建最小可用的DM一主一备一监视器集群这一节我尽量把搭建过程压缩着讲重点放在影响后续故障模拟的配置项上。如果你已经有一套能正常同步的主备环境可以跳过直接看第3章。2.1 环境规划三台机器、一张端口规划表我用的测试环境是三台Linux虚拟机网络互通时间通过chrony做了同步。在实际操作中监视器机器可以复用备库机器但为了模拟“管理节点独立存活”的真实场景我还是建议单独拆一台出来。角色实例名IP数据库端口MAL端口守护端口说明主库GRP1_PRIMARY192.168.56.101523652695270对外提供读写备库GRP1_STANDBY192.168.56.102523652695270实时同步监视器-192.168.56.103---只装dmmonitor如果只是临时做演练主备两台机器也够用。但我要强调一点监视器不要和主库部署在同一台机器上否则主库宕机时你的“决策中枢”也跟着没了自动切换一样起不来。这是我最早踩过的一个坑后面会细说。2.2 主库初始化与核心配置如果你是从零开始先完成DM数据库安装这篇文章不展开安装步骤然后用dminit初始化一个实例dminit PATH/dm/data PAGE_SIZE32 LOG_SIZE2048 CHARSET1 DB_NAMEDMDB INSTANCE_NAMEGRP1_PRIMARY PORT_NUM5236接下来要做三件关键的事第一修改dm.ini打开MAL和归档开关MAL_INI 1 ARCH_INI 1 ALTER_MODE_STATUS 0 ENABLE_OFFLINE_TS 2ALTER_MODE_STATUS0的意思是不允许通过命令随意修改数据库模式避免误操作把主备搞乱。正式部署时这个值一定要设成0演练结束时我也建议保持这个配置回切。第二配置dmarch.ini同时做本地归档和实时归档[ARCHIVE_LOCAL1] ARCH_TYPE LOCAL ARCH_DEST /dm/arch ARCH_FILE_SIZE 2048 ARCH_SPACE_LIMIT 10240 ARCH_FLUSH_TIMING 1 [ARCHIVE_REALTIME1] ARCH_TYPE REALTIME ARCH_DEST GRP1_STANDBY注意ARCH_DEST GRP1_STANDBY这里填的是备库在dmmal.ini里定义的MAL实例名不是随便写的。很多新手在这里填成备库IP或者备库实例名导致实时归档始终起不来。第三配置dmmal.ini主备库的内容要完全一致MAL_CHECK_INTERVAL 5 MAL_CONN_FAIL_INTERVAL 10 MAL_INST_FAIL_INTERVAL 15 MAL_BUF_SIZE 100 MAL_BUF_MAX_SIZE 200 MAL_LOGIN_TIMEOUT 15 [MAL_INST1] MAL_INST_NAME GRP1_PRIMARY MAL_HOST 192.168.56.101 MAL_PORT 5269 MAL_INST_HOST 192.168.56.101 MAL_INST_PORT 5236 MAL_DW_PORT 5270 [MAL_INST2] MAL_INST_NAME GRP1_STANDBY MAL_HOST 192.168.56.102 MAL_PORT 5269 MAL_INST_HOST 192.168.56.102 MAL_INST_PORT 5236 MAL_DW_PORT 52702.3 备库克隆备份、RESTORE、RECOVER三步走主库配置好后要做一次全量备份然后拿这份备份去搭建备库。我是直接在disql里执行的backup database full backupset /dm/backup/full_bk;把主库的dm.ini、dmmal.ini、dmarch.ini以及这份备份集copy到备库机器后用dmrman执行恢复dmrman CTLSTMTRESTORE DATABASE /dm/data/DMDB/dm.ini FROM BACKUPSET /dm/backup/full_bk dmrman CTLSTMTRECOVER DATABASE /dm/data/DMDB/dm.ini UPDATE DB_MAGIC这段命令里有个特别容易漏的细节备库的dm.ini里INSTANCE_NAME一定要改成GRP1_STANDBY同时ALTER_MODE_STATUS也要设成0。改完之后主备库在mount状态下分别执行模式设置-- 主库执行 ALTER DATABASE PRIMARY; -- 备库执行 ALTER DATABASE STANDBY;然后配置dmwatcher.ini主备库一致INST_INI路径各自指向本机再通过DM提供的脚本注册服务并启动DW_MODE AUTO DW_ERROR_TIME 30 INST_RECOVER_TIME 60 INST_ERROR_TIME 30 INST_OGUID 453331 INST_INI /dm/data/DMDB/dm.ini INST_AUTO_RESTART 1 INST_STARTUP_CMD /dm/bin/dmserver RLOG_APPLY_THRESHOLD 0启动顺序有讲究先主库再备库然后主备库的守护进程最后启动监视器。全部起来后在监视器交互窗口执行show health看到主备状态都是“Normal”说明集群已经就绪。这时候我习惯导入一份测试用的dmp数据到库里面备库上应声可见——顺便说一句达梦导入dmp文件用dimp工具就能完成命令路径通常是/dm/bin/dimp演练前备好一份有代表性的数据后面做数据一致性校验会方便很多。3. 演练一直接杀掉主库dmserver进程观察自动切换能否“无人驾驶”这个场景模拟的是最典型的故障进程崩溃操作系统还活着。这是成本最低、最容易复现的演练方式也是我建议所有人第一次做故障模拟时先打的科目。3.1 注入故障前先把“现场证据”记录下来任何一场正经的故障演练都不能上来就杀进程。先把当时的集群快照记录清楚后面做数据比对才有依据。我在disql里执行的是这几个查询-- 查看主库当前日志信息 SELECT INSTANCE_NAME, STATUS$, MODE$ FROM V$INSTANCE; -- 查看主备库LSN位置 SELECT FILE_LSN, CUR_LSN FROM V$RLOG; -- 查看归档同步情况 SELECT ARCH_DEST, ARCH_LSN, ARCH_STATE FROM V$ARCH_STATUS;同时记录下监视器窗口当前的show health输出保持两个终端的日志滚动。接下来才真正注入故障# 在主库机器上执行模拟主库进程被外部强制杀掉 kill -9 $(pidof dmserver)这里我刻意用kill -9而不是systemctl stop目的是模拟最极端的突发崩溃。kill -9之后dmserver没有机会做任何优雅退出动作Redo日志就停留在崩溃那一刻这对备库的日志追平能力是一个真实的考验。3.2 故障注入后的时间线从kill到业务恢复kill执行后我紧盯着监视器窗口和业务模拟端的日志。整个自动切换过程大概是这个节奏时间点事件0秒执行kill -9主库dmserver进程消失约8秒备库侧守护进程检测到与主库MAL通信异常约18秒监视器日志出现实例故障判定信息约35秒确认监视器判定主库不可用开始自动切换约40秒原备库被提升为新主库开始对外服务这个时间线是在我上面的参数配置下得到的。我把业务模拟端的Java应用连接串指向守护环境的VIP切换完成后新连接自动落到新主库上应用侧无感知只有少数几个正在执行的长事务被断开重连。切换完成后在监视器窗口执行show database命令可以看到原备库的角色已经变成了Primary原主库显示为故障状态。这个过程中最让我紧张的是日志追平环节——主库崩溃前可能还有一部分Redo日志没来得及传给备库备库要接管成为新主库必须先从本地归档把日志补齐到至少和主库崩溃点一致的位置。好在实时归档模式下达梦基本能做到“零丢失”这也是实时主备和异步主备最大的区别。3.3 切换逻辑复盘为什么备库要等“日志追平”才肯上场自动切换不是“备库投票通过就立刻顶上”而是有一个重要的前提条件备库必须确认自己拿到了主库崩溃前的全部日志。如果备库还差一段日志就强行接管那部分数据就丢了。那么怎么判断“追平”了答案是看归档序列号和LSN。备库的V$ARCH_STATUS里ARCH_DEST对应主库的归档源ARCH_LSN如果能追到和主库崩溃时一致的LSN说明已经具备接管条件。RLOG_APPLY_THRESHOLD用来控制备库与主库日志差异的容忍阈值默认0表示不允许有差异必须严格追平才能接管。如果你的业务可以容忍少量丢失以换取更快的切换速度这个参数可以适当调大但绝大多数核心系统不建议调因为“丢数据”这个代价远比“多等十几秒”严重。这个环节还暴露了一个容易被忽略的问题备库机器磁盘IO能力如果太差日志应用速度跟不上主库的写入速度平时看不出问题一旦发生故障切换备库要花很长时间才能追平日志RTO就被无限拉长了。所以做实时主备备库的硬件规格不能比主库低太多尤其是磁盘和网络这是我从几次演练里总结出来的硬道理。4. 演练二模拟网络隔离与整机宕机把“脑裂”和“回切”一次讲透主库进程被杀只是故障模拟的入门科目。真正让人头疼的是网络层面的隔离因为这种故障下主库还活着它并不知道自己已经被“孤立”了。4.1 用iptables制造“主库单边失联”看看监视器会不会出错我当时的操作是在主库机器上模拟“入站连接全部丢弃”相当于把主库的网络对外一刀切# 在主库机器上执行把入站ICMP和数据库相关端口全部丢弃 iptables -A INPUT -s 192.168.56.102 -j DROP iptables -A INPUT -s 192.168.56.103 -j DROP执行完这条命令后主库的dmserver还在跑本地连接还能正常查询但对备库和监视器来说主库已经“失联”了。这个场景比kill -9更危险因为主库侧并没有感知到故障它还在继续接收业务写入。在我这套带独立确认监视器的架构里监视器在持续一段时间收不到主库守护进程的心跳后会判定主库故障然后和备库侧的守护进程完成确认把备库提升为新主库。整个切换过程大约在一分钟以内完成原主库由于网络被隔离并不知道自己已经被“下课”但它也接不到业务流量了所以并没有出现两个主库同时对外提供服务的情况。反过来如果监视器本身没有独立部署或者MAL判定时间配置得过短网络抖动就可能触发“脑裂”——两边都认为自己才是主库两边都在接受写入。这种事故的恢复成本非常高轻则数据不一致重则整个集群都要重建。所以关于脑裂的防范我的建议是三句话确认监视器务必独立部署网络参数的调整要小步慢跑不要一次调得过于激进故障判定参数需要结合真实网络环境做记录和复盘而不是拍脑袋定一个值。4.2 整机宕机模拟直接把虚拟机断电断电的模拟更简单直接在虚拟化平台上对主库执行强制关机或者如果条件允许直接poweroff。这种故障形态下主库进程、守护进程、网络全部消失信息孤岛效应反而不存在监视器和备库很容易就达成一致完成切换。我用这个方式验证的是另一个问题原主库重新开机后能不能自己乖乖回到集群里。整机宕机恢复后原主库的dmwatcher会自动拉起dmserver它会发现集群里已经有了新的主库然后自动进入“备库重建”的流程。这里有个细节如果你用的版本支持自动重建原主库会自动从新主库拉取基线备份和归档日志重建自己的数据文件如果不支持就需要手工把原主库重新RESTORE一遍把它变成新主库的备库。我在演练中发现自动重建虽然方便但耗时取决于数据量和网络带宽。数据量大的时候建议在业务低峰期操作同时监控新主库的归档空间防止被重建请求把磁盘打满。4.3 回切让原主库重新拿回“话语权”演练的最后一环是把集群状态恢复到初始状态也就是让原主库重新变回主库。这个操作叫回切也常被称为switchover。回切的前提是原主库已经作为备库成功追平了新主库的日志并且集群整体处于健康状态。在监视器交互窗口执行切换命令switchover GRP1_PRIMARY;执行完这条命令后监视器会协调两边原主库先从备库角色切换为主库原备库也就是当前主库再从主库切换为备库。整个过程是平滑的两端的数据会在切换前做最后一次日志追平然后完成角色互换。回切之后务必再做一遍数据校验新主库上跑的测试表数据量、主备两边的归档序列、关键表的checksum是否一致。我校验的方式是-- 在主备分别执行对比结果 SELECT COUNT(*), SUM(CAST(MD5(COL_A||COL_B) AS VARBINARY)) FROM TEST_TABLE;两边结果完全一致才说明整个故障模拟和回切流程没有丢数。5. 演练中的翻车记录与参数调整心得再完美的演练方案实操起来也免不了踩坑。这一节我专门记下我重复遇到过的几个典型问题每一个都是真金白银换来的教训。5.1 我记得最深的五个坑坑一备库忘记改INSTANCE_NAME。复制主库配置文件到备库时dm.ini里还写着GRP1_PRIMARY启动守护进程时两边实例名重复监视器里看到两个“主库”日志刷屏。这个错误很低级但特别容易在熬夜操作时犯。建议备库的配置文件在copy完成后第一步就改INSTANCE_NAME不要等后面启动失败了才想起来。坑二系统时间没同步。DM主备同步对时间很敏感两台机器时间偏差超过几十毫秒同步延迟的监控曲线就会异常。第一次演练时我用了虚拟机默认时间主备时间差了整整两分钟Redo日志传输永久落后看得我差点排查到天亮。现在我把chrony同步做成了环境初始化的固定步骤。坑三归档目录空间规划不足。故障演练和自动重建需要消耗大量归档空间如果ARCH_SPACE_LIMIT设置过小备库在追日志时直接报“归档空间不足”被迫中断恢复。这个参数要按照“能容纳至少两轮全量备份体积的归档日志”来规划不要撑得刚刚好。坑四监视器放到了主库机器上。第一次做架构设计时图省事把确认监视器装在了主库机器上觉得“反正平时不用它”。结果模拟主库宕机时监视器也跟着不可用自动切换根本没触发被我手动用takeover命令接管才完成。这个教训让我彻底改了架构——监视器必须独立。坑五切换后没有及时更新应用连接串。用的是VIP才能规避这个坑。如果应用连接串直接指向实例IP主备切换后应用怎么都连不上库。生产环境建议用守护进程的VIP或者服务名来做连接入口而不是裸IP。5.2 把故障演练变成定期机制而不是一次性的“表演”一次演练成功不等于系统永远可靠。我现在的做法是每季度做一轮完整的主备故障模拟并且每次都换一种故障注入方式第一季度杀进程第二季度断网第三季度整机强制关机第四季度做磁盘满、归档中断这类“慢病型”故障。每一次演练都要形成记录包括故障注入时间、切换完成时间、数据校验结果、出现的问题和处理动作。我还做了一张简版检查清单每次演练前逐项打勾检查项操作预期主备状态show health双Normal归档连通性V$ARCH_STATUSARCH_STATE正常时间同步chronyc tracking偏差小于10ms磁盘空间df -h剩余空间充足应用连接入口确认VIP/服务名指向守护环境数据基线记录LSN/归档序列事后可比对这套机制运行了三个季度之后我再也没在深夜值班电话里手忙脚乱过。不是因为它能预测故障而是因为每一次切换动作都已经被反复验证过信息是确定的预案是走通的。最后再分享一个小技巧演练过程中监视器窗口的日志我都会原样保存到文件里命名带上日期和故障类型。一段时间之后再翻能清楚看到每次优化参数后切换时间的变化曲线这对调优来说价值极大。如果你刚准备做DM主备故障演练不妨也从这个习惯开始。