前阵子到客户现场处理一套KingbaseES V8集群的架构调整需求很明确把当前两节点的集群拆成单实例继续跑。客户一开始以为这事很简单——把备机关掉主库能用就行。真上手才发现集群管理组件、配置文件、共享内存、VIP、应用连接串全都纠缠在一起不是一台一台关机就能撒手不管的。这篇文章就把这次集群拆单实例的完整过程和踩坑记录整理出来给后面遇到类似需求的运维同行做个参考。1. 为什么要把集群拆成单实例场景梳理与风险提示1.1 哪些场景会用到这个操作我在实际运维中遇到的“集群拆单实例”需求大致能归成四类。第一类是硬件下架或机房收缩。比如上面说的客户场景两台服务器要退租业务暂时又不能停只能把一套集群缩成一台机器上的单实例先把业务托住后面再考虑重新搭建高可用。第二类是集群故障后的降级恢复。比如仲裁节点反复抖动、脑裂风险一直存在或者集群里某个节点的数据文件异常集群整体起不来。为了先把业务恢复运维会临时把其中一个健康的节点摘出来以单实例方式启动让业务先跑起来再慢慢查问题。第三类是环境资源回收。测试环境、开发环境当初为了模拟生产搭了集群资源消耗不小。验证完功能后把多节点缩成单实例能省下不少内存、CPU和磁盘。这种需求在开发测试区非常常见。第四类是迁移过渡。老集群往新环境迁移新机器上先起一个单实例把数据导入并验证完毕后续再决定是否在新环境重新搭集群。这种情况下单实例是临时状态但操作路径和场景二几乎一样。1.2 拆分前必须想清楚的三个问题不是所有集群都适合直接拆动手之前我先问自己三个问题。第一个问题业务侧能不能接受高可用能力降级。集群模式一般有自动故障切换、备库只读分担、健康检查等能力。拆成单实例后这些全部消失。数据库一旦故障恢复时间完全取决于运维响应速度可能从原来的几十秒变成几十分钟。这个变化必须提前和业务方达成一致最好有书面确认。第二个问题拆完之后还要不要恢复集群。如果只是临时降级那么拆分操作要尽量保留可回滚的余地。配置文件的改动能不改名就不改名能用注释就不用删。保留现场后面重建集群时能省很多时间。第三个问题当前节点数据是不是完整且一致的。流复制架构下主库和备库数据不是严格同步的备库可能落后主库一段事务。共享存储集群下所有实例共享一份数据文件但也要确认集群停止前有没有实例异常退出导致需要恢复。这个问题不搞清楚拆出来的单实例就是个残缺库业务验证时才发现数据不对就晚了。2. 拆前评估与资料盘点先分清形态、再做备份、最后记参数2.1 先分清你手里是什么形态的集群KingbaseES V8的集群有两种常见形态处理方式差异很大。一种是共享存储集群多实例共享同一个数据目录或共享盘上的同一份数据文件。这种集群拆单实例时理论上任意一个节点保留下来都能继续使用同一份数据重点在于清理CLSCache Layer Service共享内存、分布式锁、集群内部通信配置。另一种是流复制集群主库和备库各自有独立的数据目录通过WAL日志实时同步。这种集群拆单实例时数据是以主库为准的。如果备库数据落后拆分后需要追日志或做增量恢复。如果主库已经故障、必须用备库顶上来还要先把备库提升为主库并补齐缺失的日志段。我在现场操作前一般会先通过集群管理命令或查看配置文件确认形态。实际操作中看数据目录里的标记文件最直接。比如流复制集群数据目录下会有类似 recovery.done、standby.signal 之类的主备标记共享存储集群则会有CLS相关的配置项或共享内存文件。每个版本文件名略有差异但方向是一致的先识别再动手。两种形态的差异可以整理成下面这张对照表对比项共享存储集群流复制集群数据存储多实例共享一份数据文件主备各一份独立数据文件数据一致性依赖共享存储和全局缓存协调依赖WAL日志同步备库可能有延迟拆分保留节点选一个健康节点即可优先保留主库主库不可用则提升备库主要清理对象CLS共享内存、分布式锁、集群缓存配置主备复制标记、恢复配置、同步槽位拆分风险点共享内存残留、锁没释放、集群模式参数未关闭备库数据滞后、日志断链、主备身份混淆2.2 数据完整性判断与拆分前备份不管哪种集群形态拆分前都必须做备份。这个没得商量。现场操作时我先用金仓自带的物理备份工具做了一次全量备份把数据文件、归档日志都拉出来。同时用 sys_dump 把关键业务库的逻辑备份也导了一份。这么做不是为了走流程而是给操作上双保险物理备份用于快速恢复整个实例逻辑备份用于应对“某个表数据有问题但物理备份也覆盖不到”的极端情况。备份文件一定要放到数据库节点之外的存储。我见过有人把备份放在数据盘上结果节点磁盘故障数据和备份一起消失那真是欲哭无泪。备份完成之后再确认数据目录里没有未恢复的WAL或redo日志。具体做法是查看日志文件里的恢复信息或者直接看数据目录下有没有需要recovery的临时文件。如果实例异常退出过优先用集群管理工具或数据库恢复机制把数据恢复到一致状态再考虑拆分。2.3 需要记录下来的配置参数清单拆分前要把当前集群的关键配置抄出来。这个习惯帮我避免过很多次“拆完了发现参数不对、数据库起不来”的尴尬。至少要记录参数记录内容拆分后处理建议listen_addresses当前监听地址和VIP改成单实例实际IP或*port数据库端口确认端口未被内部通信占用shared_buffers缓存大小按单机内存重新评估可保持不变max_connections最大连接数若原来备库分担业务流量需要调大archive_mode / archive_command归档开关和命令确认归档路径对单实例仍然有效cluster相关参数例如cluster_database_mode、CLS参数拆分时必须关闭或删除sys_hba.conf 白名单应用网段、运维网段确认覆盖真实IP不只是VIP业务连接方式应用连的是VIP还是节点IP拆分后要统一改成节点真实IP这些参数不一定全部需要修改但一定要“知道当前是什么值、后面为什么要动它”。比如连接数原来主库只承担主业务备库分担了部分只读流量。拆完单实例后所有流量都压到同一个实例上max_connections和shared_buffers如果不调整业务高峰可能直接打满连接数。3. 集群拆单实例实操全过程从停集群到切业务3.1 操作步骤总览我把整个操作分为六个阶段每一步都验证通过再进入下一步避免一步错、步步错。停机窗口前完成备份和参数记录停止集群全部节点和集群管理进程改造配置文件并清理集群标记以单实例方式启动数据库验证数据完整性和基本业务场景调整应用连接、系统服务、监控项下面按这个顺序展开把每个阶段的细节讲透。3.2 停止集群节点顺序和细节停集群的顺序有讲究。流复制集群要先停备库再停主库。共享存储集群则要求所有实例同时停止或按集群管理工具的要求依次停止避免锁冲突和缓存不一致。实际操作中我习惯先用集群管理命令停止整个集群而不是直接kill数据库进程。集群管理命令会先把仲裁、监控、资源代理等组件处理好再停止数据库实例。这样停得干净后续清理时不会出现“进程明明停了但注册信息还在”的问题。如果集群本身已经起不来管理命令无法执行那就只能手动处理。手动停止时同样按“备库先行、主库最后”的顺序用 sys_ctl -D 数据目录 stop 来停止实例。切忌直接 kill -9 数据库进程那可能导致共享内存没释放、数据文件未落盘后续启动会遇到更多麻烦。这里多说一句停止集群后要确认数据目录里不再有活着的数据节点进程。用 ps -ef | grep kingbase 查看确保所有相关进程都退出了再进入下一步。3.3 配置改造别只改一个开关这一步是整个拆分操作的核心也是大多数人容易漏项的地方。首先要找到主配置文件一般是数据目录下的 kingbase.conf。在集群环境下里面会有一堆与集群相关的参数。共享存储集群常见的是 cluster_database_mode on 以及一堆以 cls_ 开头的参数流复制集群则可能在文件里配置了主备身份、同步流复制参数。拆分时我先把 cluster_database_mode 改成 off或者直接注释掉。同时检查是否有 CLS 相关参数这类参数在单实例模式下应该全部去掉。如果不确定哪些参数可以被安全注释最简单的做法是把这些参数统一改成默认值然后通过日志确认启动结果再逐步调整。流复制集群还需要处理数据目录里的主备标记文件。我遇到过备库数据目录里有 standby 标记拆分后直接启动备库当单实例结果数据库反复提示“不能以单实例方式启动一个standby节点”。处理方式是把这些标记文件改名而不是删除比如加一个 .bak 后缀。这样万一操作失误还能恢复。共享存储集群则要清理 CLS 留下的共享内存和信号量。停集群后在操作系统层面用 ipcs -lm 查看是否还有 KingbaseES 相关的共享内存段残留。如果有用 ipcrm -m [shmid] 清理。这一步漏掉的话单实例启动时很可能报共享内存冲突数据库进程起不来。3.4 换一种方式启动从集群方式到 sys_ctl配置改完之后不要急着用集群管理命令启动而是直接用数据库实例管理命令启动确认它能独立运行。# 切换到数据库系统用户 su - kingbase # 单实例方式启动数据库 sys_ctl -D /opt/Kingbase/ES/V8/data start启动之后马上查看日志确认启动过程没有报错。日志一般在数据目录下的 sys_log 目录里文件名为 sys_startup.log 或类似的命名规则。看到“database system is ready to accept connections”这类输出就说明实例已经起来了。接着通过 ksql 连接数据库验证实例当前状态-- 查看当前实例是否处于集群模式 SHOW cluster_database_mode;如果返回 off说明实例已经脱离开了集群模式。我还会顺手查一下数据字典或系统视图里有没有集群相关状态信息确认没有残留的集群标记。3.5 业务切换VIP、连接串和服务要一起改数据库实例启动只是完成了一半真正让业务恢复才是完成。原来业务连的是VIP或者连接串里配置了多个主机地址用于主备切换。拆分后这些都要改成当前单实例的真实IP。我这次就是在应用服务器上把连接串从“VIP地址备机地址”改成了“当前单实例IP”并调整了连接池配置。如果原来启用了VIP在集群停止时就应该把VIP解绑避免IP冲突。实际操作中我发现有些环境里VIP由集群管理组件自动管理集群停了VIP却还挂在网卡上。如果不手动解绑应用连接这个IP仍然能通但数据库已经不在该IP上提供服务等于有地址无服务排查起来很迷惑。同时还要检查系统的开机自启服务。原来集群节点上可能注册了集群相关的systemd服务机器重启时会自动拉起集群组件。拆成单实例后要单独把单实例数据库配置成开机自启并禁用集群组件自启。这一步不做服务器一旦重启集群组件和数据库实例可能会互相抢占资源甚至重新组集群把之前的拆分工作全部推翻。最后修改防火墙或安全组规则确保放行的IP从VIP改为实际IP和端口。很多环境在安全策略上只放通了VIP单实例真实IP没加白名单导致数据库明明起来了应用却连不上。4. 拆分过程中最容易踩的坑问题与排查实录4.1 启动直接报cluster相关错误拆分后第一次启动数据库最常遇到的就是报类似“cluster mode configure error”或“can not find CLS”的错误。出现这类报错说明配置里还有集群相关参数残留或者共享内存没清干净。排查思路很简单先grep配置文件里所有的cluster敏感词。grep -i cluster /opt/Kingbase/ES/V8/data/kingbase.conf grep -i cls_ /opt/Kingbase/ES/V8/data/kingbase.conf把找到的参数逐个确认。如果是集群模式开关改成off如果是CLS缓存参数注释掉。改完之后重启数据库基本就能解决。如果还不行就去查看共享内存残留用 ipcs 命令确认是否需要清理。4.2 端口冲突数据库端口和集群内部通信端口抢占有次拆完启动数据库数据库进程一直起不来日志显示端口绑定失败。排查下来发现是集群内部通信端口和数据库端口出现了绑定冲突。原来集群环境里除了数据库监听端口外还有内部通信使用的端口这些端口在集群模式下占用了特定的监听地址。集群停了之后有一个残留进程还在监听某个端口导致单实例绑定时失败。遇到这种问题用 netstat 或 ss 命令先查端口占用情况。ss -tlnp | grep 5432找到占用端口的进程确认不是数据库必需的进程后手动处理。如果是残留的集群管理进程把它停掉再启动单实例。这个坑的教训是拆分时不仅要看数据库进程还要看所有集群相关的辅助进程是否都退出了。4.3 备库数据缺失或WAL堆积流复制集群拆单实例时如果保留的是备库业务方可能会反馈“数据少了”。这大概率不是拆分操作导致的删数据而是备库本身就有同步延迟拆分时间点之后主库还有新事务没传过来。这种问题没有太多捷径只能做增量恢复把主库的WAL日志或归档日志拷贝到单实例节点上通过日志回放补齐数据。如果日志已经断链那就只能接受一个事实数据只能恢复到最后一个一致的日志位点。这个情况处理完之后一定要跟业务方说清楚数据时间点不能含含糊糊。还有一种情况是主库拆完之后归档目录没有及时切换导致WAL日志不断堆积。拆完后要重新核对 archive_command 是否还会尝试向旧备库地址发送归档请求。如果会就要立刻改掉否则磁盘会被日志涨满。4.4 备份和监控任务还朝着旧集群地址跑这是最隐蔽的一个坑。拆分做完后的第二天监控平台开始刷告警显示数据库备库同步异常。我登录机器一查单实例倒是跑得很正常但监控采集脚本里还保留着“检查主备状态”的逻辑定时任务还在连旧的备库地址。处理这类问题没什么技术难度难的是记得更新。我的习惯是拆分完成后把机器上的 crontab、监控agent配置、DBA运维平台里的采集项全部过一遍凡是涉及集群状态、备机地址、复制延迟的地方全部改成单实例状态下的检查逻辑或者直接停掉。4.5 节点重启后被集群组件重新拉起来拆完第二天客户重启了一次服务器结果数据库进程起来之后又尝试去连接集群里的其他节点进程状态变得很奇怪。原因就是集群组件还在开机自启列表里它不认为集群已经被拆掉了还在尝试重新组集群。解决方式是把集群管理服务的开机自启关闭只保留单实例数据库服务的自启。具体命令根据操作系统和部署方式不同有所区别在支持systemd的机器上一般就是systemctl disable cluster_service_name systemctl enable kingbase_single这个坑提醒我拆单实例不只是改数据库内部的配置操作系统层面的开机自启管理同样要同步调整。实际操作顺序应该是“先禁用集群自启再配置单实例自启最后重启验证”。4.6 复用原数据目录还是重新初始化拆单实例时优先复用原主库的数据目录。这个方案能保留用户、权限、配置、业务数据省去大量迁移工作量也是我在生产环境的首选。但如果发现原数据目录里集群残留太严重比如各种集群配置项、共享内存状态、分布式锁文件混在一起改了多次仍然启动失败那也不要死磕。可以先用本备份把数据恢复到另一个新初始化的实例上再用新实例承载业务。这个方案虽然多花了一些时间但数据目录干净后续维护起来更省心。什么情况该复用什么情况该重建我给一个自己的判断标准启动失败次数超过三次且每次都跟集群残留有关就果断走“新初始化数据导入”路线别在一条路上耗太久。5. 拆完之后要补的运维工作不是改完配置就完了5.1 监控项从集群维度改成单机维度集群模式的监控看的是主备状态、复制延迟、仲裁节点健康度、集群切换次数这些指标。拆成单实例之后这些监控项全部失效平台里会不断出现误报。因此拆分操作收敛后一定要同步调整监控策略。单实例环境下我更关注的是连接数使用率、活跃会话数、慢查询数量、磁盘空间使用率、表空间增长趋势、归档目录大小等指标。特别是连接数原来主备分担流量时主库的连接数可能只有几十现在所有应用都打到这一个实例上连接数指标必须重点盯。5.2 备份策略重建集群模式下有些备份方案依赖集群的整体状态比如先从备库备份或者通过集群快照进行一致性备份。拆成单实例后这些机制都不适用了。我的做法是拆分完成后马上重新配置备份任务用单实例支持的物理备份方式做全量备份同时配置定时归档清理策略。真正执行完第一次备份验收通过才算这部分工作闭环。5.3 向业务方同步高可用能力降级拆分之后数据库的高可用能力发生了质的变化从自动切换变为人工介入从秒级RTO变为分钟级甚至小时级RTO。这个变化一定要正式同步给业务方让他们知道现在的风险边界在哪里。我一般会输出一张简单的通知内容主要包括数据库当前为单实例运行、若发生硬件故障需人工处理、预计恢复时间、后续是否重新搭建高可用的计划。这些内容在运维群里公开同步比等出了问题再解释要主动得多。5.4 保留原集群配置和脚本为将来重建留退路拆分过程中改过的配置文件、停掉的集群管理脚本、原集群的部署参数我全部打包保存了一份。这些东西现在看起来没用等将来要重新搭建集群时就是第一手参考资料。特别是集群初始化和注册节点的过程如果当时没留文档重新排查会非常痛苦。我自己经常跟团队说一句话拆分很容易重建很难。所以拆之前的资料别删留着。最后分享一点个人体会。拆单实例这个操作本质上不是“把多余节点去掉”而是“把一个节点从集群管理体系里干干净净地摘出来”。操作本身不复杂复杂的是把那些藏得很深的关联项全部找出来处理掉配置文件里的cluster参数、共享内存的残留、开机自启的集群组件、VIP、连接串、监控脚本、备份任务。我在现场养成了一个习惯为了不出岔子把服务器当前的配置文件和业务连接方式先打印出来贴在工位旁边然后一项一项核对比记在脑子里稳妥得多。也建议你动手之前先把所有要改的位置列成清单改一项划一项再逐项验证这样即使中途被打断也不会漏掉关键步骤。
阅读完成 · 觉得有帮助?