ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

GaussDB集中式xlog堆积排查与处理:从复制槽到归档的完整指南

GaussDB集中式xlog堆积排查与处理:从复制槽到归档的完整指南 磁盘告警半夜响起来登录实例一看pg_wal目录已经六十多GB复制槽列表里躺着一个activefalse的槽restart_lsn停在两天前。这种画面做GaussDB集中式运维的人不会陌生。xlog也就是WAL预写日志本身是数据库保证崩溃恢复和主备一致性的核心机制正常情况下会随着checkpoint不断滚动回收可一旦出现堆积磁盘被吃光是迟早的事。这篇内容就把我在GaussDB 505.2.1集中式环境下处理xlog堆积问题的完整思路写出来从判断堆积、定位根因到分级处理、参数预防整个过程都配有可执行的SQL和命令。无论你是专职DBA还是兼着管数据库的运维照着这套流程走大概率能少熬几个夜。1. 接到磁盘告警之后先还原问题现场1.1 集中式环境下xlog目录的正常状态先明确一个前提GaussDB 505.2.1集中式实例是主备架构数据目录里用来存放WAL文件的目录在这套版本下是pg_wal旧一点的版本叫pg_xlog。你不需要死记目录名进data目录看一眼就知道xlog文件是固定长度名称的24位十六进制字符串每个段默认16MB比如000000010000000000000001。正常情况下xlog文件数量不是固定的。它受max_wal_size、checkpoint_timeout、写吞吐量和备机状态共同影响。低负载实例在两次checkpoint之间可能只需要几个段中等写入负载的主备实例pg_wal里稳定在二三十个到五六十个文件之间是很常见的。关键特征是数量会在一定范围内上下波动checkpoint之后掉下去业务高峰时升上来整体不出现“只增不减”的走势。我判断堆积时不会只看某一个瞬间的目录大小而是连续观察两到三个checkpoint周期。如果pg_wal目录的总量在30分钟内没有回落的迹象最老文件的时间戳还一直停在原地那基本可以判定为堆积而不是正常的瞬时增长。这一步看起来简单却能避免把“业务刚打了一波高峰”误判成故障。1.2 判断堆积的两个关键指标第一个指标是pg_wal目录总大小的增长曲线。高并发期间WAL增长是正常的但如果一段时间后大小没有回落或者在低峰期仍然匀速上涨就要高度警惕。举个例子max_wal_size如果只有1GB而pg_wal目录已经几十GB中间差了不止一个量级这绝不可能是正常行为。第二个指标是最老文件的时间戳。WAL段一旦被回收目录里永远不会留下“资历太老”的文件。你可以直接在数据目录下执行ls -lt pg_wal | tail看看最旧的那个文件是什么时间创建的。如果它已经存在了几个小时甚至几天同时目录里还堆着一大批同期文件说明回收机制已经“罢工”了。此时需要做的不是急着删文件而是搞清楚是什么条件阻止了回收。另外一个容易被忽略的点先确认磁盘剩余空间还能撑多久。如果磁盘使用率已经到95%处理窗口可能只有几个小时那就得按后面的应急顺序走如果还有很大余量可以从容地把根因找出来再动手。2. xlog为什么会堆积六类根因的机制拆解2.1 复制槽卡住最隐蔽也最高发的元凶复制槽replication slot是数据库主备复制和备份工具用来标记“日志消费到哪里”的锚点。每个槽里都有一个关键位置restart_lsn数据库回收WAL段时绝对不能越过任何槽的restart_lsn因为一旦越过槽对应的备机或工具就可能缺日志。这个机制本身很合理问题出在槽失去消费者之后——备机下线了、逻辑复制停了、备份工具异常退出了但槽还在restart_lsn永远不动。这类堆积非常典型pg_replication_slots里能看到一个activefalse的槽restart_lsn可能停在一两天前而pg_current_wal_lsn已经走了很远。两个位置之间差多少pg_wal就得留多少目录自然越来越胖。我遇到过的案例里有备份工具异常结束后残留的有测试环境搭完备机忘记删槽的也有逻辑复制停掉后订阅端迟迟没处理的。它比备机断连更隐蔽因为从复制状态视图上看主备可能都是正常的问题只藏在slot列表里。这个机制打个比方就像一个共享单车调度系统有几辆车被标记为“有人正在使用”但实际骑的人早就走了调度车永远不去清运这些车。车越积越多系统还认为一切正常。2.2 备机同步异常主库不敢回收日志即使没有复制槽备机本身也会影响主库的WAL回收。主备架构下主库回收WAL段前必须确认这些日志已经安全到达或者至少被备机接收。这是主备一致性的底线如果主库把备机还没拿到的日志删了备机后来断线重连就补不齐日志只能全量重建。所以当备机出现长时间断连、网络抖动、备机磁盘满、备机正在做恢复或消耗大量资源时主库会自觉地把从备机卡住位置往后的所有日志都留着。这就像一个木桶最短的那块板决定了桶里的水位。备机的replay_lsn长时间不前进或者state从streaming掉到catchup主库的pg_wal目录就会同步增长。这类问题好定位pg_stat_replication视图一目了然但难在解决根因往往在备机侧可能是备机硬件性能不足、机房网络问题或者是备机在做一些消耗极大的查询。光在主库上折腾是没有用的。2.3 归档失败日志在等待“出货”如果开启了归档archive_modeonWAL段必须归档成功之后checkpoint进程才有资格回收它。这个设计是为了支持PITR时间点恢复和持续备份。问题在于archive_command经常出各种幺蛾子目标目录写满了、归档命令里写错了绝对路径、目标网络存储挂载掉了、命令里的%p和%f占位符搞反了甚至有人把归档命令配置成一个卡住不返回的脚本。归档失败的表现非常直白pg_stat_archiver里的failed_count不断增长last_failed_time一直在刷新last_failed_wal停在一个文件名上后面跟着一大堆排队等待的日志。此时不管你怎么在数据目录里翻文件都会看到大量已经写完但从未被“运走”的段。因为归档是串行处理的一条卡住后面的全被堵住堆积速度很快。2.4 长事务锁住回收位点数据库在计算哪些WAL可以回收时要保证恢复时能重建到一致的快照状态。一个很老的事务或查询如果一直持有旧快照不释放数据库就必须保留从那个时间点之后的所有WAL否则一旦崩溃恢复那个长期事务将无法看到它该看到的数据版本。典型场景是应用侧连接池里的连接长期处于idle in transaction状态事务已经开启但没有任何SQL活动也不提交不回滚。从pg_stat_activity看xact_start可能是几小时甚至几天前state却是“idle in transaction”。这种连接往往最难查因为业务方通常认为“连接没在跑就是没占用资源”实际上它悄悄卡住了数据库的日志回收。2.5 参数配置不当日志回收被“合法”架空有一类堆积不属于故障纯粹是配置问题。wal_keep_segments参数定义了主库无条件保留的WAL段数量如果被设成1024甚至更大那等于不论业务是否需要都凭白多留好几十GB的日志。在GaussDB这样的集中式版本里这个参数在高写入环境下一定要克制默认值通常够用。max_wal_size和min_wal_size同样会影响目录Sizemax_wal_size决定了checkpoint触发前WAL可以涨到多大设置过大意味着“合法的WAL占用空间”本身就很大min_wal_size设置过大则会让checkpoint之后保留的空闲段偏多。还有openGauss系里的max_size_for_xlog_prune这类和复制槽保留相关的参数如果没配置或者配置过大也会把slot保留的WAL上限放得很宽。这类堆积的特征是复制槽、备机、归档、长事务全查了一遍都没问题但pg_wal就是不小。此时用show命令把几个参数列出来对比一番往往能立刻找到答案。2.6 其他隐藏原因IO异常、VACUUM慢与主备切换残留除以上五类还有一些不那么好定位的原因。比如共享存储或数据盘IO出现抖动导致日志写入和回收同时受阻VACUUM线程因为锁冲突长时间跑不完间接拖住checkpoint推进主备切换后旧主库如果以某种异常状态残留也可能在新环境里持续保留旧日志。这些情况单靠某一两条SQL不一定能一眼看出来需要结合实例日志、操作系统IO状态和切换记录综合判断。所以在排查时不要把思路锁死在复制槽上尤其是在上面五类都查过还是无解的情况下回头翻一翻数据库日志和系统监控往往会有意外发现。3. 定位根因的六步排查法附可直接执行的SQL3.1 站点实态目录大小、文件数量与当前LSN排查的第一步永远是确认现状。先用omm用户登录实例确认数据目录位置和WAL目录的实际大小gsql -d postgres -p 5432 -r show data_directory;然后在操作系统层面看一眼目录的真实占用cd $data_directory du -sh pg_wal ls pg_wal | wc -l ls -lt pg_wal | taildu给的是总大小wc -l给的是文件数量tail看的是最老文件的时间戳。这三个数据配合起来基本能判断堆积的严重程度。接着查一下当前数据库写到的WAL位置和活动文件select pg_current_wal_lsn(); select pg_walfile_name(pg_current_wal_lsn());第二个命令返回的是当前正在写的WAL文件名。记住这个位置后面处理完再回来看就能知道日志有没有继续推进。在这一步里我建议顺手记录三个值pg_wal目录大小、文件数量、最老文件的日期。这就是排查的“现场快照”无论后续怎么操作都有据可查。3.2 复制槽排查一条SQL看清谁在“扣”日志复制槽检查是最关键的一步SQL也最简单select slot_name, slot_type, active, restart_lsn, xmin from pg_replication_slots;看到activefalse的街重点怀疑看到restart_lsn很久不动的slot重点怀疑。为了直观地知道这个槽扣住了多少日志可以算一下它和当前LSN之间的差距select slot_name, active, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) as lag_keep from pg_replication_slots;如果差距是几个GB甚至几十GB同时active为false那答案基本就出来了这个槽已经被“消费方”抛弃但数据库还在为它保留大量WAL。需要提醒的是如果某个版本里pg_wal_lsn_diff函数不存在可以换成pg_xlog_location_diff试试逻辑一样。另外通过select pg_walfile_name(restart_lsn) from pg_replication_slots;可以直接获得该槽要求保留的最小WAL文件名。拿着这个文件名去和pg_wal目录里的文件对比凡是字典序比它小的文件理论上都不再被这个槽约束可以放心交给数据库回收。3.3 主备复制状态延迟与断连主备状态确认用pg_stat_replicationselect application_name, client_addr, state, sent_lsn, replay_lsn, pg_size_pretty(pg_wal_lsn_diff(sent_lsn, replay_lsn)) as replay_delay from pg_stat_replication;正常情况下state应该是streamingsent_lsn和replay_lsn非常接近replay_delay在可接受范围。如果某个备机的replay_delay非常大或者state不是streaming说明备机掉队了主库为了给它留日志正在持续堆积WAL。这里要强调一个容易误判的细节state为streaming不代表没有延迟要看sent_lsn和replay_lsn的差值。备机接收日志和回放日志是两回事接收了但没回放完同样会拖住主库的清理节奏。3.4 归档进程实况归档状态查询select archived_count, failed_count, last_archived_wal, last_failed_wal, last_failed_time from pg_stat_archiver;重点看failed_count和last_failed_time。如果failed_count在增长last_failed_time不断刷新说明归档一直在试错日志被堵在队列里。也可以顺手看一下归档配置show archive_mode; show archive_command;如果archive_modeon但archive_command是空字符串或者明显错误问题就在这里。注意归档失败和归档慢是两回事failed_count不涨但归档目录里的文件一直没增加那可能是归档进程卡住或者命令本身有问题也要排查。3.5 活跃事务与backend_xmin长事务排查select pid, usename, state, query_start, xact_start, backend_xmin from pg_stat_activity order by xact_start asc nulls last limit 30;这条SQL能把开启时间最早的事务排在最前面。正常情况下xact_start应该是几分钟以内如果看到有的连接xact_start是几小时前state还是idle in transaction这就是典型的“长事务卡清理位点”。即使它什么活都没干数据库也得按它的启动时间保留WAL。backend_xmin字段表示该会话最老的事务快照如果有值且很小说明它持有的快照正在阻止系统推进。在GaussDB集中式环境里有些管理工具或开发环境的空闲连接最容易出现这种问题查询时直接按xact_start排序就能快速锁定嫌疑会话。3.6 日志佐证从告警时间去回溯变更排查到最后可以把实例日志翻出来看看。数据库运行日志里往往有线索归档失败重试信息、备机断连告警、checkpoint耗时长、IO错误等。到这一步时我会特别关注两个时间点一是告警开始的时间二是最近一次变更操作的时间。比如日志从三天前开始报archive_command失败而系统恰恰是三天前调整过备份策略那因果链就很清晰。又比如两天前做过一次主备切换之后旧主库的日志一直没有正常收敛就要把切换后的状态和参数重新梳理一遍。排查这些时间线信息往往比反复执行SQL更能接近真相。4. 分级处理方案从优雅清理到应急止损4.1 动手前必须做的三件事确认根因之后不要急着执行任何删除或切换操作。先把三件事做完第一保存当前的所有查询结果包括复制槽列表、备机延迟、归档失败次数、pg_wal目录大小这是后续验证操作是否生效的基线第二估算剩余磁盘空间能支持多久判断是走正常处理流程还是应急流程第三确认当前没有正在运行的物理备份、PITR恢复、逻辑复制任务避免操作与这些任务互相干扰。有一个原则必须明确优先让数据库自己回收日志手动删除永远是最后手段。一个安全、可验证的处理顺序是先做日志切换和checkpoint再看回收结果如果不行再按根因分类处理。4.2 首选用法切换日志段并强制执行检查点最优雅的回收方式是手动切换当前日志段并触发checkpoint。执行select pg_switch_wal(); select pg_checkpoint();也可以直接在gsql里执行checkpoint;pg_switch_wal会让数据库切换到下一个WAL段不再写当前段pg_checkpoint则触发一次检查点让checkpoint进程重新计算可回收的WAL范围。执行后等几分钟再查pg_wal目录大小。如果所有保留条件都已经消失目录体积会明显下降如果还是纹丝不动说明确实还有某个条件在扣住日志。这个操作会带来一次IO尖峰在业务高峰期会有短暂影响但比起磁盘满导致的故障这点代价完全值得。操作前最好确认当前没有大数据量的DDL或批量导入在跑否则checkpoint会等待这些操作尽快完成失去“快速触发”的意义。4.3 复制槽处理的两种不同走向复制槽分两种情况处理。第一种槽已经没有对应的备机或工具使用确定不需要后直接删除select pg_drop_replication_slot(slot_name);删除前务必确认这个slot不是当前某个主备复制伙伴在用的。如果删除报错“replication slot is active”说明有备机正连着它不能删要转向第二种处理恢复备机同步或者等备机重新上线把restart_lsn推进后再删。这里有一个实战教训很多人一看activefalse就删槽完全没确认这个槽对应的备机是否还有恢复价值。如果备机只是因为网络抖动暂时掉线你把槽删了备机回来后想增量续传就没有锚点了只能全量重建。操作前一定要和负责备机的人确认或者先在pg_stat_replication里核对备机的源地址。删除槽之后再执行一次4.2的日志切换和checkpoint观察目录是否回落。通常到这一步被slots扣住的那部分WAL就能被正常清理掉。4.4 归档停滞的处理细节归档失败时先修好归档命令本身。一般的archive_command格式类似archive_command cp %p /backup/archive/%f如果目标目录是网络存储还要确认挂载状态和读写权限。修复后在shell里手动执行一次归档命令的关键部分验证确实能成功复制。比如手动执行cp 当前WAL文件 /backup/archive/如果能成功再让它自动跑。然后观察pg_stat_archiver里的failed_count是否停止增长last_failed_wal是否更新。归档是逐段处理的修复后积压的日志会排队归档目录才会逐渐收敛。这个过程中不要手动去删尚未归档的WAL段否则会导致PITR链路断档等于埋了一个更大的雷。4.5 长事务清理与业务联动对确认无害的长空闲事务可以直接终止select pg_terminate_backend(pid);pid从pg_stat_activity里查到。处理长事务之前一定要先和业务侧确认这段事务确实不需要继续跑。如果是应用连接池导致的长连接光杀掉单个进程还不够要同时排查连接池是否配置了合适的idle超时。这个参数在数据库侧也能兜底alter system set idle_in_transaction_session_timeout 30s; select pg_reload_conf();设置后新开启的事务如果长时间处于空闲状态会被自动断开。至于设成多少秒取决于业务特性核心交易类系统建议别太激进但要敢于设置毕竟一个长空闲事务卡住的可能不是几十个WAL而是整个实例的回收机制。4.6 关于手动删除xlog文件红线与底线绝大多数情况下我反对直接rm pg_wal里的文件。原因很简单数据库的pg_control和checkpoint记录可能还指向这些文件一旦删了正在被引用的WAL段实例崩溃后恢复会直接失败最终只能全量重建。这个代价比磁盘满还要高一个量级。如果真的到了“不删马上宕机”的极端情况底线操作是确认当前正在写入的文件名它绝不能碰用pg_walfile_name(restart_lsn)确认所有slot要求保留的最早文件名只有文件名排序在老早之前的文件才能考虑处理把候选文件移到其他挂载点而不是直接永久删除转让后再做一次checkpoint逼迫数据库重新计算活动文件范围。整个过程要记录操作清单事后面向原厂支持如实说明。我更愿意强调的是只要在故障发生前做好了复制槽监控和归档监控几乎不会走到手动清理这一步。把功夫花在预防上比在刀尖上跳舞划算得多。5. 参数调优与预防性监控5.1 与xlog回收相关参数的设置建议下面的参数和xlog回收直接相关我按生产环境的常见建议列出实际值要结合业务写入量和磁盘大小调整。参数作用建议值/备注max_wal_size触发checkpoint前WAL允许增长的上限中低写入1~4GB高写入可适当增大但不能超过磁盘可用空间的合理比例min_wal_sizecheckpoint后WAL回收保留的低水位80MB~1GB别设太高checkpoint_timeout两次checkpoint的最大间隔默认5min生产环境一般保持这个节奏checkpoint_completion_targetcheckpoint的IO铺展目标0.5~0.9不要设过高wal_keep_segments无条件保留的WAL段数默认16除非有特殊需求不要调大max_size_for_xlog_pruneopenGauss系复制槽保留WAL的上限如支持配置成1~2GB用show确认版本是否支持archive_mode归档开关按需开启开启后必须保证archive_command正确idle_in_transaction_session_timeout空闲事务自动断开时间30~60s按业务容忍度调整max_replication_slots最大复制槽数量默认值够用关键是清理不用槽修改参数要用专业方式比如alter system set或改postgresql.conf后reload部分参数需要重启实例。改完参数后务必观察一到两个checkpoint周期确认WAL目录大小确实收敛到正常范围。5.2 监控脚本与告警阈值预防xlog堆积最有效的监控有四个pg_wal目录大小、复制槽活跃度、备机延迟、归档失败计数。最简单的巡检思路是用shell加gsql组合data_dir$(gsql -d postgres -p 5432 -t -c show data_directory; | tr -d ) wal_dir$data_dir/pg_wal size$(du -sm $wal_dir | awk {print $1}) files$(ls $wal_dir | wc -l) echo wal_size_mb$size wal_files$filesSQL侧定期检查select slot_name, active, restart_lsn from pg_replication_slots where active false;select failed_count, last_failed_time from pg_stat_archiver;可以参考的告警阈值pg_wal目录连续15分钟超过max_wal_size的3倍存在activefalse且落后当前LSN超过1GB的slot归档failed_count在10分钟内增加备机replay_lag超过500MB或状态不是streaming。这些阈值可以根据磁盘容量适当放宽但原则是“宁可错报不可漏报”。5.3 每周巡检清单我建议每周做一次固定巡检动作不大但能有效降低故障概率。检查项包括复制槽列表里有没有异常槽备机延迟是否在正常范围归档失败计数是否清零过pg_wal目录大小是否在一个稳定区间以及是否存在长时间idle in transaction的连接。巡检时间选在业务低峰期把结果记录到值班文档里连续几周就能建立一套属于自己环境的水位基线。每当有变更操作时比如主备切换、备份策略调整、逻辑复制启停第二天要加做一次复查重点看有没有新残留的slot或者归档队列异常。很多xlog堆积都发生在变更之后的24小时内这时候看一次能避免问题拖到磁盘耗尽。6. 常见问题速查表与经验小结6.1 高频问题定位表现象优先检查项处理动作pg_wal涨到几十GB有activefalse的slotpg_replication_slots确认槽无消费方后删除再做switchcheckpoint备机state异常replay_lag持续变大pg_stat_replication排查备机网络、磁盘、性能恢复备机同步归档failed_count增长lc日志不归档pg_stat_archiver、archive_command修复归档命令和目标目录等待归档消费积压pg_stat_activity有长时间idle in transactionpg_stat_activity按xact_start排序终止空闲事务配置idle_in_transaction_session_timeout所有检查都正常但目录仍大wal_keep_segments、max_wal_size等参数调整参数必要时与原厂支持确认手动删过xlog后实例无法恢复pg_control、实例日志立即联系原厂支持准备全量重建方案6.2 处理xlog堆积时我沉淀的几个小习惯第一个习惯是“先快照再动手”。每次开始排查先把查询结果存到一个文件里再执行任何操作。这样做的好处是如果处理过程中发现方向错了还能回到最初的状态重新分析而不是凭记忆猜。第二个习惯是“switchcheckpoint作为第一动作”。这个动作安全、可逆、对业务影响小而且能立即过滤掉一大批“其实已经没有保留条件”的简单堆积。做了之后目录回落那就说明问题不在slots不需要再折腾。第三个习惯是“复制槽永远是第一个怀疑对象”。在集中式主备架构里xlog堆积十有八九和复制槽或备机状态有关。每次排查都先看slot再往后查别的能节省大量时间。再分享一个实用小技巧用pg_walfile_name(restart_lsn)算出每个slot要求保留的最早WAL文件名然后到pg_wal目录里做一次“字典序对比”凡是排序更早的文件理论上都有机会被回收。这个判断不需要一层层翻资料一条SQL加一个ls就能对现场情况心里有数。最后说句实在话xlog堆积问题只要在监控和巡检上花了功夫绝大多数都能在变成故障之前被发现。把这篇流程里的SQL固化成一个巡检脚本再配几条告警你可能就再也不会在凌晨三点被磁盘告警叫起来处理pg_wal了。
返回列表