开工第一天收到生产告警PolarDB 集群的只读节点连接失败率直接飙到红色。起初我还以为又是网络波动随手把监控图放大一看从节点整个处于不可用状态应用侧大量“无法连接数据库”的报错堆满了日志。大过年的遇到这种情况属实有点“开年就丢人”。但问题已经发生了与其在那尴尬不如趁这次机会把从节点不可用的常见原因和排查思路彻底梳理一遍避免以后再踩同一个坑。这篇文章就围绕 PolarDB 的从节点也叫只读节点、备节点展开结合我一个真实排障过程的复盘讲清楚从节点为什么会“不能用”、怎么一步步定位根因、以及如何提前预防。无论你是 DBA、后端开发还是运维工程师只要你的业务在用 PolarDB 做读写分离或高可用这篇文章的内容都值得收藏备查。1. 从节点在 PolarDB 中扮演什么角色为什么“不能用”是大事1.1 从节点是什么为什么不能只靠主节点PolarDB 作为一个云原生数据库一个集群通常包含一个主节点和若干个只读节点。主节点负责写入同时也可以提供读能力只读节点则通过复制主节点的数据来提供扩展的读能力同时参与高可用切换。在业务里我们通常会把读流量分到只读节点上减轻主节点的压力。这里的“从节点不能用”可不是小事。因为很多业务的读请求是直接打到只读节点上的一旦它挂了那些读流量要么转移到主节点导致主节点压力上升要么直接报错失败影响线上可用性。更麻烦的是如果主节点发生故障需要切换从节点通常会被晋升为新的主节点如果从节点本身数据不完整或者状态不正常切换就会失败整个集群可能就瘫痪了。1.2 从节点“不能用”的几种典型表现我们所说的“不能用”在实际情况里往往有不同的表现形式我把常见的归一下类连接类客户端连接从节点时提示超时、拒绝连接、认证失败或者连接上之后很快断开。状态类控制台上从节点显示“不可用”“重启中”“异常”或者健康检查失败。性能类连接是通的但一个简单查询就卡住响应时间越来越长最终超时看起来像假死。数据类从节点能连上但查询到的数据和主节点不一致有明显延迟或者同步状态显示中断、报错。不同的表现对应的排查方向完全不同。如果不先把这个分类搞清楚一上来就胡乱重启节点大概率还会踩坑。1.3 先从分层视角大致定位问题范围我自己的习惯是不管报错信息多么吓人先按“网络层 - 实例层 - 同步层 - 数据层”这四层去套一遍把问题范围缩小。网络层看的是客户端和从节点之间的链路通不通实例层看的是从节点所在的数据库实例本身有没有异常同步层看的是主从复制链路是否健康数据层看的是数据一致性和查询结果是否正常。每一层都有对应的监控指标和排查工具。下面我就按这个思路把完整的排查路径拆开来讲。2. 排查从节点不可用的核心路径2.1 第一步从控制台状态和监控指标入手无论报错是什么先打开 PolarDB 的控制台看集群的基本信息。重点关注从节点的实例状态是“运行中”还是“异常”以及最近有没有发生过切换或重启。这个步骤看起来简单但能直接过滤掉一大半问题。然后看监控指标不要只看 CPU要把以下几项一起拉出来看CPU 使用率如果持续 100%说明从节点上可能有慢查询或满负载任务。内存使用率内存耗尽会导致无法分配新会话甚至触发 OOM。连接数是否打满连接数超过 max_connections 时新的连接会被直接拒绝。磁盘使用率和磁盘 I/O磁盘满会导致数据库无法写入同时在崩溃恢复时可能有大量 IO 操作。网络带宽和公网流量如果开了公网访问还需要看是否被 DDoS 或恶意扫描打爆。正常情况下这些指标曲线应该是平缓有规律的。一旦看到某个指标贴着上限跑问题基本就有了方向。2.2 第二步检查网络连通性和安全配置如果控制台显示从节点运行正常但客户端连不上那就优先怀疑网络层。先用最简单的工具验证一下连通性。假设从节点的内网地址是 10.0.0.5在能访问到它的网络环境里执行telnet 10.0.0.5 3306如果端口不通说明网络策略或者安全组有问题。PolarDB 控制台里通常有白名单和安全组配置你得确认客户端机器的 IP 是否在从节点所属集群的白名单里。如果白名单没加正确连主节点也会失败但很多场景里主节点白名单和从节点是分开的或者做读写分离时各实例的访问地址不同极容易漏配。如果是通过内网访问确认客户端和数据库是否在同一个 VPC 和交换机下路由表是否正常。如果通过公网访问还需要确认公网白名单和端口是否放开有些云厂商默认不开放公网入口需要单独申请。在这一步里我经常遇到的情况是有人只写了主节点的白名单忘了从节点也有人把从节点的地址写成了另一个可用区的 IP导致跨区域访问延迟高得像断连。2.3 第三步审查主从同步状态如果网络没问题连接能建立但客户端读到的是“从节点数据不对”或“同步延迟过大”那重点就在同步状态。PolarDB 的只读节点和主节点之间本质上是基于日志的复制机制。你可以通过 SQL 查看复制状态。如果底层兼容 MySQL可以执行类似下面的语句具体名称可能随版本有所差异但思想一致SHOW SLAVE STATUS\G -- 关注以下字段 -- Slave_IO_Running: Yes -- Slave_SQL_Running: Yes -- Seconds_Behind_Master: 0在 PolarDB 的某些版本或控制台上你可能会在“只读节点信息”里看到“复制延迟”“复制状态”这样的指标。只要复制线程没有正常运行或者 Seconds_Behind_Master 数值持续增大从节点的数据就一定处在过期状态。这时候哪怕连接正常对业务来说也算“不能用”。更要警惕的是复制线程反复中断。如果 Slave_SQL_Running 显示 No通常说明 SQL 线程执行出错可能是在从节点上执行某个语句时遇到主键冲突、表不存在、字段不一致等问题。一旦同步断裂从节点就会停留在错误时刻的数据视图上必须人工介入处理。2.4 第四步翻日志和慢查询定位“假死”根因如果状态显示正常复制也正常但查询就是慢得像卡死那就得看日志和慢查询了。PolarDB 控制台一般提供错误日志、慢日志、审计日志。先看错误日志里面可能会有 OOM、死锁、连接超限、复制中断等关键信息。再看慢查询日志重点找那些执行时间特别长、扫描行数特别多的 SQL。这里我有一个习惯排障时不要只把慢日志按执行时间排序还要看“执行频率”。有些 SQL 单次执行可能只花几百毫秒但如果每秒被调用几百次累积起来一样能把从节点的 CPU 打满。低频大查询和高频小查询都要排查不能只看单条耗时。日志看完后还可以在从节点上执行 SHOW PROCESSLIST 查看当前所有正在执行的会话看看有没有长时间处于 Query、Sending data 或其他状态的进程。如果有拿到 Thread ID 之后可以通过 kill 掉异常会话应急处理但千万别乱杀务必确认它是不是业务核心事务。3. 从节点不可用的常见根因与解决思路3.1 主从同步中断或同步异常导致数据不可用这是从节点“不能用”里比较让人头大的一种。同步中断通常有几个原因主节点上有大事务长时间未提交导致 binlog 没有被及时应用从节点延迟拉高甚至超时判定为中断。从节点上执行了与主节点冲突的操作比如有人手动在从节点上创建了一张同名的表或者修改了数据导致复制 SQL 执行报错。网络分区或主从节点之间的链路不稳定导致 I/O 线程断连。解决同步中断我的建议步骤是先用SHOW SLAVE STATUS或对应的控制台指标确认是 I/O 线程断还是 SQL 线程断。如果只是网络抖动导致 I/O 中断通常网络恢复后会自动重连。如果 SQL 线程报错先查看具体的 Error 信息确认是不是有人为修改。如果是误操作需要清理干净冲突的对象或数据然后重新开始同步。这个过程要谨慎最好由有权限的 DBA 操作并且提前备份。如果是大事务导致延迟不要急着重启从节点先让主节点压力缓解给它时间追回进度。同时考虑在应用侧临时把读流量切到主节点或备用只读节点。这里最关键的觉悟是从节点不是垃圾桶不能在它上面做任何非只读操作。我在实际项目里真的见过有同事为了“试试语句效果”直接在从节点上建了个索引结果复制线程立刻中断全公司的读请求都雪崩了。记住只读节点就是只读任何写操作请在主节点完成。3.2 只读节点负载过高被慢查询打爆我遇到的从节点不可用案例里大约有一半是因为慢查询把资源耗尽。原因往往是某个新上线的报表查询或者忘了加索引的常用查询被路由到了从节点。它本身只是一条 SQL但执行计划走了全表扫描扫描行数上千万一下子把从节点 CPU 拉到 100%。更麻烦的是从节点资源被打满后复制线程也分不到足够的 CPU 来应用日志于是延迟越拉越大最终从节点上的数据变成“旧数据”业务读到的都是过期的看起来就跟不能用一模一样。这类问题的排查相对直接通过慢日志找出罪魁祸首然后EXPLAIN分析执行计划看看有没有走索引、扫描行数是否合理。解决手段无非就是如果没有合适索引先创建索引注意在主库上建然后同步到从节点。如果 SQL 逻辑过于复杂考虑改写 SQL 或者用物化视图、汇总表来支撑报表查询。如果确认是临时性的大查询可以在数据库端设置超时时间或者在中间层限流避免单个请求占死整个实例。我在一次排障中还发现从节点上的连接池参数被调得过大应用为了并发性能给从节点创建了上千个连接。虽然每个连接占用的资源不算多但上千个连接同时活跃查询内存直接爆掉最后 OOM。所以连接数监控非常有必要不能只看 CPU。3.3 集群变更操作导致从节点短暂重启还有一种常见但很容易被忽略的情况维护窗口期内给 PolarDB 集群做规格变更、内核升级或参数修改这些操作大概率会引起节点的重启或切换。如果业务侧没有配置连接重试机制数据库重启的几秒到几十秒窗口内应用会直接报连接失败。这个问题的特征是报错时间点和变更窗口吻合而且监控上看从节点在重启前曾有“实例状态”变为“重启中”之后又自动恢复。解决思路比较简单尽量在业务低峰期做集群变更。应用层必须配置连接池和重试机制不能把数据库连接当成永远可用的长连接。在变更前先手动检查一遍只读节点有没有积累大量未完成的事务确保重启后复制能正常追齐。我在工作中就吃过没配置重试的亏。线上某个服务用的连接池检测心跳间隔特别长数据库一重启连接池没及时剔除失效连接所有请求都卡在旧连接上整整过了几十秒才算缓过来。后来把testOnBorrow、重试次数、超时时间都调了才好很多。这些参数虽然不直接存在于数据库里但它是让数据库变更对业务“无感”的保障。3.4 账号权限和访问白名单配置坑从节点连接不上有时候和数据库实例本身一点关系都没有纯粹是配置问题。最常见的两个坑分别是账号权限不足在 PolarDB 中主节点和只读节点的账号权限可能是分开管理的。有些账号只被授予了主节点的读写权限没有授予只读节点的查询权限或者某些高权限账号默认只能从主节点访问没有开启从节点访问能力。这时候连接从节点会报类似Access denied for user ...的错误。白名单或安全组遗漏前面提过这里再强调一遍。特别是当你有多个只读节点时白名单配置容易漏加。还有一个细节如果业务用了高可用虚拟 IP 或者负载均衡器转发读流量还需要把 LB 的 IP 也加入到白名单否则从节点同样连不上。遇到连接失败不要老想着重启节点先用自己的 MySQL 客户端手动试一下mysql -h 从节点IP -P 3306 -u 账号 -p如果手动能连上说明问题在业务侧的连接配置如果手动也报错再撸起袖子查网络和权限。3.5 磁盘满或内存 OOM 导致的实例级故障只读节点也是数据库实例同样有磁盘和内存限制。当它的数据文件、日志文件、临时文件把磁盘占满后整个实例会进入不可写甚至不可读状态。有些场景下磁盘满还会导致复制中断因为中继日志relay log写不进去。磁盘满的紧急处理方式先清理日志比如删除过期的慢查询日志、审计日志、临时文件。但注意数据库数据文件绝对不能乱删。对大表做归档或清理时不要把压力打到从节点上要从主节点规范操作。扩容磁盘是最稳妥的兜底方案。云数据库一般支持在线扩容可以先扩容争取时间再慢慢定位是什么占满了磁盘。内存 OOM 相对隐蔽一些。当从节点的内存使用率持续上升最终进程被操作系统杀掉时控制台会显示实例异常需要重启才能恢复。这种情况一般和连接数过多、缓存命中率低、大量排序或临时表有关。解决思路是把内存参数调优比如缓冲区大小、临时表大小以及在应用侧控制慢查询。4. 实操记录一次从节点“假死”的完整排查过程说了这么多理论还是用一个我自己遇到过的排障案例把它们串起来更有参考价值。4.1 现象描述某天早上 10 点业务方反馈后台报表页面打开超时查数据库的读写分离链路发现所有读请求都报“Lost connection to MySQL server during query”。监控上看PolarDB 集群的主节点一切正常但其中一个只读节点 CPU 100%连接数飙升并且复制延迟从几十秒涨到了上千秒。一开始我第一反应是只读节点是不是挂了。于是打开控制台发现只读节点状态仍然显示“运行中”没有重启记录。但它确实已经无法正常服务属于典型的“假死”状态——进程还在但资源被耗尽什么请求都处理不了。4.2 分步排查过程第一步我先把所有读流量从故障只读节点切走让应用连接到另一个健康的只读节点或者暂时切到主节点保证业务先恢复。这一步非常重要任何排障都不能让业务一直在受损状态下陪着我们分析。第二步登录故障只读节点执行SHOW FULL PROCESSLIST发现里面有大量会话处于Sending data状态且都集中在同一个 SQL 模式。我把这个 SQL 捞出来一分析发现是一条对订单明细表做统计的查询关联了多张大表但没有走索引。第三步看慢查询日志发现这条 SQL 在过去一个小时里已经执行了上百次每次扫描行数超过 5000 万行平均执行时间 35 秒。正常情况下它应该在 1 秒内完成。为什么执行计划这么差我使用EXPLAIN一看优化器选择了一个完全错误的驱动表把大表当成小表去驱动结果产生了海量的中间结果集。造成这个错误执行计划的根因是统计信息过期。这个订单明细表数据量在快速增长但优化器使用的统计信息还停留在很久以前低估了表的行数。于是优化器选了错的方向。4.3 找到根因并恢复我先是针对问题 SQL 加了必要的索引在主库加上等待同步然后执行了ANALYZE TABLE 订单明细表;更新统计信息之后再用EXPLAIN验证执行计划的驱动表已经变了SQL 扫描行数降到了百万级以下执行时间从 35 秒压到 0.4 秒。接着我把之前杀掉的异常会话清理干净等只读节点 CPU 降下来后重新恢复读流量到它上面。复制延迟也随之逐渐追平集群回到正常状态。整个排查过程花了大概 40 分钟真正定位根因只占了 10 分钟大部分时间都花在确认“不是网络”“不是同步中断”“不是配置错误”上了。但正因为前面按层排查排除了那些常见原因后面才能确定问题出在慢查询和执行计划上。4.4 事后加固和预防措施这个案例让我意识到从节点“不能用”很多时候不是数据库自己坏了而是上层业务行为把它“拖垮”了。事后我做了几个预防措施在监控里单独建立了只读节点的慢查询数和预期执行时间告警一旦某个 SQL 的平均执行时间超过 3 秒就触发提醒。在业务层给读请求设置合理的 SQL 超时时间比如 10 秒避免单条慢查询无限占用连接。定期用定时任务对高频写入的大表做ANALYZE TABLE防止统计信息过期影响执行计划。调整连接池参数限制到从节点的最大连接数并启用空闲连接的回收机制。这些措施并不复杂但能有效防止同类问题再次发生。数据库本身的稳定性是一方面更重要的还是入口流量和 SQL 质量的管控。5. 运维避坑建议与从节点健康速查表5.1 排障过程中的常见误区排查从节点不可用时我踩过几个坑也见过别人踩在这里共享一下不要轻易重启实例。如果根因是复制中断或者大事务重启只会让情况更糟。先确认对其他节点的影响再做决定。别忽略了从节点之间的差异。当你有多个只读节点时它们不一定是完全一样的规格和状态。比如一个只读节点配置较低用来承接大查询就容易宕另一个配置高同样的 SQL 没问题。排查时要把节点差分出来看。别只盯着 CPU。磁盘满、连接数满、内存 OOM 经常被 CPU 曲线所掩盖。我的习惯是每次排障先把所有关键指标截图再挨个看。不要在从节点上直接改数据或建索引。前面说过这会直接导致复制中断。哪怕只是执行一条UPDATE也会造成不可预估的后果。5.2 从节点快速排查速查表我把自己常用的排查路径做成一个速查表方便大家在实际中照着做。排查阶段核心操作或指标问题指向实例状态控制台查看节点状态、是否存在重启记录节点重启、异常停顿网络连通性telnet测试端口检查白名单、安全组、VPC 路由网络策略、防火墙、路由问题账号权限手动连接测试检查账号是否被允许访问从节点权限配置、账号标识连接资源当前连接数、max_connections、processlist连接数打满、连接池配置系统资源CPU、内存、磁盘、IO 监控曲线资源耗尽、磁盘满、OOM复制链路SHOW SLAVE STATUS或控制台复制指标同步中断、延迟大慢查询日志执行时间、扫描行数、执行频率慢 SQL、缺少索引、统计信息过期错误日志查看 OOM、死锁、复制错误信息数据库内部异常每条思路都对应着一个“如果这里正常就去看下一层”的判断。不需要一次全查多按步骤来效率反而会高很多。5.3 如何从源头避免“开年丢人”数据库出问题不可怕可怕的是从来没提前准备过应对方案。经过这件事我给自己的运维工作立了几条规矩每个月至少做一次从节点状态巡检内容包括复制延迟、磁盘空间、慢查询数量、连接数峰值。每次业务大版本上线前评估一下对只读节点的影响尤其有没有新的查询会落到只读节点上SQL 是否走了索引。所有新员工或所有有数据库访问权限的同事都明确知道从节点上只能读不能写所有变更操作都必须走主节点或提工单。只要你把这些基础动作做扎实了从节点“不能用”的概率会大大降低。而且即便真的遇到问题排障流程也能让你做到心中有数不用手忙脚乱。6. 写在最后的经验之谈这次“开年就丢人”的排障经历让我对 PolarDB 从节点高可用和运维有了更深的体会。其实很多从节点问题并不是数据库本身不稳定而是我们平常对这个节点的关注度不够。主节点出了问题大家会第一时间响应但只读节点长期处在低关注度的状态等到业务流量一剩慢查询一堆积问题暴露的时候就已经很严重了。我个人现在的习惯是把从节点当成和主节点一样重要的生产资源来对待。监控指标不只覆盖存活状态还包括资源水位、复制延迟、SQL 质量。这样做了之后再也不会有“从节点突然不能用”的措手不及感。最后再分享一个小技巧如果你在对从节点排障时实在没有头绪就在高可用层面提前准备好一个“备用只读节点”。很多云数据库都支持快速增加只读节点成本不高但能让你在问题爆发时多一条退路。毕竟应急方案的价值不在于它有多优雅而在于关键时刻它能顶上。希望这篇排障实录能帮到正在为 PolarDB 从节点头疼的你。有问题欢迎在评论区交流我会把自己踩过的坑继续分享出来。
阅读完成 · 觉得有帮助?