ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

PolarDB只读节点故障排查实战:从复制链路中断到根因修复

PolarDB只读节点故障排查实战:从复制链路中断到根因修复 开年第一个工作日我还在工位上对着日历感慨假期过得太快手机上的告警群就炸了。线上业务反馈PolarDB MySQL版的只读节点连不上了应用侧所有读流量全部超时报错。我那一瞬间脑子是蒙的配置没动过、版本没升过、前几天还做了压测怎么会开年第一天就“丢人”后来一步步排查下来发现“从节点不能用”这句话背后藏的坑远比表面上的连接失败要深得多。这篇文章就把这次完整的过程记录下来从原理到排查到根治给同样在用PolarDB或其他云数据库主从架构的同学一份可以直接抄作业的参考。1. 故障现场还原开年第一天只读节点“失联”了1.1 从节点为什么重要它挂了比你想象的影响大先说清楚一个概念。PolarDB这种云原生数据库核心架构是计算与存储分离一个主节点负责写入一个或多个只读节点负责扩展读能力。业务侧一般会把读多写少的流量拆开写流量走主节点报表查询、列表页、数据分析这些走只读节点。只读节点一旦不可用最直接的影响是所有依赖只读地址的查询全部失败应用侧如果在代码里没有做降级或者超时熔断很容易把主库的连接池也拖垮进而引发整个业务链路雪崩。所以“从节点不能用”这件事从来不是只读库自己的事它直接影响线上可用性。这次故障的现场是业务A的订单查询接口开始抛ERROR 2003 (HY000): Cant connect to MySQL server业务B的报表任务直接报连接超时监控大屏上只读节点的CPU使用率曲线直接掉到0主节点的CPU反而因为读流量全部挤压过来上涨了30%左右。这就是典型的“只读节点失联后读流量打回主库”的连锁反应。1.2 这次的故障现场记录事情发生在上午10点出头具体的告警明细大概是这样的只读节点1的TCP连接数在5分钟内跌到接近0之前稳定在200左右。主节点CPU使用率从40%跳到70%以上活跃会话数从30涨到120。应用侧日志大量出现Access denied for user、Connection refused和Connection timed out三种不同类型的报错。PolarDB控制台里只读节点状态显示“运行中”但没有报“异常”从监控上看到复制延迟的指标曲线变成了空的这非常反常。我当时第一反应是检查是不是有人改了白名单或者账号权限查了一圈发现都没有。又怀疑是不是只读节点自己发生了主备切换但控制台没有切换记录。最后是从一条“隐藏”的复制链路日志里找到了突破口这条链路的状态才是真正决定只读节点能不能服务的命脉。这一块我在第4节里详细拆。2. 排查前必懂的原理PolarDB主从架构与复制链路2.1 计算存储分离下的节点分工要排查“从节点不能用”先得搞清楚PolarDB的节点分工和同步机制。PolarDB的架构里存储层是分布式共享存储主节点和只读节点其实访问的是同一份数据文件这跟传统MySQL那种主库复制binlog到从库、从库自己落盘一套数据是完全不同的模型。打个比方传统主从是主库把“每天发生的所有操作日志”抄给从库从库照着日志自己重新做一遍PolarDB更像是主库和只读节点共用同一张巨型草稿纸主库在草稿纸上写新的内容只读节点只需要把主库新写的那部分内容“同步”到自己能看到的位置就行。这个同步动作依赖的就是PolarDB的物理复制机制。主节点把数据页面的物理变更产生的Redo日志持续复制给只读节点只读节点拿到Redo日志后在内存里做数据页面的回放更新自己持有的数据版本视图。因为存储是共享的所以只读节点不需要像传统从库那样维护一套完整的数据副本它更多的是在“追”主库的Redo日志位点。这也是为什么PolarDB只读节点的“复制延迟”一般能做到毫秒级远远低于传统主从架构。但也正因为如此一旦Repro日志同步链路出问题只读节点拿不到最新的数据位点就会直接影响它对外提供读服务的能力。2.2 同步链路与延迟从哪看在PolarDB的控制台或者通过SHOW REPLICA STATUS如果是兼容MySQL 8.0语法能看到复制链路的实时状态。核心字段有几个Slave_IO_Running表示IO线程是否在正常拉取主节点的Redo日志。这个线程如果断了最直接的表现就是只读节点拿不到新数据。Slave_SQL_Running表示SQL/回放线程是否在正常应用Redo日志。这个线程如果卡住Redo日志堆积就会越来越大复制延迟持续上涨。Seconds_Behind_Master或Replica_IO_Thread_Running相关的延迟指标表示只读节点落后主节点的秒数。PolarDB里这个值通常很小一旦超过某个阈值就需要警惕。复制报错的Last_IO_Error和Last_SQL_Error字段这两个字段是故障时的“第一现场”记录了复制链路中断的具体原因。除了这些MySQL兼容性视图PolarDB控制台还会有PSLPolarDB Serverless/物理复制相关的基础监控指标包括Redo日志的接收量、回放速率、复制延迟时间曲线。这次故障里延迟曲线变成“空”而不是出现明显延迟是因为IO线程直接中断了连延迟计算的基准都没了。如果只盯着Seconds_Behind_Master看反而容易被误导。2.3 连接流量分配哪里断了才叫“从节点不能用”“从节点不能用”需要拆成两个层面看一个是“它本身活着但连不上”另一个是“它已经无法对外提供服务”。前者大概率出在连接链路比如白名单、账号权限、连接串、网络策略后者大概率出在复制链路比如Redo同步中断、节点角色异常、内部状态机卡住。这两个层面是独立的也可能同时发生。比如这次PolarDB控制台里显示只读节点“运行中”但复制链路实际已经断了。节点本身的计算进程还在但它内部的数据版本静止了系统会把它标记为“无法提供最新读能力”的状态然后摘掉它的读写流量。如果应用连接池里还持有到这个节点的空闲连接就会表现为连接超时或直接拒绝。所以排查的时候光看节点运行状态是不够的必须看复制链路的健康状态和连接访问链路的健康状态两条线一起查。3. 从节点不可用的常见原因先做减法再定位根因3.1 连接层的坑账号、白名单、地址、端口先讲最容易排查也最容易被误判的连接层问题。只读节点连不上第一反应永远是检查四样东西账号是否存在、密码是否正确、白名单是否包含来源IP、连接地址是否写成了主节点地址。这里有个很常见的坑很多人会踩PolarDB的连接地址有“主实例地址”和“只读实例地址”之分它们在控制台上看起来很像都是xxxx.mysql.polardb.rds.aliyuncs.com这种样式但端口和背后路由的节点完全不同。如果应用配置里写的是主实例地址读流量就会打到主节点上只读节点反而空转。我们在实际项目里就遇到过“连接正常但只读负载很低”的情况查了半天才发现是配置文件里的地址写错了。白名单的问题也很有意思。云数据库的白名单如果配置的是某个弹性IP或者NAT网关出口IP一旦出口IP变动应用侧全部连接会被拒绝报错就是ERROR 1045 (28000): Access denied for user。注意这个报错不一定代表密码错误白名单拦截也会伪装成这种错误。所以看到1045先别急着改密码去查白名单。3.2 复制链路中断IO线程和回放线程的真实状态复制链路中断是“从节点不能用”最阴险的原因因为它表面看着节点活着但数据不动了。IO线程断开的常见原因包括主节点和只读节点之间的网络闪断、Redo日志产生的速率远大于只读节点消费的速率、底层存储出现短暂IO抖动被复制框架判定为超时等。回放线程卡住的原因则通常和SQL执行有关大事务在主库执行完产生了大量物理变更只读节点要回放这些变更如果本地内存或IO能力不够回放速度跟不上延迟就会像滚雪球一样越滚越大。极端情况下Redo日志堆积量超过阈值系统为了自保护会暂停该只读节点的对外服务。还有一种情况比较隐蔽物理复制要求主备节点的表结构、参数、插件完全一致。如果在主库执行了某些DDL操作且同步不完全兼容或者修改了关键参数没有同步到只读节点回放线程就会报错并停住。这时候SHOW REPLICA STATUS里的Last_SQL_Error会明确写出具体原因比如找不到表、字段类型不匹配、表不存在等。3.3 硬件与内核瓶颈磁盘、内存、CPU云数据库虽然把底层资源都托管了但它不是无限资源的。只读节点同样有规格上限。读流量高峰期如果只读节点规格偏小CPU和内存被打满连接处理能力就会急剧下降。这时候从应用侧看就是连接超时从监控看就是只读节点CPU使用率持续100%、活跃会话数飙升、内存使用率接近上限。有一个特别容易忽视的资源是磁盘空间。PolarDB的共享存储架构里只读节点本地一般不会有太大的数据盘压力但临时文件、日志文件、排序文件都会占用本地临时空间。如果一个只读节点承担了大量复杂的分析型查询临时空间被写满节点就会进入异常状态。这里多说一句很多团队给只读节点配置的规格和主节点一样但读流量却比写流量大好几倍这种“平均主义”的资源配置方式本身就是隐患。3.4 参数与版本变更引发的隐藏问题降级、发版、参数修改这些变更操作在某些情况下也会让只读节点“失灵”。比如批量修改参数模板时如果参数模板里某个值不兼容只读节点当前运行的内核版本节点在应用新参数后可能无法正常启动回放线程。又比如数据库小版本升级过程中如果新版本在复制协议上有变化而只读节点升级不对齐就会出现复制链路版本不匹配进而中断。这类问题在时间点上很有迷惑性因为看起来是“什么都没动突然就坏了”。实际上变更可能发生在几天前只是当时没有触发故障等到某条特定SQL或者流量上涨才把问题引爆。这次我们的故障排查最后也指向了一个提前埋下的隐患第5节细说。4. 完整排查实操用四步从现象摸到根因4.1 第一步确认“不可用”的具体表现排查的第一步不是去翻日志而是先把“不可用”的边界搞清楚。到底是所有只读节点都不可用还是只有一个节点不可用是连接完全建立不起来还是连接能建立但查询报错是应用侧自己做了读写分离但配置错误还是数据库侧本身的问题我当时的操作方法很简单从应用服务器上直接用只读节点的连接串跑一条最简单的SELECT 1再用telnet检查只读地址对应端口的连通性。如果能连上但查询报错问题在数据链路如果连不上再换账号、换白名单、换网络逐层排除。这一步花的时间不需要多但能把问题的半径从“整个数据库”缩小到“某一层网络策略”或者“某一个节点”。这里有个实操技巧如果手头有多个只读节点一定要分别测试每个节点的连接串。PolarDB的集群读地址Cluster Endpoint通常会在多个只读节点之间做负载均衡如果其中一个节点被摘除读地址可能已经绕开了它。所以用集群读地址测出来的结果可能显示“正常”但实际上故障节点仍然存在。务必要用每个只读节点的私网地址分别做连通性测试。4.2 第二步看监控指标与慢日志确认了是某个只读节点的问题之后第二步就是打开监控。重点看六个指标复制延迟IO线程状态SQL/回放线程状态活跃会话数CPU使用率磁盘空间如果复制延迟显示是有数据的比如几十秒、几分钟说明复制链路还活着但追不上如果延迟曲线为空大概率是IO线程已经断开。CPU使用率如果一直打满考虑是查询负载过高如果CPU不高但活跃会话数很高可能是连接堆积导致的应用侧问题。慢日志也要翻一下。只读节点如果承受了某些重量级查询查询本身会出现在慢日志里而且执行时间可能是平时的几十倍。慢日志能帮你判断是“这个节点被某些高消耗SQL拖垮了”还是“这个节点自身就没在正常工作”。如果节点被摘除流量后慢日志数量反而下降说明问题出在进来访问的流量上如果慢日志里SQL很少但节点依然异常那就要进一步怀疑复制链路。4.3 第三步查复制状态与报错日志这一步是核心。登录到数据库后用SHOW REPLICA STATUSMySQL 8.0语法查看完整的复制状态。我当时看到的结果非常典型Slave_IO_Running: NoSlave_SQL_Running: YesLast_IO_Error字段明确写着Got fatal error 1236 from master when reading data from binary log: Could not find first log file name in binary log index file看到1236这个错误码的时候就明白了只读节点请求的Redo日志位点已经不在主节点可提供的范围内了。也就是说只读节点落后主节点实在太多主节点上的Redo日志已经清理掉了只读节点找不到自己需要从哪个位置继续同步。这个问题一旦发生不是简单重启能解决的必须重建复制关系。在实际排查中我还见过Slave_IO_Running: Connecting这种中间态它表示IO线程在尝试重连但一直失败。这种场景多半是网络抖动或者主节点负载过高导致连接超时。如果是Slave_SQL_Running: No那就是回放线程卡住的典型表现需要看Last_SQL_Error具体报错。4.4 第四步针对性验证与恢复操作不同的错误码有不同的应对方式。如果是白名单和账号问题直接在控制台改配置如果是网络策略问题检查安全组和路由表如果是复制链路中断导致的位点丢失常规做法是重建这个只读节点让系统重新从主节点复制一份数据出来。PolarDB控制台一般会提供“重建只读节点”的入口操作上相当于新创建一个只读节点并重新开始物理复制。这个操作的耗时取决于数据量大小数据量大的情况下可能需要比较长时间所以如果业务不能接受长时间只读能力缺失建议提前在架构上保留至少两个只读节点一个异常时另一个还能顶上。这里想提醒一句不要尝试通过手工设置CHANGE MASTER TO去强行续接复制位点在PolarDB这种共享存储架构下手工操作复制链路很可能导致数据一致性问题而且云数据库本身也不允许这种操作。遇到复制位点丢失最稳妥的方案就是重建节点。5. 根因复盘与修复实录那条SQL怎么把从节点拖垮的5.1 真正触发故障的那条SQL与执行计划重建只读节点之后我在主库的慢日志和审计日志里做了一次复盘找到了真正触发问题的根源。故障发生前一周线上某张订单明细表启用了一个新的归档任务每天凌晨会对大批量历史订单做一次UPDATE单次事务涉及的数据行数接近千万行。这个大事务在主库执行了很长时间生成了海量Redo日志。按理说PolarDB的物理复制延迟应该在毫秒级到秒级但Redo日志生成速度远远超过了只读节点的回放能力。叠加凌晨正好也在跑报表任务只读节点的CPU和内存被报表SQL占用了大半回放线程分到的资源更少复制延迟从几秒钟一路涨到几十分钟。最致命的是大事务产生了巨量的Redo日志而主库侧Redo日志的保留策略是按时间或大小滚动的只读节点还没来得及消费完更早的日志主库就已经把那段日志清理掉了。等只读节点回放到那一段的时候发现找不到日志文件IO线程直接报错中断。这一步复盘让我彻底明白只读节点不是被“某一次异常”打挂的它是被持续一周的“大事务高峰读负载”组合拳逼到了墙角最后一步是“Redo日志被清理”这个压死骆驼的稻草。5.2 从“应急恢复”到“长效加固”的处理动作应急恢复动作相对简单就是重建只读节点。但能稳定地跑过故障靠的是后面的垃圾清理和架构调整。第一件事把凌晨归档任务从大事务拆成小批量事务。原来一次UPDATE千万行改成每次UPDATE5万行每次操作间歇停顿一小段时间让Redo日志的生成速率保持平稳也方便只读节点在间隙里追平复制位点。实测下来同样的归档数据量执行总时间从40分钟拉长到70分钟左右但对整个集群的影响从“红色告警”变成了“完全无感”。第二件事给报表查询专门划分独立的只读节点。以前读流量全打到同一个只读节点上归档任务产生的回放压力和报表查询的CPU压力挤在一起互相拖累。现在把报表类的分析查询路由到一个独立节点上线上订单查询走另一个节点避免两类负载互相干扰。第三件事建立复制延迟的预警机制。在监控平台里新增了复制延迟和IO线程状态的告警规则延迟超过10秒就告警IO线程状态如果变成Connecting或No直接拉起高优先级告警。原先这套监控其实是缺失的只在只读节点“完全不可用”的时候才会触发告警而复制链路劣化的过程有可能是好几天越早发现处理成本越低。这次根因复盘之后我又给团队梳理了一份只读节点巡检清单每天定时检查复制延迟、Redo日志堆积趋势、主库大事务情况从源头避免类似问题再次发生。6. 这些坑我替你们踩过了避坑清单与日常巡检6.1 常见问题速查表整理一张速查表基本覆盖了“PolarDB从节点不能用”的常见场景、典型特征和应对方式可以直接收藏起来用。场景典型特征常见原因应对方式连接被拒绝应用报ERROR 2003、连接超时白名单未放行、连接地址错误、网络策略不通分节点测试连通性检查白名单和连接串账号权限报错报ERROR 1045密码错误、白名单拦截、账号权限变更重置密码、确认白名单、核对账号权限只读节点查询报错连接能建立但SELECT失败节点角色变更、复制状态异常、数据版本不一致查看复制状态必要时重建只读节点复制延迟持续上涨延迟曲线一路攀升大事务生成大量Redo、只读节点资源不足拆分大事务、扩容只读规格、低峰期执行负载复制位点丢失IO线程No、ERROR 1236Redo日志被清理只读节点追不上重建只读节点避免手工改复制链路参数/版本变更后异常回放线程报错参数模板兼容性问题、版本升级不齐回滚变更确认主备参数一致测试后再切换6.2 日常巡检与主动防御与其每次故障后抢救不如把“从节点能不能用”变成日常巡检里的常规项目。我的习惯是每周做一次只读节点健康巡检重点看三块第一块复制链路健康度。查SHOW REPLICA STATUS里三个关键字段Slave_IO_Running、Slave_SQL_Running、Seconds_Behind_Master。不需要追求每秒都看但每次巡检必须看到这三个值是正常的。延迟偶尔波动没关系连续多个采样点延迟都在涨就要开始排查了。第二块主库大事务监控。主库的大事务是只读节点延迟的第一推手如果监控平台能感知到单个事务执行时间超过一定阈值或者事务影响行数特别大就主动告警。我们现在的标准是任何影响行数超过20万行的事务都必须提前报备并通过拆分方案执行。第三块只读节点的规格水位。观察过去一周只读节点的CPU平均水位和峰值水位。如果平均水位超过60%或者峰值水位经常触顶就要考虑升级规格或者再增加一个只读节点分流。不要等到节点被高负载拖到复制追不上了才去扩容那时候业务已经受损了。另外强烈建议在应用侧做连接池的健康检查和自动重建。这次故障里连接池中陈旧连接导致的问题比数据库侧本身更早暴露出来。设置合理的连接空闲超时、定时检测连接有效性、对只读节点CIDR变更或者角色变化自动刷新连接池这层防御能帮你兜住很多数据库侧的底层故障。6.3 最后分享一个小技巧排查从节点问题时如果控制台里显示节点“运行中”但实际服务不正常可以试着用SHOW GLOBAL STATUS LIKE Threads_running看一眼当前并发运行中的线程数。如果这个值很高说明有大量查询挤在回放队列里如果这个值接近0但连接数还居高不下反而可能是连接本身卡在验证阶段。这个指标能帮你快速区分“节点在忙”还是“节点挂了”在线上五分钟内就能确认方向。这次开年第一天的“丢人”经历给我的最大教训是只读节点的健康靠的不是控制台上那个绿油油的“运行中”状态而是复制链路的真实状态。主从架构里的每个节点都不是铁打的大事务、高峰负载、资源规格、配置变更任何一个环节失衡最后都会以“从节点不能用”这种最直接的方式反馈给你。把这些排查思路和巡检习惯提前建好比事后熬夜救火值钱得多。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进