引言
上周生产环境一套GaussDB集群重启后,GTM状态显示Unknown,cm_ctl query -Cvpd一看是cm_agent退出了。折腾了两小时才定位到根因——运维同事之前手动kill了一个僵尸进程,不小心把cm_agent也带下去了,而om_monitor当时刚好在执行周期检测的间隔期,cm_agent在那几十秒窗口内没被及时拉起,导致本节点GTM心跳中断,cm_server判定该节点异常,触发了一连串状态告警。这件事让我意识到,对GaussDB架构和启动流程的理解不能只停留在文档层面——你得知道看护链条怎么运作、每个组件挂了什么症状、怎么快速定位。这篇文章把GaussDB的六个核心组件和启动流程掰开揉碎了讲,都是踩过坑之后的心得。
一、六个组件:不是背定义,而是要知道"它挂了会怎样"
我刚接触GaussDB的时候,看文档记了一堆缩写:OM、CM、GTM、ETCD、CN、DN。但真正用到生产环境里才发现,光知道定义没用,你得知道每个组件的职责边界在哪里、它挂了会触发什么连锁反应、恢复需要多久。下面按这个思路重新梳理。
1.OM:运维入口,平时用得多,关键时刻靠不住
OM:运维入口,平时用得多,关键时刻靠不住OM(Operation Manager)集成了一堆运维工具,gs_om -t start/stop/restart/status这些日常命令都走它。但注意一个细节:OM本身不参与集群的高可用仲裁。也就是说,OM进程挂了不会影响数据库业务,只是你暂时没法用gs_om命令了。这时候可以直接调用底层的cm_ctl来操作,所以生产环境里OM挂了不慌,先保证业务,再修OM。
2.CM:真正干活的管理层,分三个子模块
CM是整个集群管理的核心,拆开看有三个进程在跑:
cm_server—— 集群里只有一个主,主备架构。它做的事情很简单:收集所有实例的心跳 → 存到ETCD → 分析状态 → 决定谁做主谁做备 → 下发切换指令。cm_server挂了会怎样?备cm_server会在心跳超时后(默认大约几十秒)自行仲裁升主,优先选节点号小的那个备。只要ETCD多数派还在,切换就能完成。cm_server切换期间,集群管理功能暂停,但数据库读写不受影响——这是很多人误解的地方,以为cm_server挂了数据库就挂了,其实不影响。
cm_agent—— 每个节点一个,是cm_server的"手脚"。它干两件事:一是定时采集本节点所有实例(GTM、CN、DN)的状态上报给cm_server;二是接收cm_server下发的指令去启停实例、做主备切换。cm_agent挂了,本节点的所有实例就"失联"了——cm_server收不到心跳,会判定这些实例状态异常,可能触发不必要的主备切换。所以cm_agent的优先级最高,由om_monitor专门看护。
om_monitor—— 一个定时任务进程,唯一职责就是看护cm_agent。cm_agent死了它负责拉起,它自己死了由系统crontab负责拉起。这个三级看护链条(crontab → om_monitor → cm_agent → 实例)是GaussDB自愈机制的底座,缺一不可。
3.GTM:全局事务ID发号器,挂了会影响写操作
GTM负责生成全局事务ID(GXID)、全局快照、时间戳。分布式事务开始时,CN会先向GTM申请一个全局事务ID,然后才能往下执行。所以GTM挂了的影响是:新事务无法启动,读写操作都会卡住。但已有的事务不受影响,可以继续执行完。
GTM也是主备架构,主挂了会切备(优先切高优先级AZ的备)。切换过程一般需要几秒到十几秒。实际生产中,如果业务对中断时间敏感,建议部署多个GTM备机分散在不同AZ。
4.ETCD:集群状态的"账本",
多数派没了集群停摆
ETCD存了所有组件的实时状态:谁主谁备、各实例的心跳信息、集群拓扑配置。cm_server做仲裁决策时,所有判断依据都从ETCD读。所以ETCD是GaussDB最不能挂的组件,它的优先级甚至高于cm_server。
ETCD内部用raft算法实现分布式一致性。关键点:
ETCD集群必须有奇数个节点(3个、5个等),才能形成多数派
需要额外规划一个仲裁AZ,AZ3作为仲裁AZ,在1个AZ故障状态下,保证ETCD的存活节点超过多数,从而保障数据库集群仍可正常仲裁
ETCD leader挂了,follower会发起投票,获得多数票的升主
如果ETCD多数派节点同时挂了,整个集群管理功能冻结,cm_server无法做任何仲裁决策
5.CN:SQL入口,挂了不影响读已缓存的数据
CN是所有客户端的连接入口,负责SQL解析、生成执行计划、汇总DN返回的结果。一个GaussDB集群可以部署多个CN,它们之间完全对等,一个CN挂了客户端连另一个就行。
但要注意两个细节:
DDL操作需要所有CN参与(因为CN上有表的元信息缓存),如果有一个CN挂了且25秒内拉不起来,CMS会把它剔除,这期间DDL执行会被阻塞
CN挂了之后,已经连在这个CN上的会话会断开,但其他CN上的会话不受影响
6.DN:数据节点,真正干活的
DN是数据存储和计算的实际执行者。数据按shard分布到多个DN上,每个shard有1主多备(默认1主3备)。DN的主备复制用Quorum机制:日志必须在多数派(含主)上落盘,事务才能提交。这意味着:
少数派备机挂了 → 主DN继续工作,不受影响
多数派挂了(比如1主3备里主+1备挂了,只剩2备)→ 主DN无法形成多数派确认,事务提交被阻塞,业务卡住
cm_server仲裁DN主备切换时,会从半数以上存活的备机中选择日志量最全(LSN最大)的那个升主。这个设计保证了切换后的新主数据最全,不会丢数据。
二、启动流程:七个步骤,一步都不能跳
GaussDB集群启动不是systemctl start gaussdb这么简单,它有严格的启动顺序。理解这个顺序,排障的时候才能知道该看哪里。
1.启动链条(从底到顶)
2.实际排查时怎么看
gs_om -t status,cm_ctl query -Cvipd的输出按这个顺序看。正常的输出大概是:
排障时按从底到顶的顺序检查:
3.Step 1~3: 看护链是否正常
这三步有问题,后面的组件一定起不来。我那次GTM状态Unknown的故障,根因就是cm_agent被人手动kill掉了,om_monitor刚好在检测间隔期没及时拉起,本节点GTM心跳中断,cm_server判定异常,状态全部变Unknown。
4.Step 4~5: cm_server和ETCD
ETCD必须全部Healthy或者至少多数派Healthy。如果ETCD有问题,cm_server的日志里会看到大量连接ETCD失败的报错。
5.Step 6~7: GTM、DN、CN
cm_server仲裁确定好主备关系后,实际启动动作由cm_agent执行。所以GTM/DN/CN起不来,首先怀疑cm_agent是否正常——cm_agent挂了,本节点所有业务实例都无人看护。看gs_om -t status里的state列判断各实例状态。如果DN状态是Manually stopped或者Unknown,说明cm_agent尝试过拉起但没成功,需要去对应节点的日志里查原因。
三、故障恢复:每个组件谁看护、谁仲裁、怎么切
GaussDB的故障恢复设计非常精细,每个组件都有明确的看护关系和仲裁逻辑。下面按组件逐个拆解,全是生产环境里需要烂熟于心的知识点。
1.Monitor:进程故障由crontab系统
定时任务拉起
om_monitor是整个看护链条的起点。它自己挂了由crontab兜底,cm_agent挂了由om_monitor拉起。这条链任何一个环节断了,后面的自愈机制全部失效。
2.CMAgent:进程故障由Monitor拉起
cm_agent挂了 → om_monitor检测到 → 自动拉起cm_agent。cm_agent是所有实例的统一看护人,本节点上GTM、DN、CN的进程状态都由cm_agent监控并上报cm_server。cm_agent是整个集群自愈机制的底座,优先级最高。
3.CN:进程故障由CMAgent自动拉起
cm_agent先尝试拉起CN进程
拉不起的话,cm_server会仲裁剔除该CN(25秒超时)
CN被剔除后会阻塞DDL执行(因为DDL需要所有CN参与元信息同步)
通过CN节点加回操作可以恢复故障CN
CN没有主备概念,一个CN挂了其他CN还能继续提供查询服务
4.DN:进程故障由CMAgent自动拉起
cm_agent先尝试拉起DN进程
拉不起的话触发主备切换
cm_server仲裁从半数以上存活DN中选择日志量最全(LSN最大)的节点升主
采用1主3备或1主5备方式部署
日志在多数派DN上落盘之后事务才提交
备机故障(少数派)不影响主机业务
新主起来后,其他备机自动追日志同步
故障DN修复后可以作为新备机重新加入集群
5.GTM:进程故障由CMAgent自动拉起
cm_agent先尝试拉起GTM进程
拉不起的话触发主备切换
优先选择高优先级AZ的GTM备机升主
备机故障不影响主机业务
只要有一个GTM主就不影响业务(新事务需要向GTM申请全局事务ID)
6.CMServer:进程故障由CMAgent自动拉起
cm_agent先尝试拉起cm_server进程
拉不起的话触发主备切换
CM备发现CM主心跳超时,CM备自行仲裁新主
优先选择节点号较小的cm_server备机升主
只要有一个CMS主就不影响业务(切换期间集群管理功能暂停,但数据库读写不受影响)
主备仲裁依赖ETCD:备cm_server尝试在ETCD中写入自己的信息,谁先写入谁升主
7.ETCD:进程故障由CMAgent自动拉起
om_monitor先尝试拉起ETCD进程
ETCD采用raft分布式一致性算法
如果主节点(leader)故障,备节点(follower)发起投票,获得多数投票的(candidate)升主
故障节点恢复之后成为(follower)
2AZ部署时(每个AZ部署同样个数ETCD),需要额外一个仲裁AZ(部署奇数个ETCD),确保有一个AZ故障时,ETCD可以多数派选主
ETCD主要作用有两个:
利用共识算法来存储集群状态信息
用于cm_server主备状态判断(故障时先写入ETCD的升主)
DN主备仲裁主体由cm_server完成,会依赖ETCD中保存的数据(如term值)
3.一句话总结各组件故障影响
组件 | 看护人 | 仲裁者 | 切换策略 | 对业务的影响 |
om_monitor | crontab | — | 自动拉起 | 无直接业务影响 |
cm_agent | om_monitor | — | 自动拉起 | 本节点实例失联,可能误触发切换 |
cm_server | cm_agent | ETCD写入 | 节点号小的备优先升主 | 管理功能暂停,读写不受影响 |
ETCD | cm_agent | raft投票 | 多数派选举 | 多数派没了集群管理冻结 |
GTM | cm_agent | cm_server | 高优先级AZ备升主 | 新事务无法启动,已有事务不受影响 |
DN | cm_agent | cm_server | LSN最大的备升主 | 少数派故障不影响,多数派不够事务阻塞 |
CN | cm_agent | cm_server | 25秒拉不起就剔除 | DDL被阻塞,查询不受影响 |
四、实战中的四个血泪教训
1.教训一:kill进程前先确认是不是
看护链上的组件
我那两个小时就浪费在这上面。运维同事在清理僵尸进程时用了kill -9,没注意把cm_agent也带下去了。cm_agent是om_monitor看护的,但om_monitor的检测有周期间隔(默认几十秒),cm_agent刚好死在这个间隔窗口里,没被及时拉起。那几十秒内GTM心跳没上报,cm_server判定异常,状态全部变Unknown。排查时翻来覆去看了GTM日志、cm_server日志,最后才发现是cm_agent进程没了。现在清理进程之前,必须先ps -ef | grep cm_agent确认一下,看护链上的组件一个都不能动。
2.教训二:ETCD节点数必须是奇数,
2AZ部署别忘了仲裁AZ
ETCD集群必须有奇数个节点(3个、5个等)才能形成多数派。2AZ部署时,如果两个AZ各放同样数量的ETCD节点,一旦其中一个AZ整体故障,剩下的AZ节点数可能构不成多数派,导致ETCD无法选主,整个集群管理功能冻结。这时候需要额外加一个仲裁AZ,部署奇数个ETCD节点,确保任意一个AZ挂了还剩多数派。这个仲裁AZ只跑ETCD,不跑业务,很多项目前期规划时容易漏掉。
3.教训三:DN多数派的计算要心里有数
1主3备的部署,多数派是3(含主)。也就是说:
挂了1个备 → 还剩1主2备,仍能形成3个多数派,不影响
挂了主+1个备 → 还剩0主2备,多数派不够,事务阻塞
挂了2个备 → 还剩1主1备,多数派不够,事务阻塞
1主5备的部署,多数派是4(含主),能容忍更多的故障。金融核心系统建议1主5备,普通业务1主3备够用了。
4.教训四:CN剔除后要尽快恢复
CN被剔除后DDL会被阻塞。如果业务有频繁的建表、改表操作,影响会很大。建议在告警策略里给CN状态加个告警,一旦CN被剔除立即通知DBA处理。
总结
GaussDB的架构设计思路很清晰:每一层都有上一层看护,最底层由操作系统定时任务兜底。这个链条是 crontab → om_monitor → cm_agent → cm_server → 业务实例,任何一个环节断了都有恢复机制。
日常运维中,理解这套启动依赖和故障恢复优先级,能让你在遇到问题时快速缩小排查范围。记住这个口诀:
• 集群起不来,从底往上查(crontab → om_monitor → cm_agent → cm_server → ETCD → 业务实例)
• 实例挂了看cm_agent能不能拉起,拉不起等cm_server仲裁切换
• ETCD多数派在,集群就不会彻底瘫
• DN多数派不够,事务就提交不了
下次生产环境出问题,别慌,按这个链条一步步查,基本都能定位到根因。
END