ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

达梦DM8读写分离集群配置与故障切换实战指南

达梦DM8读写分离集群配置与故障切换实战指南 去年年末接到一个活儿客户的核心业务系统用的是达梦数据库业务形态是典型的读多写少白天大量查询高峰期写操作也不少。主库CPU在业务高峰经常飙到80%以上有几个慢查询差点把应用拖垮。当时评估了两套方案一是直接升配服务器二是上达梦读写分离集群。我选择了后者。这个方案既能分散主库读压力又能保住高可用底线在DM8上属于比较成熟的使用方式。折腾了两周把主备部署、日志同步、读写路由和故障切换都验证了一遍最终顺利上线。这篇就把配置与测试的全过程记录下来给正在摸达梦集群的朋友一些参考。我先把结论放在前面达梦读写分离集群本质上是在数据守护Data Watch的基础上让备库以只读方式对外提供查询服务主库承担所有写入和部分必须强一致的读操作。它适合读请求远大于写请求、允许读库有毫秒级延迟、同时要求数据库具备自动故障切换能力的业务。如果你的业务对一致性要求极其苛刻比如任何读都不能读到旧数据那就要谨慎设计路由策略甚至所有请求都走主库。后面我会详细聊这个坑。1. 达梦读写分离集群的定位与选型思路1.1 达梦数据库高可用方案的横向比较达梦数据库这里以DM8为例官方提供的高可用方案不止一种最容易搞混的就是共享存储集群DSC、数据守护Data Watch和读写分离集群。它们的核心区别在于数据分布方式、故障切换粒度和适用场景。我用一个表格帮助大家快速理解方案架构形态数据存储读扩展自动切换典型场景DMDSC多实例共享同一份存储类似Oracle RAC集中存储一般多实例可读写但共享存储是瓶颈支持需要高可用且不丢数据单机性能不足数据守护一主一备或一主多备备库处于恢复状态各节点独立存储日志同步较弱备库一般不做业务查询支持容灾、故障切换读写分离的基础读写分离集群一主多备常用一主一备备库只读各节点独立存储实时同步强备库直接承担读流量支持读多写少、查询密集型业务MPP多节点并行计算数据分布存储各节点独立存储按表/分区分布强分析查询并行一般大并发分析、数据仓库类业务当时客户业务的特点是在线交易加报表查询混跑事务量不大但查询量很大而且要求主库故障后业务不能长时间中断。DSC需要共享存储客户机房没有现成的SAN存储MPP更偏向分析型负载对OLTP事务的支持不够友好。算来算去读写分离集群最合适主库继续保持OLTP写入能力备库把高频查询全部接走还有守护进程盯着状态一旦主库挂了可以自动切换一举两得。1.2 读写分离集群的架构与设计目标读写分离集群的基本形态是一主一备或一主多备。主库完全开放负责所有INSERT、UPDATE、DELETE以及部分SELECT备库以只读方式运行持续接收并应用主库的Redo日志对外提供查询服务。应用层通过数据源路由把读写请求分发到不同节点。这个架构解决的核心问题有三个第一降低主库负载。把高频、只读的查询分流到备库让主库集中精力处理写事务相当于用一台备库服务器的成本换来了读能力的线性扩展。第二保留完整的高可用能力。备库并不是单纯做报表的“备份货架”它实时同步主库数据并运行着守护进程。主库宕机后备库可以自动切换为新主库业务读连接自动转移写连接在短暂中断后恢复。第三降低跨机房的容灾成本。主备库可以部署在不同物理机甚至不同机房数据通过日志实时同步本质上是把容灾和读写分离揉在了一起省掉了一套独立灾备环境的投入。不过要泼一盆冷水读写分离不等于“随便读”。由于日志传输和应用有一定耗时备库的数据存在毫秒级延迟。应用里那些先插入数据、马上又要查询这笔数据的场景如果路由到了备库很可能查不到。这个必须在应用设计上做约束比如强制走主库或者接受最终一致性。2. 核心组件与工作原理2.1 集群里的每个角色都在干什么部署过Oracle Data Guard的人再看达梦读写分离集群会发现很多相似概念但名字完全不一样。集群里主要有这几个角色角色进程/组件职责主库dmserver对外提供读写服务产生Redo日志并通过日志发送线程把日志传给备库备库dmserver只读接收并应用主库日志对外提供只读查询服务守护进程dmwatcher部署在主备库上监控实例状态自动发起故障切换监视器dmmonitor部署在独立节点或某台机器上查看集群状态手动控制切换归档配置dmarch.ini配置本地归档和实时日志传输通道这里容易犯糊涂的是守护进程和监视器的分工。简单理解守护进程是“贴身保镖”每台数据库机器上都有一个负责感知本机状态并向监视器汇报监视器是“指挥官”如果设置自动切换实际决策逻辑由监视器和守护进程共同完成。生产环境我建议单独弄一台轻量服务器跑监视器别跟数据库挤在一起否则主库机房整体断电时监视器也没了自动切换就成了空话。2.2 数据同步机制日志传输而不是SQL重放读写分离集群能保持数据一致靠的是主库产生的Redo日志实时传输到备库再由备库日志应用进程重放。这个过程有两个关键点第一它是在物理日志层面同步的不是把SQL捞出来在备库重新执行。因此备库不需要再次解析、优化SQL应用日志的代价远小于执行SQL的代价性能损耗很低。第二同步模式可以配置。达梦支持同步归档和异步归档。同步模式REALTIME要求主库事务提交时日志必须已经被备库接收并落盘RPO为0理论上主库宕机也不丢数据但写入RT会高一些。异步模式备库接收日志延迟可以忍受主库写性能几乎没有损失但极端故障下可能丢少量数据。读写分离集群我建议用同步实时归档毕竟备库要承接读业务数据延迟过大容易引发业务事故。另外达梦的归档通道有个“即时归档”概念和实时归档不一样。实时归档是日志产生后立刻推给备库即时归档是本地归档文件切换时才同步过去延迟更大。配置时要在dmarch.ini里写清楚ARCH_TYPEREALTIME不要用默认的LOCAL。3. 环境准备两台Linux机器与DM8的安装3.1 硬件与操作系统要求读写分离集群至少需要两台机器。我这次用的是两台虚拟机配置不高但足够验证整个流程每个节点4核CPU、8GB内存、200GB数据盘。生产环境建议主备配置保持一致避免切换后性能缩水。操作系统是CentOS 7.9 x86_64数据库版本是达梦DM8。安装介质从官网申请开发版即可开发版功能上足够支撑小规模集群验证。需要注意核对CPU架构x86和ARM的安装包不通用。3.2 创建用户与安装目录这一步很多新手会跳过结果安装时各种权限报错。达梦要求使用专用系统用户运行数据库不能直接用root。命令我贴一下groupadd dinstall useradd -g dinstall -m -d /home/dmdba -s /bin/bash dmdba mkdir -p /dmdata /dmarch /dmsoft chown -R dmdba:dinstall /dmdata /dmarch /dmsoft安装包解压后把整个目录放到/dmsoft下之后用dmdba用户执行安装su - dmdba cd /dmsoft/DM8_Install ./DMInstall.bin -q如果是在图形界面环境下直接双击运行如果是远程终端建议用-q静默安装提前准备好install.properties文件。静默安装的响应文件模板在安装目录里有按实际路径改一下安装位置和数据库类型即可。安装完成后bin目录下的工具是最常用的dmserver是数据库服务进程disql是命令行客户端dmrman是备份恢复工具dminit是初始化工具后面都要用到。3.3 初始化主库并做成基础备份两台机器都安装完DM8后先初始化主库。这里有一个必须重视的约定主备库的初始化参数要完全一致尤其是页大小和字符集。页大小一旦初始化就不能改如果主备不一致日志应用必定报错。我在主库机上执行了初始化cd /dmsoft/bin ./dminit PATH/dmdata/dm01 PAGE_SIZE16 CHARSET1 CASE_SENSITIVE1 INSTANCE_NAMEDM_A参数含义PATH是数据文件目录PAGE_SIZE16表示页大小16KBCHARSET1表示UTF-8CASE_SENSITIVE1表示区分大小写。这些参数在备库初始化时必须保持一致。初始化结束后先把主库以正常方式启动一次确认数据库能起来。然后做一次物理备份作为备库的初始数据su - dmdba cd /dmsoft/bin dmserver /dmdata/dm01/dm.ini disql SYSDBA/SYSDBAlocalhost:5236 backup database full backupset /dmarch/init_bak;备份完成后把整个数据目录/dmdata/dm01和备份集都拷贝到备库机上。最保险的方式是用scp打包传输注意保持目录权限tar czf dm01.tar.gz /dmdata/dm01 /dmarch/init_bak scp dm01.tar.gz 192.168.56.102:/dmdata/备库机上解压后把目录权限调整好修改dm.ini里的实例名为DM_B路径不变。这样备库就有了和主库完全一致的数据文件省去了从零恢复的大量时间。备库的初始化其实也可以单独用dminit生成但用主库备份恢复更稳妥能确保数据文件完全同步。4. 定制化配置让主备库进入集群状态4.1 主库dm.ini的核心参数达梦集群要正常工作需要在dm.ini里打开几个开关。主库和备库的dm.ini都要设置差异主要在实例名和部分路径上。关键参数如下INSTANCE_NAME DM_A MAL_INI 1 ARCH_INI 1 DW_INI 1 ALTER_MODE_STATUS 0 ENABLE_OFFLINE_REP 0MAL_INI1表示启用MAL系统这是达梦集群节点之间通信的基础ARCH_INI1表示启用归档配置会读取dmarch.iniDW_INI1表示启用数据守护会读取dmwatcher.ini。ALTER_MODE_STATUS和ENABLE_OFFLINE_REP建议保持0避免手工误切换和非法操作破坏集群状态。备库的dm.ini除了实例名改为DM_B其他保持一致。如果备库数据文件来自主库备份还要检查数据目录里的归档日志路径是否合适必要时手动创建归档目录。4.2 dmmal.ini与dmarch.ini配置dmmal.ini定义集群中每个节点的MAL通信端口和实例信息。我的两台机器地址假设为主库192.168.56.101备库192.168.56.102端口规划如下MAL_CHECK_INTERVAL 5 MAL_CONN_FAIL_INTERVAL 10 [MAL_INST1] MAL_INST_NAME DM_A MAL_HOST 192.168.56.101 MAL_PORT 5237 MAL_INST_HOST 192.168.56.101 MAL_INST_PORT 5236 MAL_DW_PORT 5238 [MAL_INST2] MAL_INST_NAME DM_B MAL_HOST 192.168.56.102 MAL_PORT 5237 MAL_INST_HOST 192.168.56.102 MAL_INST_PORT 5236 MAL_DW_PORT 5238MAL_PORT是节点间日志传输的通信端口MAL_INST_PORT是数据库实例的服务端口MAL_DW_PORT是守护进程的通信端口。这些端口不能和数据库端口冲突防火墙里要放行。MAL_CHECK_INTERVAL和MAL_CONN_FAIL_INTERVAL用默认即可没必要调的太激进否则网络抖动时容易误判。dmarch.ini配置归档策略主备库基本相同。主库dmarch.ini长这样ARCH_WAIT_APPLY 1 [ARCHIVE_LOCAL1] ARCH_TYPE LOCAL ARCH_DEST /dmarch/arch ARCH_FILE_SIZE 2048 ARCH_SPACE_LIMIT 10240 [ARCHIVE_REALTIME1] ARCH_TYPE REALTIME ARCH_DEST DM_BLOCAL归档是必需的用于本地保存日志方便备份恢复REALTIME归档指定实时发送到哪个备库实例ARCH_DEST填的必须是备库的MAL_INST_NAME。备库的dmarch.ini中REALTIME归档的ARCH_DEST填主库的MAL_INST_NAMEDM_A。LOCAL归档路径在备库也要改成自己的目录。注意ARCH_FILE_SIZE单位是MB我设置了2048MB一个归档文件ARCH_SPACE_LIMIT是归档目录总容量上限设置10240MB即10GB。归档目录如果写满数据库会挂起这个要结合磁盘空间提前规划。4.3 dmwatcher.ini配置与守护进程启动dmwatcher.ini是守护进程的配置主备库内容一样。放在数据目录下DW_MODE AUTO DW_ERROR_TIME 10 INST_RESTART_INTERVAL 60 INST_OGUID 4532DW_MODEAUTO表示自动切换模式这是生产推荐的模式。如果设置为MANUAL主库故障后需要人工干预那就失去了高可用的意义。DW_ERROR_TIME是守护进程判定实例故障的超时时间单位秒。INST_OGUID是一个集群标识所有节点必须一致可以用任意数字但不要跟别的集群重复。配置完成后启动顺序很关键。我第一次配置时顺序搞反折腾了很久。正确顺序是先启动主库到OPEN状态再启动备库到MOUNT状态如果是用备份恢复的备库。启动主库上的守护进程。启动备库上的守护进程。启动监视器。主库启动dmserver /dmdata/dm01/dm.ini 备库启动前需要先用dmrman恢复数据库状态。因为备库的数据文件直接复制自主库数据页里记录的数据库状态可能处于OPEN状态要把备库调整到正确状态。我用的命令是dmrman RESTORE DATABASE /dmdata/dm01/dm.ini FROM BACKUPSET /dmdata/init_bak;恢复完成后再执行dmserver /dmdata/dm01/dm.ini MOUNT 这里MOUNT是启动参数表示备库以MOUNT方式加载。接下来启动守护进程守护进程配置文件位置要和数据目录一致dmwatcher /dmdata/dm01/dmwatcher.ini 两台机器的守护进程都启动后最后启动监视器。监视器也使用dmwatcher.ini配置文件但它的作用是连接并监视守护进程不是被守护的对象。命令为dmmonitor /dmdata/dm01/dmwatcher.ini进入监视器命令行后输入show可以看到集群状态。如果主备状态为OPEN/MOUNT守护进程状态为STARTUP或OKOGUID一致说明集群基本起来了。如果主备库都显示OPEN那可能有问题需检查是不是启动参数没加对。5. 读写分离的真正实现应用如何做到“写主读从”5.1 不依赖中间件JDBC双数据源方案集群只是把读能力备好了业务要真正用上备库还得在应用层做路由。第一种做法是配置两个数据源无脑但有效。Spring Boot项目里写两套数据源配置spring: datasource: primary: jdbc-url: jdbc:dm://192.168.56.101:5236 username: SYSDBA password: SYSDBA driver-class-name: dm.jdbc.driver.DmDriver readonly: jdbc-url: jdbc:dm://192.168.56.102:5236 username: SYSDBA password: SYSDBA driver-class-name: dm.jdbc.driver.DmDriver再把两个数据源定义成不同的Bean查询方法用读库更新方法用写库。有什么缺点首先是侵入性很强每个Service方法都要手动选择数据源漏一个就可能把读压力打回主库其次事务混合在一起时容易出事一个事务里先写后读如果读走了备库读到旧数据是大概率事件。所以这种方法更适合老项目快速改造但不适合对一致性敏感的大型业务。5.2 使用中间件ShardingSphere一类的自动路由更优雅的方式是引入读写分离中间件让路由规则集中在配置层。以ShardingSphere为例它可以配置数据源分组和负载均衡策略rules: - !READWRITE_SPLITTING dataSources: rw_ds: writeDataSourceName: dm_primary readDataSourceNames: - dm_readonly loadBalancerName: round_robin这样应用只面向一个逻辑数据源中间件根据SQL类型自动把读请求分发到备库写请求固定发到主库。事务内默认全部走主库避免读到旧数据。想强制某个查询走主库可以加Hint或SQL注释。我比较推荐中间件方案原因有两个一是路由规则集中管理后续加备库、改策略都容易二是事务边界容易控制不需要业务代码里塞一堆数据源判断。缺点也很明显中间件成为关键路径运维上多一个组件要维护网络拓扑也复杂了一些。5.3 强一致读怎么办给出兜底策略无论用哪种路由方式都要面对一致性问题。我的处理经验是在数据源路由里增加一个“主库优先”开关。具体做法是把读请求默认走备库但标记那些必须在主库执行的查询比如刚刚提交订单后的详情查询走主库。用注解或者ThreadLocal去控制代码层面写清楚哪些场景需要强一致避免一刀切全部走备库导致备库压力没减下来。还有一个兜底方案备库同步延迟告警。通过在备库上查询主备日志差距如果延迟超过设定阈值直接切走全部读流量到主库。这个可以通过应用配置中心动态调整路由规则配合监控实现。初期没有太复杂的监控时至少要把主备延迟的SQL定期跑一遍出了问题心里有数。6. 测试从状态检查到压测再到故障切换6.1 集群状态检查与同步延迟验证基础环境搭好之后要做一轮完整的验证。先确认主备状态和守护进程都正常。进入dmmonitor后我常用的命令是login show global info show watcher infoshow global info会列出所有实例的运行模式、状态、OGUID等show watcher info能看到守护进程的状态。正常的输出里两个实例都在线主库OPEN备库MOUNTOGUID一致守护进程状态为OK。再登录数据库查看同步情况。我用disql执行select * from v$arch_status; select * from v$recover_status;主库上可以看到REALTIME归档状态是否正常备库上可以看到日志应用进度。最直接的方法是建一张测试表插一条数据后立即到备库查询-- 主库执行 create table t_verify(id number, col varchar(20)); insert into t_verify values(1, cluster_test); commit; -- 备库执行 select * from t_verify;如果备库能查到这条记录说明实时同步链路通了。如果查不到不要急着下结论先确认数据是否提交再确认备库是否已经应用日志。理论上同步模式下主库commit时备库已经收到日志但应用可能略有延迟。6.2 功能验证备库只读与读写冲突备库必须是只读的这个要重点验证。我在备库上执行insert into t_verify values(2, readonly_test);期望会得到类似“数据库只读不允许执行该操作”的报错。这一步很关键如果备库能写入说明数据守护配置出了问题可能是备库没有正确以只读方式打开或者在被误当成普通独立库启动了。接着验证读性能是否真的分到了备库。可以开两个终端在主库和备库分别查看当前连接数select count(*) from v$sessions;然后跑一个并发查询程序观察备库连接数上升而主库连接数增加不明显说明读流量确实被分流了。如果主库连接数还是蹭蹭涨要去应用侧看路由是否生效。6.3 读写分离性能压测模拟读多写少压测是判断集群到底值不值得上的关键。我用的是一个自写的小工具模拟200个并发线程其中80%的执行等幂SELECT20%执行INSERT分别跑单机环境和读写分离环境各10分钟记录TPS、QPS、主备库CPU使用率。测试结果很有代表性指标单机主库读写分离集群总TPS含读8501420读QPS6801240写TPS170180主库CPU峰值82%46%备库CPU峰值-58%可以看到读写分离后主库CPU明显下降整体吞叶量上了一个台阶。备库CPU虽然升高但这就是买它的意义。要注意压测时不要把所有线程的SELECT都发往备库仍然保留一部分SELECT走主库模拟真实业务中必须强一致的查询否则主库CPU会降得过低反而不符合实际。压测过程中要盯监控。我记得第一次压测时备库CPU飙到了90%排查发现是有一条看起来很小但走了全表扫描的SQL在备库上放大后很吃资源。后来给这个查询相关表补了索引备库CPU才降下来。这也提醒我读写分离只是解决了读能力横向扩展SQL本身的执行效率该优化还得优化。6.4 故障切换与回切测试高可用方案必须做真实的故障演练不能只停留在“配置上了应该没问题”。我做了两次切换测试。第一次测试主库进程被kill。操作是kill -9 主库dmserver进程号此时监视器会检测到主库心跳丢失。等DW_ERROR_TIME超时后备库自动切换为新主库状态由MOUNT变为OPEN。应用侧读连接因为在备库基本无感写连接在切换窗口期会抛异常重连后恢复正常。我实测切换耗时在15秒左右如果让DW_ERROR_TIME更短可以更进一步缩短但太短容易因网络抖动误切换不建议极端追求。切换完成后备库承担了主库角色原主库变为了故障实例。我把原主库机器重新启动它不会自动乖乖变回主库。需要在监视器里执行手动将原主库加入集群让它重新成为新主库的备库login choose DM_A as standby或者根据具体版本执行相应命令。回切操作类似不再赘述。这里想强调高可用切换是最后一道防线能不动手就不要轻易回切尤其是业务运行平稳时。很多故障的发生恰恰是在回切过程中。7. 常见问题与避坑指南7.1 数据库启动报“544”错误这个错误在达梦环境里太常见了。报错信息类似“连接服务器失败错误码-544”多发生在客户端连接数据库时原因也五花八门。我遇到过两种一是数据库实例根本没启动用ps -ef | grep dmserver一看进程不存在二是网络端口不通连接的是备库地址但备库没有开放服务端口。排查步骤通常是ps -ef | grep dmserver ss -ltnp | grep 5236如果进程没启先看错误日志如果端口没监听检查dm.ini里的PORT_NUM和是否以正确模式启动。还有一种情况是在备库上直接执行了dmserver而没加MOUNT参数导致备库启动成了独立库端口虽然监听但集群状态不对也会让应用连接出现奇怪错误。7.2 主备同步失败日志应用卡住我配置过程中遇到最头疼的问题是备库日志应用一直卡住v$recover_status显示进度不动。最后定位到原因是dmmal.ini里MAL_INST_HOST写成了主机名而双机DNS解析有问题换成IP地址就好了。这个案例说明如果节点间通信异常优先排查MAL配置里的IP和端口而不是数据库本身的归档逻辑。另外要确保主备库的页大小、字符集、大小写敏感等初始化参数完全一致。我在备库机上曾经用dminit重新初始化了一份数据文件结果页大小默认8K主库是16K归档日志应用直接报错。后来重新用主库备份恢复才解决。这个问题很难从表面看出来最好在主备库分别执行select page_size, charset, case_sensitive from v$dm_ini;自己心里有数。7.3 守护进程不自动切换自动切换要看三个条件DW_MODEAUTO、INST_OGUID一致、监视器在线。很多用户在测试时把DW_MODE设成了MANUALkill主库后观察半天发现备库纹丝不动还以为配置错误。另外监视器必须正常运行如果monitor进程挂掉自动切换也无法触发。我在生产环境给过同事一个建议定期做一次主备切换演练验证自动切换链路。不要只在实施时测一次就高枕无忧。切换后还要检查应用连接池是否针对新主库地址做了配置否则主库地址漂移了应用还连旧地址高可用就白做了。7.4 Navicat这类图形工具连接达梦很多人习惯用Navicat操作数据库连接达梦时需要选择正确的驱动。Navicat需要安装达梦的JDBC驱动或者使用Navicat专门的达梦版本。如果连接报错先确认数据库是否开放了服务端口以及客户端机器的网络策略。达梦默认端口是5236服务端防火墙要放行。Windows上安装达梦客户端后也可以用DM管理工具直接连接功能更完整Linux上则常用disql。7.5 备份与日常运维建议读写分离集群虽然承担了容灾职责但备份还是要做。备库因为一直只读打开非常适合做备份不过要控制备份时间点别在主库大事务进行时备份导致备份集过大。建议每天在业务低峰从备库全量备份再定期做归档日志备份。备份集最好放到第三台机器或对象存储上防止主备库同时故障。集群上线后需要把几个动态视图加入监控v$instance实例状态、v$arch_status归档状态、v$recover_status日志应用状态、v$dmwatcher守护进程信息。如果主备延迟超过业务可接受阈值要及时告警。实际运营中readonly备库表空间、临时表空间增长也是要盯的因为查询负载大临时空间可能突增。最后分享一点个人心得。达梦读写分离集群不是搭起来就完事真正的难点在应用路由设计。你可以先把主备同步和自动切换跑通这是基础然后再花时间梳理业务SQL把那些允许最终一致性的查询摘出来走备库。上线后多观察几周发现备库延迟或性能问题再逐步调优。第一次配置的时候别急着上生产先在虚拟化环境里完整模拟一遍主库宕机、网络中断、备库回切把这些场景都跑熟了再动生产环境。这样才能在真正出事的时候不慌。
返回列表