大家好,我是小耶,写功课只是为了我踩过的坑,你们别再踩了!
有一次凌晨切换演练,监控大盘上所有指标都变绿了:主库失联、备库接管、切换耗时12秒。值班的同事在群里发了一句“切换成功”。
十分钟后,业务方打来电话:订单写不进去了。
登录上去看,数据库活着,能查,不能写。查同步状态,从库的SQL线程停着。查仲裁日志,切换过程中网络分区触发了保护机制,两个节点都认为自己不该接受写入。
切换动作成功了,业务恢复失败了。
这件事之后我才意识到,高可用切换的“成功”有两种,而监控大盘只认得其中一种。
先把这两层拆开:
切换动作成功——监控看到的:主库失联、备库接管、VIP漂移、切换耗时达标。这一层是编排层的成功。
业务恢复成功——应用能正常读写、数据一致、没有脑裂。这一层是数据层和应用层的成功。
大盘盯的是第一层。但用户感受到的是第二层。两层之间,隔着数据层的脑裂防护和应用层的连接残留。
一、数据层假成功:脑裂防护触发了
高可用系统最怕的不是主库挂了,是它以为主库挂了,但主库其实还活着。
网络分区发生时,备库的心跳断了,它会判断“主库已死”,发起切换。但主库那一侧的网络是好的,它还在正常接受写入。两边都认为自己是主,数据开始分叉——这就是脑裂。
成熟的数据库会在检测到这种风险时主动拒绝切换或拒绝写入。金仓KES的做法是网关仲裁:切换需要多数派节点同意,网络分区时无法达成多数派,仲裁层直接阻断切换,避免双主。共享存储架构则从根上避免数据副本分歧。
这个保护机制是对的,但它的表现是“切换报错”或“切换后拒绝写入”。 监控看到的是“切换未完成”或“切换完成但写入失败”,第一反应容易误判成“高可用坏了”。
实际上,数据库是在保护一致性——宁可报错,也不盲目切换造成数据分叉。
排查顺序:先看同步状态(从库SQL线程是否在跑、延迟多少),再看仲裁日志(是否触发了保护),最后才考虑是不是真的需要强制切换。不要一上来就重启——重启会清掉现场,仲裁日志和同步状态都没了。
二、应用层假成功:流量没真正切过去
数据层一切正常,切换也完成了,业务还是报错。问题往往在应用侧。
残留一:旧主连接没清理。 应用连接池里的连接还指向旧主。旧主虽然已经降级为从库,但连接本身是活的,应用拿着这条连接继续发写请求,被拒绝。
残留二:VIP没漂移或DNS缓存没刷新。 应用配置的是VIP或域名,切换后VIP没跟着漂移,或者DNS缓存还指向旧地址,流量根本没到新主。
残留三:连接池的验证查询没开。 连接池认为连接还活着,实际上数据库已经把这条连接断开了。应用拿到一个“死连接”,第一次请求失败。
排查顺序:确认VIP/域名解析是否指向新主,确认连接池的最大存活时间和验证查询配置,确认旧主上的活跃连接是否已经清理。这三步走完,应用层的问题基本能定位。
一个反直觉的点:演练环境和生产环境的最大差异,往往不在数据库,在应用连接池的“干净程度”。演练时应用是重启过的,连接池是干净的;实战时旧连接还在,流量还在往旧主跑。切换成功不等于业务恢复,差的就是这一步。
三、两类假成功的区分方法
| 现象 | 数据层假成功 | 应用层假成功 |
|---|---|---|
| 数据库能否连接 | 能连,但写入被拒绝 | 能连,能写,但写到了错误的地方 |
| 同步状态 | 从库SQL线程停、延迟大 | 同步状态正常 |
| 仲裁日志 | 有保护触发记录 | 无异常 |
| 应用报错 | 数据库返回拒绝写入 | 连接超时、连接已关闭 |
| 排查入口 | 同步状态、仲裁日志 | VIP/域名、连接池配置、旧主连接 |
判断顺序:先看数据库能不能写,能写就是应用层问题,不能写就往数据层查。
四、小结
高可用切换的“成功”有两层。编排层的成功,监控能看到;业务恢复的成功,得靠数据层的同步状态、仲裁日志和应用层的连接清理来验证。数据层假成功的根因是脑裂防护触发了保守拒绝,排查时先看状态别重启;应用层假成功的根因是流量没真正切过去,排查入口是VIP、连接池和旧主连接。切换报成功但业务没恢复,问题往往在这两层之间。
小耶在手,SQL 不愁
还有什么想了解的,欢迎留言!小耶一定知无不言言无不尽……我们下次见~