1. 为什么单机DM8扛不住生产环境:主备集群解决的三个核心问题
先说说我自己的经历。前几年做国产化替代项目,客户核心业务库从国外数据库迁到达梦DM8,最初部署就是一台物理机单机。单机跑了一段时间,开发测试都挺顺利,真正快上线的时候,客户问了一句:“这台机器如果凌晨三点挂了,我们的业务几点能恢复?”我一下被问住了。因为单机环境下,最典型的恢复路径是:找一台备用机重新装数据库、导入备份、追归档日志,运气好恢复时间按小时算,运气不好备份和归档刚好有缺口,数据直接倒不回去。这种可用性水平,放在交易类系统里是完全不可接受的。
所以“DM8主备集群”这个需求,本质上不是一道数据库命令题,而是一道高可用工程题。它要解决三个问题:
- 故障切换问题:主库宕机后,备库能否在几十秒内接管业务,而不是让业务等人工干预。
- 数据丢失问题:主备之间日志实时同步,主库故障瞬间丢失的数据尽可能趋近于零,也就是RPO接近0。
- 日常维护问题:需要做硬件更换、系统补丁、数据库升级时,能不能先在备库上操作,再平滑切换,做到业务无感。
DM8主备集群的底层机制,简单说就是:主库不停产生Redo日志,通过网络传递给备库,备库自动重演日志;达梦的守护进程(DM Watcher)专门负责监控角色和状态,一旦发现主库失联,备库守护进程会在配置的时间窗口内完成角色切换,把备库提升为新主库继续服务。这个思路和Oracle DataGuard类似,但具体实现和配置文件完全是达梦自己的体系,不能想当然照搬Oracle命令。
那为什么不一步到位上DSC共享存储集群?这取决于预算和场景。DSC需要共享存储,比如SAN磁盘阵列或者裸设备,由多个实例同时挂载同一套数据文件,节点故障后另一个节点直接接管,RTO可以做到秒级甚至更快。但共享存储的采购成本、网络要求、运维门槛都更高。主备集群只需要两台独立服务器加普通网络,数据通过日志同步来保持一致性,不需要额外存储设备,对大多数中小规模生产系统来说,主备集群已经是性价比最高的高可用形态。
我通常会建议用户这样选型:如果系统要求RPO为0、RTO在秒钟级别,并且预算允许上共享存储,选DSC;如果业务可以接受最多丢失一条日志的时间、切换时间在几十秒内,主备集群足够;如果是边缘节点或者纯查询报表库,甚至可以做异步级的主备,进一步降低网络和同步压力。
2. 搭建前的规划比命令更重要:网络、端口、目录、用户这些细节
说实话,真正把主备集群搭崩掉的人,大多不是死在配置文件语法上,而是死在环境准备上。我自己第一次搭的时候,两台机器的主机名、时间、用户权限乱七八糟,排错排了一整天,最后发现是备库服务器时间比主库快了五分钟,守护进程一直认为日志序号错乱。所以先别急着敲命令,把以下准备工作一条条过掉。
2.1 操作系统与用户规划
DM8支持主流Linux发行版,常见的有麒麟V10、统信UOS、CentOS 7 x86_64这些。无论用什么系统,建议都用独立的dmdba用户来安装和运行数据库,不要用root直接跑数据库进程。原因很简单:数据库进程被攻破或误操作时,进程权限越小,破坏范围越小;另外达梦很多初始化工具直接用root运行会存在文件属主问题,导致后续服务起不来。
创建用户的典型操作:
groupadd dinstall useradd -g dinstall -m -d /home/dmdba -s /bin/bash dmdba passwd dmdba然后规划安装目录和数据目录。我的习惯是这样分开:
/dm8:数据库软件安装目录,放可执行程序、jar包、驱动、内置工具。/dm8/data:数据目录,放控制文件、数据文件、Redo日志。/dm8/arch:归档日志目录。/dm8/backup:备份文件目录,也是搭建备库时备份集暂存区。
归档目录和数据目录最好放在不同的物理磁盘或文件系统上,避免磁盘写满时互相拖累。
2.2 网络与端口规划
主备集群需要网络传输大量Redo日志,同步网的好坏直接决定同步延迟。生产环境最好单独用一张网卡做数据库实例之间的数据同步,不要和业务流量、备份流量混在一起。我见过客户把日志同步和业务请求放在同一个千兆网口上,业务高峰时同步延迟飙到几十秒,备库追不上主库,一发生切换丢数据丢得心惊肉跳。
端口规划要有全局观。假设主库在192.168.10.11,备库在192.168.10.12,我习惯使用以下分配逻辑:
| 用途 | 主库 | 备库 | 说明 |
|---|---|---|---|
| 数据库实例监听端口 | 5236 | 5237 | 客户端通过该端口连接数据库 |
| MAL通信端口 | 6336 | 6337 | 实例间日志同步专用通道 |
| 守护进程端口 | 8336 | 8337 | DM Watcher之间互相通信、传递心跳 |
这个规划的核心是:数据库端口、MAL端口、守护端口三者互不冲突,且在主备两台机器上保持一致错位。防火墙记得放行这些端口,如果用云主机安全组,也要在安全组规则里配置。不然配置全对,网络不通,守护进程会一直报错。
2.3 时间同步
主备集群里,两台机器的时间差不能太大。Redo日志的序号虽然不依赖系统时间,但守护进程判断日志应用状态、故障时间线时,如果时间差距过大,轻则告警日志刷屏,重则切换逻辑判断错乱。
推荐每台机器都配置chrony或ntpd,指向公司内网时间源,并设置开机自启。配置完用chronyc sources -v验证同步状态。
3. 主备集群的四个配置文件:每份文件到底是干什么的
DM8主备集群的核心配置集中在四个文件里,把它们之间的关系搞清楚,配置就不会觉得乱。这四个文件我都放在数据目录下,也就是/dm8/data/DAMENG下。
dm.ini:实例配置文件,相当于实例的“身份证”。里面定义实例名、端口号、是否启用MAL和归档等核心开关。dmmal.ini:MAL系统配置文件,相当于集群节点之间的“通讯录”。各节点的MAL主机地址、端口都在这里面登记。dmarch.ini:归档配置文件,定义日志归档到哪里、归档文件大小限制等。dmwatcher.ini:守护进程配置文件,定义守护组的模式、故障判定时间、节点信息等。
3.1 dm.ini中最关键的四个参数
每个节点的dm.ini至少要关注以下参数:
INSTANCE_NAME = DM1 PORT_NUM = 5236 MAL_INI = 1 ARCH_INI = 1注意主备实例名必须不同,比如主库叫DM1,备库叫DM2。数据库名DB_NAME则要完全一致,否则后面备份恢复会报“库不匹配”。
MAL_INI=1表示实例启动时启用MAL系统,这是日志同步和守护进程通信的前提。ARCH_INI=1表示启用归档配置,等于告诉实例去读取dmarch.ini。这两个开关都在数据库实例启动前就要定好,运行过程中不能随便改。
3.2 dmmal.ini:集群的通讯录
dmmal.ini在主备两台机器上的内容基本一致,每个节点占一个小节。以两节点为例:
# 全局配置 MAL_CHECK_INTERVAL = 5 MAL_CONN_FAIL_INTERVAL = 5 # 主库节点 [MAL1] MAL_INST_NAME = DM1 MAL_INST_HOST = 192.168.10.11 MAL_INST_PORT = 6336 MAL_DW_PORT = 8336 # 备库节点 [MAL2] MAL_INST_NAME = DM2 MAL_INST_HOST = 192.168.10.12 MAL_INST_PORT = 6337 MAL_DW_PORT = 8337MAL_INST_HOST要写对方机器能访问到的实际IP,不要写localhost。MAL_INST_PORT是MAL通信的数据通道端口,MAL_DW_PORT是守护进程通道端口,这两个端口和dmwatcher.ini中的DW_PORT需要保持一致。
3.3 dmarch.ini:归档日志的存放规则
主备节点都要配置归档,因为主库要归档日志给备库同步,备库自己也需要保留日志便于追溯。
[ARCHIVE_LOCAL1] ARCH_TYPE = LOCAL ARCH_DEST = /dm8/arch ARCH_FILE_SIZE = 1024 ARCH_SPACE_LIMIT = 0ARCH_FILE_SIZE单位是MB,这里设置单个归档文件最大1024MB;ARCH_SPACE_LIMIT = 0表示不限制归档空间总大小,生产环境建议限制一个合理值,不然归档文件堆满磁盘会导致数据库hang住。
3.4 dmwatcher.ini:故障切换的总调度
守护进程是主备集群的大脑。dmwatcher.ini示例:
DW_MODE = AUTO DW_INACTIVE_INTERVAL = 10 DW_ERROR_TIME = 30 [DM1] DW_INST_NAME = DM1 DW_HOST = 192.168.10.11 DW_PORT = 8336 DM_INI_PATH = /dm8/data/DAMENG/dm.ini [DM2] DW_INST_NAME = DM2 DW_HOST = 192.168.10.12 DW_PORT = 8337 DM_INI_PATH = /dm8/data/DAMENG/dm.iniDW_MODE有两种值:AUTO和MANUAL。AUTO模式下,主库故障后守护进程自动把备库切换为主库,这就是自动故障转移;MANUAL模式下,主库故障后需要DBA手动干预,适合那些需要人工确认后才能切换的严肃生产系统。绝大多数场景我都会推荐AUTO。
DW_INACTIVE_INTERVAL是实例被判定失效的时间窗口,单位是秒。这个值不能设得太小,否则网络抖动容易误判;也不能设得太大,否则业务等待时间过长。一般10秒左右比较稳妥。DW_ERROR_TIME是守护进程报错后的等待时间,设30秒。
需要注意,dmwatcher.ini的节点块名称在不同版本里可能有细节差异,我在实操中见过的写法是直接用小节名对应实例名。如果你用的是某个特定版本,以该版本官方手册中的示例为准,但整体字段逻辑是通用的。
4. 主备搭建实操过程:从库初始化到备份恢复
配置文件的逻辑理清后,实际操作就容易多了。整个流程可以分成四步:初始化两套实例、配置主库归档并做备份、把备份恢复到备库、启动守护进程完成角色确认。
4.1 初始化主备实例
安装好DM8软件后,用dminit工具初始化数据库实例。主库和备库分别执行以下命令,只是实例名和端口不同。
主库:
dminit PATH=/dm8/data PAGE_SIZE=32 CASE_SENSITIVE=1 CHARSET=1 DB_NAME=DAMENG INSTANCE_NAME=DM1 PORT_NUM=5236备库:
dminit PATH=/dm8/data PAGE_SIZE=32 CASE_SENSITIVE=1 CHARSET=1 DB_NAME=DAMENG INSTANCE_NAME=DM2 PORT_NUM=5237这里有三个参数必须严格一致:PAGE_SIZE、CASE_SENSITIVE、CHARSET。页面大小不一致会导致备份集无法在备库恢复;大小写敏感设置不一致会导致恢复后数据行为不同;字符集不一致会导致中文乱码甚至恢复报错。所以初始化之前就要想好一套标准参数,两台机器照着用。
初始化完成后,先把两套实例都正常注册服务并启动起来。服务注册一般使用达梦自带的dm_service_installer.sh脚本,注册好后把实例先启动到OPEN状态,再通过disql连接到实例执行:
ALTER DATABASE MOUNT;为什么要切到MOUNT状态?因为主备集群的日志同步要求主库和备库都先以MOUNT状态收拢,后续由守护进程控制角色切换。备库必须保持MOUNT状态,不能处于OPEN状态去对外提供读写,否则主备逻辑会错乱。
4.2 主库开启归档并做备份
在MOUNT状态下配置主库的归档。达梦支持在线修改归档配置,命令如下:
ALTER DATABASE ADD ARCHIVELOG 'TYPE=LOCAL, DEST=/dm8/arch, FILE_SIZE=1024, SPACE_LIMIT=0'; ALTER DATABASE ARCHIVELOG;这两句执行完后,主库的归档模式就打开了。接着恢复主库到OPEN状态:
ALTER DATABASE OPEN;然后对主库发起一个完整的联机备份,备份集放到指定目录:
BACKUP DATABASE FULL TO FULL_BAK_20250321 BACKUPSET '/dm8/backup/full_bak_20250321';这里我不展开说语法细节,因为不同小版本略有差异,但完整备份这一步是搭建备库的数据基础。主库确认备份成功后,把备份集整个目录拷贝到备库服务器的/dm8/backup目录下:
scp -r /dm8/backup/full_bak_20250321 dmdba@192.168.10.12:/dm8/backup/4.3 在备库执行恢复
备库实例此时应该处于停止状态,不能开着服务去恢复覆盖数据文件。使用达梦自带的备份恢复工具dmrman:
dmrman进入工具后依次执行:
RESTORE DATABASE FROM BACKUPSET '/dm8/backup/full_bak_20250321'; RECOVER DATABASE FROM BACKUPSET '/dm8/backup/full_bak_20250321';RESTORE把备份集的数据文件还原到备库的数据目录,RECOVER则把备份过程中产生的Redo日志重演到备份结束的那个时间点。两条命令都完成后,备库的数据就已经和主库备份时刻的数据一致了。
这里要注意备份集的文件权限。拷贝过来的备份文件如果属主不是dmdba,dmrman会拒绝读取,拷贝后记得检查一遍:
chown -R dmdba:dinstall /dm8/backup chown -R dmdba:dinstall /dm8/data4.4 分发并核对配置文件
现在把主库的dm.ini、dmmal.ini、dmarch.ini、dmwatcher.ini检查一遍,备库也要对应准备。注意dm.ini里INSTANCE_NAME和PORT_NUM要改成备库的值,其他三个文件的节点信息都包含主备两端内容,基本可以一致使用。
我一般会在备库准备一份单独的配置清单逐项打勾:
dm.ini中INSTANCE_NAME=DM2是否正确。PORT_NUM=5237是否和主库不同。MAL_INI=1是否开启。ARCH_INI=1是否开启。dmmal.ini中两个节点IP、端口是否对应实际环境。dmwatcher.ini中DW_INST_NAME是否和dm.ini的实例名一致。
4.5 按照正确顺序启动服务
启动顺序错了也会踩坑。我推荐的顺序是:先启动备库到MOUNT,再启动主库到MOUNT,然后启动两台机器的守护进程。
具体操作:
- 启动备库数据库实例,用
disql连接后执行ALTER DATABASE MOUNT;。 - 启动主库数据库实例,同样切到MOUNT状态。
- 在主库节点启动守护进程:
dmwatcher /dm8/data/DAMENG/dmwatcher.ini,以服务方式启动也可以。 - 在备库节点启动守护进程。
守护进程启动后,观察日志输出。正常情况,主库守护进程会把主库自动置为PRIMARY并切换到OPEN状态,备库会自动变成STANDBY状态并开始从主库接收和应用Redo日志。这个过程可能要等十几秒,别刚看到日志没输出就急着重启。
启动完成后,在任意一台机器上用disql登录数据库,查询视图:
SELECT NAME, INSTANCE_NAME, ROLE, STATUS FROM V$DATABASE;如果主库ROLE显示PRIMARY,备库ROLE显示STANDBY,说明主备关系建立成功。此时再往主库建一张测试表插入数据,备库应该能很快查到同样的数据,这说明日志同步链路是通的。
5. 故障切换验证和回切:演练时最容易暴露问题的环节
配置搭完不代表高可用已经生效,真正决定集群质量的是故障切换能不能在预期时间内完成。很多团队搭建完成后直接丢到生产,三个月后主库真挂了才发现备库数据延迟了好几分钟,或者备库根本没有自动切换。所以上线前必须做至少两轮故障演练。
5.1 模拟主库宕机
我常用的最小化演练方式是直接在主库节点上杀掉数据库服务进程,模拟最极端的硬件故障:
kill -9 $(pgrep -f dmserver)守护进程检测到主库失联后,会等待DW_INACTIVE_INTERVAL设定的时间窗口,然后通知备库守护进程执行角色切换。按我上面的10秒配置,大概十几秒后,原备库就会变成PRIMARY并对外提供服务。
在这个环节你要重点观察两件事:
- 切换时间是否符合预期。如果超过一分钟还没切换,优先检查守护进程日志,看故障检测是卡在哪个阶段。
- 业务侧是否真的能连上新主库。如果业务连接串还指向原主库IP,切换后业务自然连不上。生产环境一般配合VIP漂移或者应用连接池的重连机制来解决。
5.2 主库恢复后重新加入集群
故障切换只是第一步,原主库修复后怎么让它重新回到集群作为备库,才是最容易出乱子的地方。不要直接启动原主库让它自己同步,因为此时原主库的数据已经和现主库不一致了。
正确的思路是:把现主库做一个新的完整备份,恢复到原主库节点,让原主库以备库身份重新加入集群。具体流程和执行上面搭建备库是一样的:现主库备份、拷贝备份集到原主库、原主库停机恢复、重新启动守护进程观察状态。
很多人在这一步图省事,直接启动原主库然后指望日志追赶,结果两个实例互相认为自己是主库,脑裂风险极大。对于主备集群,任何情况下都不要让两个实例同时以PRIMARY角色对外服务。
5.3 平时运维必须盯的指标
主备集群平时的运维,重点盯三个地方:
- 归档目录使用率。日志同步依赖归档,归档目录满了,数据库会停止写入,整个系统直接不可用,这是生产事故的重灾区。
- 同步延迟。可以通过守护进程日志或者系统视图观察备库应用日志是否滞后,如果持续增长,说明网络带宽不够或者备库性能跟不上。
- 备库状态。定期确认备库仍是STANDBY角色且数据库处于正常的MOUNT状态,防止备库被误操作打开变成普通库。
6. 写在实际操作之后的几条心得
这套主备集群搭建方式,我在多个现场环境里验证过,也帮客户排过不少后续问题。最后补几个实际踩过坑之后得出的经验。
第一个建议是配置文件的字段名核对问题。达梦不同版本、不同补丁之间,某些参数写法可能有细微差异,比如DW_MODE在高版本里可能默认值不同,dmmal.ini的块名称也可能受版本影响。所以每次到新环境,我第一件事是打开官方手册翻阅对应版本的主备集群章节,把字段名和当前环境的示例文件逐个对照,再开始动手。别觉得自己搭过一次就能凭记忆盲写。
第二个经验是备份集一定要保留到集群稳定运行几天后再删。搭建备库时产生的那份完整备份,是回切和重建备库的重要底座,如果删了,下次出问题只能在线再打一份备份,时间和带宽成本都高。
第三个建议是切换演练一定要纳入每季度固定运维计划,而不是只在项目上线前做一次。数据库版本升级、操作系统补丁、网络设备调整都可能影响集群行为,定期演练才能保证故障发生时,预案是真的能跑通的。我见过不止一个项目,建集群时测试一切正常,半年后网络加了防火墙策略导致守护端口被禁,真发生切换时备库根本不知道主库挂了,业务直接中断。
最后提一句,如果你的业务系统对RTO非常敏感,网络环境又不稳定,可以认真考虑把DW_INACTIVE_INTERVAL调得更短,并且给业务连接配上多地址重试机制。集群只是给了数据库一个自动恢复的机会,应用侧能不能快速感知和重连,直接影响最终的业务中断时间。主备集群是一整套工程,不是几条SQL命令的事。