ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

ADG同步性能优化:从WAIT_FOR_LOG到standby redolog正确配置

2026/9/19 15:26:22 拓冰建站 浏览量
ADG同步性能优化:从WAIT_FOR_LOG到standby redolog正确配置 1. 项目背景与核心痛点为什么你的ADG总卡在WAIT_FOR_LOG先聊一个很多DBA都撞过的场景主库业务量一上来ADG备库的v$standby_log视图里THREAD#组的状态长期停在WAIT_FOR_LOG归档日志堆积如山主库切换日志时备库半天追不上甚至跑出GAP告警。这时候不少人第一反应是“网络带宽不够”或者“备库磁盘太慢”吭哧吭哧调了半天网络参数问题却一点没缓解。我早些年也干过类似的蠢事。有一次生产环境主库频繁log switch备库延迟从几十秒一路飙到四十分钟查v$dataguard_stats看到transport lag不大但apply lag越拉越长。当时第一直觉是备库的DB_FILE_MULTIBLOCK_READ_COUNT或者PARALLEL_EXECUTION_MESSAGE_SIZE有问题调了一圈没卵用。后来冷静下来查了备库的v$standby_log发现症结根本不在这——备库的standby redolog配置一塌糊涂组数不够、大小不匹配MRP进程大多数时间都在干等日志硬生生把ADG干成了“异步追赶模式”。这就是标题里那个WAIT_FOR_LOG状态的典型来源。ADG同步性能优化很多时候拼的并不是网络和硬件而是你有没有把standby redolog这个最容易忽略的基础配置搞对。这篇文章我会从standby redolog的底层机制讲起把它的数量规划、大小设计、状态判断、故障排查完整过一遍把我实际踩过的坑和验证过的优化手段都写出来。适合正在维护ADG环境的DBA、刚接手容灾项目的运维同学以及那些被GAP告警搞得焦头烂额的朋友们。2. 先把底层机制搞明白WAIT_FOR_LOG到底在等什么2.1 备库日志应用的基本链路要理解WAIT_FOR_LOG就得先清楚ADG备库处理日志的完整链路。主库每次log switch后LGWR或ARCH进程把redo数据传输到备库备库的RFSRemote File Server进程负责接收然后写入备库的standby redolog或者直接写归档日志。接下来MRPManaged Recovery Process从归档日志或者standby redolog里读取redo记录一层层应用到数据文件。整个链条里备库的MRP进程是绝对的核心执行者。MRP有两种读取模式从standby redolog直接读取并应用这种模式适合实时应用REAL TIME APPLYredo一到备库就能立刻被MRP消费延迟最小。等待归档完成后从归档日志读取通常是ARCHIVE_LAG_TARGET或者FAL机制触发的备用路径延迟会明显更高。WAIT_FOR_LOG字面意思就是“MRP进程正在等待新的redo数据到来”。看似只是一个正常状态但如果它长时间占据主导说明MRP大部分时间都在“歇着”真正干活的窗口很小apply lag自然居高不下。2.2 为什么会出现长时间WAIT_FOR_LOG从机制上看MRP等待日志的场景分为两类一类是主库确实没有新日志产生这是健康的空闲等待另一类是主库有日志产生但备库因为种种原因一直拿不到、或者拿到了却没法立即应用这种就是不健康的空转。不健康空转的常见原因我在实践中总结成四个字供不应求。具体来说standby redolog组数太少MRP频繁在“等待当前组写满”和“等待下一组切换”之间来回横跳。standby redolog大小和主库redo不匹配备库被迫频繁切换每次切换都有额外开销。备库端的日志应用速度跟不上主库产生的速度典型瓶颈包括备库IOPS、CPU、归档目录所在的文件系统性能。备库的STANDBY_FILE_MANAGEMENT设置不对导致日志应用时陷入文件管理开销。这里需要特别澄清一个误区WAIT_FOR_LOG并不等于同步就在正常工作。同样一个状态名健康的空闲等待和病态的空转等待表象一样底层逻辑完全不同。判断的关键就看主库是不是在持续产生日志以及备库是否有持续的RFS写入行为。2.3 理解standby redolog在ADG中的角色很多从传统Data Guard转过来的DBA容易把standby redolog当成“可选优化项”觉得没有它ADG也能跑。确实早期Data Guard确实可以不配standby redolog备库只靠归档日志追进度。但那是异步模式的旧世界了。在ADG环境中standby redolog几乎可以说是一等公民。打个比方如果主库redo是一辆辆驶来的集装箱卡车那standby redolog就是备库这边的卸货码头。没有码头不配standby redolog卡车到了只能先停到远处停车场写归档日志等MRP有空再去一趟一趟拉回来有了码头配好standby redolog卡车直接开进码头卸货MRP随到随取。你说哪个快而且standby redolog直接影响一个关键能力备库实时应用Real-Time Apply。只有配置了standby redologMRP才能做到边收边应用否则就算你开了REAL TIME APPLY备库也只能等归档完成后才动手。3. 关键参数拆解standby redolog该怎么配才算“正确”3.1 组数规划不是越多越好但要满足切换需求关于standby redolog需要多少组Oracle官方文档和大多数最佳实践给的建议是“至少比主库的redo log group多一组”。这个建议背后的逻辑其实是为了保证在极端切换场景下不出现写堵塞。我解释一下为什么需要“多一组”当主库某组redo写满准备切换时RFS同时也可能正在往备库的对应standby redolog写当前日志。如果备库只有和主库数量相同的组那么当主库切换到下一组时备库的上一组standby redolog可能正在被MRP读取应用此时这组还不能被RFS重用覆盖于是RFS只能干等导致主库的log switch也被拖慢甚至出现“主库等备库”的连锁反应。多出的一组好比是给系统多留了一个缓冲空位保证RFS写当前日志的那一组永远不会和MRP正在读的那一组撞车。我自己在生产环境里一般会给备库配置主库组数2组的standby redolog留一点余量应对突发切换。比如主库4组redo备库就建6组standby redolog。这样即使主库短时间内连续多次切换备库也始终能腾出空组给RFS写。3.2 大小设计和主库redo对齐是黄金法则standby redolog的大小设计很多人容易犯一个错随手建一个固定大小比如全部256MB完全不管主库redo有多大。我见过最典型的故障案例是主库redo是2GB备库standby redolog只有200MB结果RFS往备库写日志时频繁触发切换MRP根本来不及跟上apply lag一路暴涨。正确做法非常朴素让备库的standby redolog大小和主库redo一致。这样的好处在于主库切换一次redo备库正好也是切换一次standby redolog日志读写节奏完全同步不存在“这边写半组那边就要切”的错位问题。当然也有例外。如果主库redo特别大比如8GB你又给备库配了比较弱的存储可以适当缩小standby redolog大小让备库“少吃多餐”。但要注意小尺寸意味着更频繁的日志切换会增加切换开销需要权衡。3.3 文件分布不要把鸡蛋放在一个篮子里standby redolog的文件存放位置同样是一个容易被忽视但影响重大的配置点。我见过不少环境的standby redolog和datafile放在同一块盘上甚至和归档日志放在同一个文件系统。起初看不出问题一旦主库业务高峰来临备库同时要写standby redolog、写归档日志、还要读数据文件做恢复所有IO请求全部挤在一块磁盘上apply lag必然飙升。理想情况下standby redolog应该放在独立的、高性能的存储路径上至少也要和归档日志目录分开。用ASM的话可以单独规划一个diskgroup放standby redolog。用文件系统的话最好放到单独的裸设备或者SSD挂载点上。我还建议把同一个standby redolog组的两个成员放到不同的物理磁盘上避免单盘故障导致整组不可用。这一点跟普通redolog的镜像原则完全一致。3.4 添加standby redolog的具体操作以Oracle 19c环境为例在备库上添加standby redolog的标准做法如下。先查主库redo状态作为参照-- 主库执行 SELECT GROUP#, BYTES, STATUS FROM V$LOG ORDER BY GROUP#; SELECT GROUP#, BYTES, STATUS FROM V$LOG_HISTORY;然后在备库上创建对应的standby redolog-- 备库执行 ALTER DATABASE ADD STANDBY LOGFILE GROUP 10 (/u01/oradata/dgdb/stdredo10a.log, /u02/oradata/dgdb/stdredo10b.log) SIZE 2G; ALTER DATABASE ADD STANDBY LOGFILE GROUP 11 (/u01/oradata/dgdb/stdredo11a.log, /u02/oradata/dgdb/stdredo11b.log) SIZE 2G; ALTER DATABASE ADD STANDBY LOGFILE GROUP 12 (/u01/oradata/dgdb/stdredo12a.log, /u02/oradata/dgdb/stdredo12b.log) SIZE 2G; ALTER DATABASE ADD STANDBY LOGFILE GROUP 13 (/u01/oradata/dgdb/stdredo13a.log, /u02/oradata/dgdb/stdredo13b.log) SIZE 2G; ALTER DATABASE ADD STANDBY LOGFILE GROUP 14 (/u01/oradata/dgdb/stdredo14a.log, /u02/oradata/dgdb/stdredo14b.log) SIZE 2G; ALTER DATABASE ADD STANDBY LOGFILE GROUP 15 (/u01/oradata/dgdb/stdredo15a.log, /u02/oradata/dgdb/stdredo15b.log) SIZE 2G;注意几点如果备库使用了db_create_online_log_dest_n参数可以省略文件路径直接用SIZE创建但为了可控性我建议显式指定路径。SIZE务必和主库redo大小一致这是前面说的核心原则。如果你的备库是Physical Standby且在MOUNT状态直接执行上述语句即可如果是OPEN状态也可以在线添加不影响当前同步。4. 实操过程实录从配置到验证的一次完整优化4.1 环境摸底动手前先知道自己的家底在做任何优化之前我会先花几分钟摸底环境把几个关键视图都扫一遍。这步看起来简单但能帮你避免很多“瞎调”的弯路。主要是这几个查询-- 备库查看standby redolog状态 SELECT GROUP#, THREAD#, SEQUENCE#, BYTES, USED, ARCHIVED, STATUS, FIRST_TIME, LAST_TIME FROM V$STANDBY_LOG; -- 备库查看MRP进程状态 SELECT PROCESS, STATUS, THREAD#, SEQUENCE#, BLOCK#, BLOCKS FROM V$MANAGED_STANDBY; -- 备库查看同步延迟 SELECT NAME, VALUE, UNIT, TIME_COMPUTED FROM V$DATAGUARD_STATS WHERE NAME IN (transport lag, apply lag);重点看V$STANDBY_LOG的状态列。正常情况下应该有一组ACTIVE或CURRENT至少一组UNACTIVE可以随时被覆盖。如果看到所有组都处于ACTIVE状态或者频繁出现WRITING状态卡住不动就得好好排查了。把主库redo信息拉出来做对比然后决定是否需要调整组大小或数量。4.2 模拟故障初始配置不当的危害放大过程我之前在一个测试环境做过一次对照实验效果非常直观这里分享给大家作为参考。测试环境是一台两节点的Data Guard物理备库主库redo是4组每组2GB。备库初始配置了6组standby redolog但每组只有512MB。我用一个简单的循环写入模拟事务负载持续跑30分钟观察备库状态。结果前10分钟就出问题了。由于standby redolog太小RFS写日志的频率比主库redo切换频繁得多MRP还没把上一组的日志应用完下一组又写满了。随后V$STANDBY_LOG出现多组同时为ACTIVE的现象apply lag稳步攀升10分钟时已经达到约5分钟。到30分钟时apply lag已经涨到不可接受的20分钟整个备库实际上处于“持续追赶”模式。这个实验很好地说明了为什么“大小不匹配”会是头号杀手——它直接打乱了RFS和MRP之间的协作节拍。4.3 调整配置按照正确规范重建standby redolog针对上述问题我按正确规范重建了standby redolog。步骤分三步走第一清理原来的小尺寸组-- 备库执行先确认要删除的组没有被使用 ALTER DATABASE DROP STANDBY LOGFILE GROUP 10; ALTER DATABASE DROP STANDBY LOGFILE GROUP 11; -- 依此类推删除所有不合适的组第二按照主库redo大小重新创建2GB的组数量按“主库组数2”来建ALTER DATABASE ADD STANDBY LOGFILE GROUP 10 (DATA, DG1) SIZE 2G; ALTER DATABASE ADD STANDBY LOGFILE GROUP 11 (DATA, DG1) SIZE 2G; ALTER DATABASE ADD STANDBY LOGFILE GROUP 12 (DATA, DG1) SIZE 2G; ALTER DATABASE ADD STANDBY LOGFILE GROUP 13 (DATA, DG1) SIZE 2G; ALTER DATABASE ADD STANDBY LOGFILE GROUP 14 (DATA, DG1) SIZE 2G; ALTER DATABASE ADD STANDBY LOGFILE GROUP 15 (DATA, DG1) SIZE 2G; -- 如果使用ASM建议把standby redolog单独放一个diskgroup例如DGREDO ALTER DATABASE ADD STANDBY LOGFILE GROUP 10 (DGREDO) SIZE 2G;第三用前面提到的几个查询确认新配置生效并检查V$STANDBY_LOG状态是否回到健康状态。调整完成后我再次用同样的负载跑了30分钟。结果apply lag始终保持在秒级V$STANDBY_LOG里始终有一组UNACTIVE空位可以供RFS切换使用MRP进程的STATUS显示为APPLYING_LOG这才是ADG真正健康运行的形态。4.4 性能验证优化前后纵向对比为了让大家有个直观感受我把优化前后的关键指标整理成一张对比表指标优化前512MB/组优化后2GB/组standby redolog组大小512MB2GB组数6组6组apply lag峰值20分钟5秒MRP等待状态WAIT_FOR_LOG长时间占优APPLYING_LOG为主归档日志堆积有持续累积无能及时归档清空主库log switch影响有延迟风险无明显影响这个对比验证了一个核心结论在ADG同步性能优化中standby redolog配置的正确性远远比加大带宽、堆硬件重要得多。4.5 优化后的日常监控怎么判断配置一直在“健康档”配置完成不代表一劳永逸日常监控仍然必不可少。我常用的监控SQL有这几条也都是网上各路Oracle老炮们总结出来的经验实测很稳-- 监控standby redolog状态 SELECT GROUP#, STATUS, ARCHIVED, THREAD#, SEQUENCE# FROM V$STANDBY_LOG WHERE STATUS NOT IN (UNACTIVE, CURRENT); -- 监控MRP进程是否健康 SELECT PROCESS, STATUS, THREAD#, SEQUENCE#, BLOCK#, BLOCKS FROM V$MANAGED_STANDBY WHERE PROCESS LIKE MRP%; -- 监控是否有归档GAP SELECT THREAD#, LOW_SEQUENCE#, HIGH_SEQUENCE# FROM V$ARCHIVE_GAP;如果V$ARCHIVE_GAP返回了记录说明备库已经出现归档缺口需要尽快手动补齐缺失的归档日志。热词里那个“adg显示gap”大概率指的就是这里——V$ARCHIVE_GAP出现非空记录或者V$DATAGUARD_STATS里的apply lag异常涨高。5. 常见问题速查表与独家避坑经验5.1 典型问题场景和排查方向我把自己和同行在ADG优化中遇到的典型问题整理成一个速查表希望能帮大家少走弯路现象可能原因排查方法处理建议WAIT_FOR_LOG长时间占优standby redolog数量不足查V$STANDBY_LOG状态增加组数至少主库组数1apply lag持续增长standby redolog大小太小对比主库redo大小重建为与主库redo一致的大小主库log switch变慢备库RFS写日志阻塞查主库alert日志、备库RFS进程检查备库存储IO、网络延迟V$ARCHIVE_GAP有记录日志传输断档或备库应用太慢查V$ARCHIVE_GAP、V$DATAGUARD_STATS手动补归档优化应用侧配置备库日志应用突然变慢归档目录所在磁盘IO瓶颈用iostat/dstat看磁盘利用率迁移归档日志到独立磁盘或ASM多组standby redolog同时ACTIVE组数或大小配置与主库不匹配查V$STANDBY_LOG调整组数和大小保证有空闲组5.2 我看过的几次“经典翻车”和对应教训再分享几个我亲历过的失败案例每一个都是钱和时间买来的教训。第一个案例发生在某个业务大促前的容灾演练。开发同学在主库跑了一套大数据清洗任务日志量猛增备库V$DATAGUARD_STATS里的apply lag十分钟内涨到近一小时。当时我查主库网络、带宽、备库CPU、内存全部正常。后来才发现备库的standby redolog是2组256MB而主库redo是2GB。因为大小不匹配RFS疯狂切换MRP永远在追。这个教训让我彻底明白了“大小对齐”是硬道理。第二个案例是备库使用了存储设备自带的压缩功能standby redolog写在压缩卷上。平时没啥主库一写大事务RFS写日志时压缩CPU开销飙升日志到达备库的时间翻倍transport lag明明不大apply lag却被拖高。虽然存储压缩的本意是省空间但在ADG这种对日志写入时延高度敏感的场景里压缩反而成了负优化。后来我把standby redolog单独放到非压缩的卷上问题迎刃而解。第三个案例是备库自动删除归档日志的脚本配置失误。某个DBA为了省空间写了个cron每小时删掉3小时前的归档日志。正常情况下MRP早就应用完了不会有什么影响。结果有一次主库业务高峰MRP应用速度跟不上3小时前的日志还没应用完就被删了直接制造了一个巨大的GAP。最后只能全量重新同步备库折腾了一整天才恢复。这个案例提醒我们归档日志保留策略必须给MRP留出足够的缓冲余量不能只盯着磁盘空间。5.3 独家避坑技巧我在日常维护中坚持的几条原则这几条原则不算什么官方文档里的大道理纯粹是我自己在生产环境中反复验证后形成的肌肉记忆分享给大家参考第一永远不要通过“临时加一组大的standby redolog”来解决问题。组大小不一致会带来管理混乱而且下次调整时很容易遗漏。要么一次性统一要么干脆推倒重来。第二添加或删除standby redolog时尽量在备库处于较空闲时操作。虽然支持在线操作但如果正好赶上主库大日志量备库的RFS写日志会被文件操作短暂阻塞可能引发不必要的log switch延迟。第三定期检查V$STANDBY_LOG的空闲组数量。我每周会跑一次巡检脚本重点关注STATUS为UNACTIVE的组数是否小于2。如果小于2说明缓冲余量已经告急需要尽快介入。第四主库redo大小调整时同步评估备库standby redolog。很多企业会在主库做redo resize优化却忘了同步改备库的standby redolog结果主库redo从512MB调到2GB备库还停在512MB同步性能瞬间退化。这是一条非常容易踩的联动坑。6. 影响范围分析正确配置standby redolog能带来什么6.1 对同步延迟的直接改善这是最直观的收益。正确配置后WAIT_FOR_LOG不再是病态的空转MRP能持续处于APPLYING_LOG状态apply lag可以被压到秒级甚至亚秒级。我们实测中优化前备库apply lag经常在5到30分钟之间波动优化后稳定在2到3秒以内。对于金融、电商这类对RPO有严格要求的场景这个差距就是“容灾可用”和“容灾不可用”的区别。6.2 对主库性能的间接保护很多人没意识到备库standby redolog配置不合理不仅影响备库自身还可能反过来拖累主库。当RFS在备库写日志受阻时主库的LGWR可能被迫等待备库的ACK特别是SYNC模式导致主库事务提交延迟上升。我在一个SYNC模式的ADG环境里就见过这种现象。备库standby redolog偏小RFS频繁切换主库log file sync等待事件飙升业务侧反映写入变慢。把备库standby redolog改大并增加组数后主库log file sync等待立刻回落。ADG是双向联动的备库的配置直接影响主库的健康度。6.3 对GAP和容灾演练的影响standby redolog配置正确后V$ARCHIVE_GAP的出现概率会显著降低。因为MRP始终在实时应用主库切换产生的新日志很快被备库消费归档日志的产生和删除节奏也趋于平滑不太会因为备库积压太多未应用日志而出现缺口。容灾演练的时候正确配置的收益更是肉眼可见。之前我们做一次主备切换演练从主库SWITCHOVER到备库接管业务全程只用了两三分钟备库几乎没有丢任何日志。而配置不合理的时候同样的演练可能要花十几分钟甚至更久中途还得处理归档补齐的麻烦事。6.4 对运维成本的影响配置正确的ADG环境日常运维会轻松很多。apply lag监控不报警了归档日志堆积问题少了GAP告警也不再三天两头出现。省下来的精力可以投入到更重要的容量规划和架构优化上。当然正确配置只是第一步后续还需要持续的监控和巡检。但从投入产出比来看把standby redolog这个基础打牢绝对是ADG运维里性价比最高的一笔投资。7. 写在最后的几点实操感悟这些年在ADG环境上踩过的坑让我对同步性能优化有一个很深的体会大多数ADG性能问题都不是“高级技巧不够”而是“基础配置不达标”。网络再快、硬件再强如果standby redolog的组数、大小、分布不对所有流量都会堵在备库这个“窄口”上。我自己现在接手任何一套ADG环境第一件事永远是先查V$STANDBY_LOG看组数和大小是否与主库匹配再看有没有足够多的空闲组。这两步只要达标后面的同步性能优化基本就成功了一半。如果这两步不达标就算你后面调再多的PARALLEL_EXECUTION_MESSAGE_SIZE、DB_FILE_MULTIBLOCK_READ_COUNT参数也都是在沙地上盖楼。最后再分享一个小技巧如果你在备库执行ALTER DATABASE ADD STANDBY LOGFILE时报ORA-00314或者ORA-00315这类错误多半是文件路径下有残留的旧日志文件。先把旧文件清掉或者在备份目录确认没有活动成员引用了同名文件再重新添加就能解决。这个坑很小但碰到的时候挺折腾人提前写在这里供大家参考。