高可用读写分离实战(二):我把数据库主库停了,结果整个集群的反应和我想象的不一样

发布时间:2026/6/27 19:28:36

高可用读写分离实战(二):我把数据库主库停了,结果整个集群的反应和我想象的不一样 高可用读写分离实战二我把数据库主库停了结果整个集群的反应和我想象的不一样 上一篇把读写分离集群搭好了本来只是想验证一下故障切换没想到最后连续做了两个多小时实验。从主库宕机、VIP漂移到读写分离和SQL路由我把整个过程都记录了下来。这篇不是官方文档而是一次真实的实验记录。“要不直接把主库停了试试”上一篇部署完成以后我一直觉得心里没底。虽然repmgr cluster show显示一切正常但总感觉少了点什么。毕竟生产环境不会因为你部署成功就真的万事大吉。晚上九点多我重新登录两台服务器打开了三个终端。一个窗口盯数据库日志。一个窗口不停执行SQL。还有一个窗口一直刷新集群状态。整个环境大概长这样。应用系统 │ JDBC读写分离驱动 │ ┌────────────────┐ │ VIP │ └────────────────┘ │ │ │ │ ┌───────┘ │ ▼ ▼ ┌────────────┐ Streaming WAL ┌────────────┐ │ Primary │ ───────────────▶ │ Standby │ │ node1 │ │ node2 │ └────────────┘ └────────────┘当时脑子里只有一个问题。如果现在把 Primary 干掉业务到底会不会中断我按下回车以后数据库居然一点反应都没有直接停止数据库。sys_monitor.sh stop执行完成以后我第一时间不是看日志而是刷新业务页面。结果页面还能打开。又执行了一条SQL。SELECTNOW();返回正常。我当时第一反应就是“不会吧是不是我停错数据库了”赶紧去服务器确认。ps-ef|grepkingbase数据库进程已经没有了。说明主库确实停了。但是业务为什么还能访问我盯着日志看了几秒。没有切换。没有漂移。什么事情都没有发生。那几秒钟我甚至怀疑自己的高可用配置是不是有问题。后来看日志我才知道数据库比我冷静得多过了几秒以后。日志终于开始刷新。内容类似下面这样。Reconnect to primary... retry 1... retry 2... retry 3...看到这里我一下子明白了。原来数据库根本不会因为一次连接失败就立刻升主。它第一件事情不是切换。而是确认。Primary到底是真的挂了还是只是网络抖了一下这一点我觉得设计得挺合理。如果网络偶尔丢两个包就开始Failover那整个集群一天不知道要切多少次。所以生产环境里慢一点反而是一种保护。 我后来还专门去调整了reconnect_attempts参数想让切换快一点。测试环境确实舒服。但想想生产环境最后还是改回来了。切得太快有时候反而不是好事。真正开始切换的时候比想象中复杂确认主库无法恢复以后集群才真正进入切换流程。我后来按照日志大概整理了一下整个过程。Primary异常 │ ▼ 持续重连确认 │ ▼ 停止接收新的WAL │ ▼ Standby结束Recovery │ ▼ 提升为Primary │ ▼ VIP漂移 │ ▼ 业务重新连接以前一直觉得高可用就是一句话主挂了备升主。真正看完日志以后才发现中间还有很多细节。尤其是WAL同步。如果最后几条日志还没有同步完成就直接升主很容易出现数据不一致。所以真正的数据库比我们想象得谨慎得多。我最关心的其实是VIP数据库什么时候升主我其实没那么关心。我真正关心的是Java程序还能不能连因为线上配置的数据库地址一直都是VIP。jdbc:kingbase://192.168.10.100:54321/test整个业务根本不知道后面是哪台服务器。于是我登录两台机器。执行ipaddr发现VIP已经从node1消失。过了几秒。出现在node2。整个过程基本不用人工参与。这也是为什么业务始终连接同一个地址却能够自动恢复。第一次看到VIP漂移的时候我终于理解以前为什么很多项目数据库切换以后Java服务根本不用改配置。实验做到这里我突然想到另一个问题业务恢复以后我本来准备结束。结果脑子里突然冒出来一个问题。现在新的Primary已经起来了。那我执行一条SELECT到底是谁在处理于是我没有停。继续做实验。打开两个数据库终端。不停执行下面这条SQL。SELECTinet_server_addr();结果还真发现了点东西。查询请求已经开始分散到不同节点。也就是说。读写分离已经开始工作了。顺手做了一次小压测没有用特别复杂的工具。直接写了一个简单测试程序。循环执行查询。for(inti0;i10000;i){jdbcTemplate.queryForObject(select now(),Timestamp.class);}同时观察两个节点。发现一个很有意思的现象。开始的时候。所有连接都集中在Primary。调整JDBC读写分离配置以后。Standby开始承担越来越多查询。CPU也慢慢降下来了。虽然只是一个简单测试。但至少证明了一件事。备库终于不是摆设了。以前它只是负责同步。现在真正开始承担查询压力。我还踩了一个特别低级的坑这里提醒一下。我第一次压测一直没成功。所有查询还是跑Primary。我还怀疑是不是数据库配置有问题。后来排查半天。发现居然是JDBC URL写错了。驱动根本没有启用读写分离模式。所以看似数据库没生效其实问题出在客户端。这种问题在线上其实挺常见。很多时候不是数据库不会工作而是客户端根本没按预期连接。我的一点体会做完这次实验我最大的感受就是很多人理解高可用都是站在数据库角度。但真正上线以后用户根本不关心数据库。他们只关心页面有没有打不开SQL有没有报错订单有没有丢查询是不是变快了所以我现在做高可用测试都会多验证几件事。✅ JDBC连接池有没有恢复✅ VIP是不是正常漂移✅ 查询是不是已经进入Standby✅ 主备数据有没有延迟这些看起来不起眼却比数据库Running更重要。写在最后这次实验本来只是想验证一下Failover。结果最后把读写分离、VIP漂移、SQL路由也一起测试了。整个过程下来我反而觉得高可用真正难的地方不是部署而是验证。因为只有亲手做一次故障演练你才知道自己的集群到底有没有准备好面对真正的生产环境。下一篇我准备把这次压测的数据整理出来重点聊聊读写分离到底能提升多少性能、哪些SQL不会走备库以及生产环境如何选择同步或异步复制。这部分也是我觉得最值得深入研究的内容。

相关新闻