可用shell脚本通过sqlplus查询v$archive_dest_status视图,将transport_lag和apply_delay转为秒级数值,配合timeout防卡死、awk提取字段、循环轮询与阈值判断实现稳定监控。

如何用Shell脚本获取Data Guard实时同步延迟(APPLY_DELAY 和 TRANSPORT_LAG)
Oracle Data Guard 的同步延迟不能靠 ps 或 netstat 看,必须连到数据库查视图。最直接的是查 V$ARCHIVE_DEST_STATUS,其中 APPLY_DELAY 表示备库应用日志的固定延迟(单位秒),TRANSPORT_LAG 是归档传输滞后(单位秒),但注意:这两个字段是 INTERVAL 类型,需转成秒才能比较和告警。
实操建议:
- 用
sqlplus -s / as sysdba静默连接,避免交互提示干扰脚本解析 - SQL 查询必须加
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF,否则输出含页眉、空行、提示符,awk解析会错位 - 推荐查询语句:
SELECT NVL(TO_NUMBER(EXTRACT(DAY FROM TRANSPORT_LAG)) * 86400 + TO_NUMBER(EXTRACT(HOUR FROM TRANSPORT_LAG)) * 3600 + TO_NUMBER(EXTRACT(MINUTE FROM TRANSPORT_LAG)) * 60 + TO_NUMBER(EXTRACT(SECOND FROM TRANSPORT_LAG)), 0) AS TRANSPORT_SEC, NVL(TO_NUMBER(EXTRACT(DAY FROM APPLY_DELAY)) * 86400 + TO_NUMBER(EXTRACT(HOUR FROM APPLY_DELAY)) * 3600 + TO_NUMBER(EXTRACT(MINUTE FROM APPLY_DELAY)) * 60 + TO_NUMBER(EXTRACT(SECOND FROM APPLY_DELAY)), 0) AS APPLY_SEC FROM V$ARCHIVE_DEST_STATUS WHERE DEST_ID = 2; - DEST_ID = 2 是默认主库指向第一个物理备库的编号;若配置了多个备库,需确认实际
DEST_ID(查V$ARCHIVE_DEST)
Shell脚本中如何稳定提取延迟数值并避免SQL*Plus超时失败
SQL*Plus 在网络抖动或备库不可达时可能卡住,默认无超时。不处理会导致监控脚本 hang 死,后续检查全部失效。
实操建议:
- 用
timeout 10s sqlplus -s / as sysdba @check_lag.sql强制 10 秒超时,超时返回非零退出码,可被if捕获 - SQL 脚本末尾必须加
EXIT,否则sqlplus不退出,timeout可能杀错进程 - 输出结果用
awk '{print $1,$2}'提取两列(TRANSPORT_SEC 和 APPLY_SEC),不要依赖空格数量——Oracle 字段对齐可能随数值位数变化 - 把 SQL 输出重定向到临时文件再读取,比管道更可靠:
timeout 10s sqlplus -s / as sysdba @check_lag.sql > /tmp/dg_lag.out 2>/dev/null
如何设计循环监控与阈值告警逻辑(不依赖外部服务)
实时监控 ≠ 每秒跑一次 SQL。太频繁会加重主库负载,且 Oracle 内部统计本身有约 5–10 秒刷新周期。合理间隔是 30 秒到 2 分钟。
实操建议:
- 用
while true; do ...; sleep 30; done实现轮询,sleep 放在末尾,确保每次执行完再等 - 延迟判断用数值比较,不是字符串匹配:
if [ "$apply_sec" -gt 300 ]; then echo "ALERT: APPLY delay > 5min"; fi - 记录日志要带时间戳和来源实例名(防止多套 DG 混淆):
echo "$(date '+%F %T') PRIMARY -> STANDBY2: transport=$transport_sec apply=$apply_sec" >> /var/log/dg_monitor.log - 避免重复告警:用
touch /tmp/dg_alerted_2标记已发过告警,恢复后rm /tmp/dg_alerted_2,否则每轮都发邮件
为什么不能只看 APPLIED_SCN 和 PRIMARY_SCN 的差值
有人试图用 (SELECT CURRENT_SCN FROM V$DATABASE) 减去备库的 APPLIED_SCN 来算延迟,这是错误的。SCN 增长速率不恒定,10000 SCN 差 ≠ 10 秒延迟——高负载时 SCN 跳得快,空闲时几乎不动。
真正反映业务影响的是时间维度的滞后:TRANSPORT_LAG 和 APPLY_DELAY 是 Oracle 内部根据归档生成时间、传输完成时间、应用完成时间精确计算的 INTERVAL,唯一可信。
容易踩的坑:
- 在备库本机查
V$DATABASE.CURRENT_SCN,得到的是备库当前 SCN,不是主库的,不能用于减法 - 用
DBA_HIST_DATABASE_INSTANCE查历史 SCN 更慢、不准,不适合实时监控 -
V$DATAGUARD_STATS虽也含延迟字段,但刷新频率更低(默认 10 分钟),且部分字段在非实时应用模式下为 NULL
真正在生产环境跑起来,最常被忽略的是 SQL*Plus 连接权限和 ORACLE_HOME/ORACLE_SID 环境变量是否在 crontab 或后台 service 中正确继承——脚本手动运行成功,但 systemctl 启动就报 ORA-12162: TNS:net service name is incorrectly specified,八成是环境没导全。











