Oracle RAC与 ADG巡检脚本分析 – 刘子毅

Oracle RAC与 ADG巡检脚本分析 – 刘子毅


Oracle RAC および ADG の検査は、次の 4 つのレベルで実行することをお勧めします。クラスター層 → ASM ストレージ層 → データベースインスタンス層 → Data Guard 同期層。 RAC メイン データベースと RAC スタンバイ データベースの両方を検査する必要がある場合は、それぞれメイン データベースとスタンバイ データベースで実行する必要があります。


1. クラスター層 (グリッドユーザー)

# 1. 集群守护进程状态(CRS/CSS/OHASD)
crsctl check crs

# 2. 所有集群资源状态,重点看 ONLINE/OFFLINE/UNKNOWN
crsctl stat res -t
crsctl stat res -t -init

# 3. 节点成员与角色
olsnodes -n -s -t

# 4. 私网(心跳)网卡配置,确认 interconnect 绑定正确
oifcfg getif

# 5. 表决盘与 OCR
crsctl query css votedisk
ocrcheck

# 6. 数据库/服务/监听资源
srvctl status database -d  -v
srvctl status service  -d 
srvctl config database -d 
srvctl status asm -n <节点名>
srvctl status listener
lsnrctl status

2. ASMストレージ層(+ASMインスタンス)

asmcmd lsdg
asmcmd lsdsk --statistics
-- 磁盘组容量与冗余余量(ASM 实例执行)
SELECT name, type, state, total_mb, free_mb,
       required_mirror_free_mb, usable_file_mb, offline_disks
FROM v$asm_diskgroup_stat
ORDER BY name;

-- 磁盘挂载/成员状态,检查是否有 MISSING/FORCING/OFFLINE 盘
SELECT group_number, disk_number, name, path,
       mount_status, header_status, mode_status, state
FROM v$asm_disk
ORDER BY group_number, disk_number;

3. RAC インスタンス層 (任意のインスタンスによって実行)

-- 1. 各实例状态、角色、启动时间
SELECT inst_id, instance_number, instance_name, host_name, version,
       status, database_status, active_state, startup_time, thread#
FROM gv$instance
ORDER BY inst_id;

-- 2. 集群私网互连地址
SELECT inst_id, name, ip_address, is_public, source
FROM gv$cluster_interconnects
ORDER BY inst_id;

-- 3. 服务在节点间的分布(防止单节点承载全部连接)
SELECT inst_id, name, network_name, goal, clb_goal
FROM gv$active_services
ORDER BY inst_id, name;

-- 4. 在线日志与线程对应关系(RAC 每个实例一个线程)
SELECT group#, thread#, sequence#, bytes, status, archived
FROM v$log
ORDER BY thread#, group#;

-- 5. 会话与等待概况(按实例汇总)
SELECT inst_id, COUNT(*) AS session_cnt,
       SUM(CASE WHEN status="ACTIVE" THEN 1 ELSE 0 END) AS active_cnt
FROM gv$session
GROUP BY inst_id
ORDER BY inst_id;

4. ADG同期レイヤー(コア、スタンバイ・データベースで実行する必要があります)

1. データベースの役割と保護モード

SELECT db_unique_name, database_role, protection_mode, open_mode,
       switchover_status, force_logging, flashback_on, current_scn
FROM v$database;

期待: バックアップ ライブラリ DATABASE_ROLE = PHYSICAL STANDBY、OPEN_MODE = READ ONLY WITH APPLY;PROTECTION_MODE 計画と一致している。

2. 伝送遅延とアプリケーション遅延

SELECT name, value, unit, time_computed, datum_time
FROM v$dataguard_stats
WHERE LOWER(name) IN ('apply lag', 'transport lag')
ORDER BY name;

知らせ:このビューをメイン ライブラリで実行すると空のセットが返されるため、同期が正常であるかどうかを判断できません。。value は文字列なので、次と組み合わせる必要があります unit 一緒に読んでください。 2 つの連続したサンプル datum_time 先に進まないということは、新しいログが受信されていないことを意味します。現時点では、表示される遅延は非常に小さいため、正常とは考えられません。

3. ターゲット状態のアーカイブ (11gR2 以降)

SELECT dest_id, status, type, database_mode, recovery_mode, destination,
       error, gap_status, archived_thread#, archived_seq#,
       applied_thread#, applied_seq#
FROM v$archive_dest_status
WHERE status <> 'INACTIVE'
ORDER BY dest_id;

期待する:status = VALID、error 空です、gap_status = VALID。

4. アーカイブログのギャップ

SELECT thread#, low_sequence#, high_sequence#
FROM v$archive_gap
ORDER BY thread#;

空が返されるということは、回復を妨げるギャップが現在存在しないことを意味します。ただし、結果が空であっても、プロセス全体でログが失われていないことを意味するわけではありません。

5. Data Guard プロセス (RAC スタンバイ データベースはインスタンスごとに表示されます)

SELECT inst_id, name, pid, type, role, action, client_role, client_pid,
       thread#, sequence#, block#, block_count, delay_mins, dest_id
FROM gv$managed_standby
ORDER BY inst_id, name;

重要なのは見ることです MRP0 そうですか APPLYING_LOG。 RACスタンバイ・データベースでマルチインスタンスREDO適用が有効になっている場合、MRPは複数のインスタンスに分散されます。単一インスタンス モードでは、MRP0 は 1 つのインスタンスにのみ存在します。

6. スタンバイデータベースのリカバリ/アプリケーションの進行状況

SELECT start_time, type, item, units, sofar, total, timestamp
FROM v$recovery_progress
WHERE type="MEDIA RECOVERY"
ORDER BY start_time DESC, item;

調整されていないインスタンスは、マルチインスタンスREDO適用では機能しない可能性があります。sofar/total 意味はによって異なります item 変更はパーセンテージを一律に変換しません。

7.スタンバイREDOログ

SELECT group#, thread#, sequence#, bytes, used, archived, status
FROM v$standby_log
ORDER BY thread#, group#;

容量はオンライン ログと一致しており、各スレッドの SRL グループ数 ≥ このスレッドのオンライン ログ グループ数 + 1;status 長期間使用しないでください UNASSIGNED。

8. 同期サイト比較(マスター、スレーブそれぞれで実行)

-- 主库:各线程当前最大序列
SELECT thread#, MAX(sequence#) AS last_seq
FROM v$log
GROUP BY thread#
ORDER BY thread#;

-- 备库:各线程已应用到的最大序列
SELECT thread#, MAX(sequence#) AS applied_seq
FROM v$archived_log
WHERE applied = 'YES'
GROUP BY thread#
ORDER BY thread#;

双方の差は増加し続けており、アプリケーションが追いつけないか、送信が中断されていることを示しています。

9. 過去 24 時間の Data Guard アラーム

SELECT *
FROM (
  SELECT timestamp, facility, severity, dest_id, message_num, error_code, message
  FROM v$dataguard_status
  WHERE severity IN ('Warning', 'Error', 'Fatal')
    AND timestamp >= SYSDATE - 1
  ORDER BY timestamp DESC, message_num DESC
) WHERE ROWNUM <= 100;

10. ブローカー構成の検査 (ブローカー管理が使用されている場合)

dgmgrl sys/<密码>@<主库TNS> "show configuration verbose"
dgmgrl sys/<密码>@<主库TNS> "show database verbose "
dgmgrl sys/<密码>@<主库TNS> "validate database "

焦点を当てる Configuration Statusそれぞれの丘 Status、Transport Lag、Apply Lag、Protection Mode、同様に validate エラーを報告するかどうか。


5. ホスト層とログ層

# 资源使用
top -b -n1 | head -20
vmstat 1 5
iostat -x 1 5
free -g
df -h

# 进程检查(备库看 MRP,主库看 LNS/ARCn)
ps -ef | grep -iE "mrp|lns|arc"

# 告警日志
adrci -exec "show alert -tail 200"

6. 結果判断のポイント

チェック項目 正常な判断
クラスターリソース すべてのリソースはオンライン、不明/中間はなし
ASM state = MOUNTED、offline_disks = 0、usable_file_mb 適度な余裕がある
例 すべてのノード status = OPEN、database_status = ACTIVE
スタンバイの役割 PHYSICAL STANDBY、READ ONLY WITH APPLY
送信/アプリケーションの遅延 0に近い、そして datum_time 前進し続ける
アーカイブ対象 VALID、なし error、gap_status = VALID
対数ギャップ v$archive_gap 空です
MRPプロセス MRP0 で APPLYING_LOG
SRL 数量は「スレッドあたり ≥ オンライン グループの数 + 1」を満たしており、長期的なものはありません。 UNASSIGNED

以下は、直接保存して実行できるコピーです。 Oracle RAC + ADG ワンクリック検査スクリプト(Bash + SQL*Plus)。スクリプトは読み取り専用であり、構成は変更されません。デフォルトでは、root として実行すると自動的に に切り替わります。 grid / oracle ユーザーは対応するコマンドを実行するか、対応するユーザーとして個別に実行できます。

使用法

chmod +x rac_adg_inspect.sh
./rac_adg_inspect.sh -d  [-s ] [-o <输出目录>]
# 主库、备库各跑一次;Broker 巡检需额外提供连接串:
DG_BROKER_CONNECT='sys/<密码>@<主库TNS>' ./rac_adg_inspect.sh -d 

スクリプトの内容

#!/usr/bin/env bash
# =============================================================================
# rac_adg_inspect.sh  —  Oracle RAC + ADG 一键巡检(只读)
# 适用:Oracle 11gR2 / 12c / 18c / 19c / 21c+,RAC 主库与 RAC 备库
# 用法:./rac_adg_inspect.sh -d  [-s ] [-o <输出目录>]
# 建议:以 root 执行,脚本自动以 grid 执行集群命令、以 oracle 执行 SQL
# =============================================================================
set -uo pipefail

DB_UNIQUE_NAME=""
ORACLE_SID="$ echo "$*" "
OUT_DIR=""
GRID_USER="grid"
DB_USER="oracle"

usage()  grep -m1 "^CHK_$1=" "$CHKOUT" 2>/dev/null 

while getopts "d:s:o:h" opt; do
  case "$opt" in
    d) DB_UNIQUE_NAME="$OPTARG" ;;
    s) ORACLE_SID="$OPTARG" ;;
    o) OUT_DIR="$OPTARG" ;;
    h) usage ;;
    *) usage ;;
  esac
done

[ -z "$DB_UNIQUE_NAME" ] &&  echo "$*" 

TS="$(date +%Y%m%d_%H%M%S)"
OUT_DIR="$ echo "$*" "
mkdir -p "$OUT_DIR/sql" || exit 1
LOG="$OUT_DIR/inspect.log"
: > "$LOG"

log()  grep -m1 "^CHK_$1=" "$CHKOUT" 2>/dev/null 
sec()  cut -d= -f2-; 

is_root()   { [ "$(id -u)" -eq 0 ]; }
have_user() { id "$1" >/dev/null 2>&1; }

# 以 grid 用户执行任意 shell 命令
run_grid() {
  local cmd="$1"
  if is_root && have_user "$GRID_USER"; then
    su - "$GRID_USER" -c "$cmd"
  else
    bash -lc "$cmd"
  fi
}

# 以 oracle 用户执行任意 shell 命令
run_oracle_cmd() {
  local cmd="$1"
  if is_root && have_user "$DB_USER"; then
    su - "$DB_USER" -c "$cmd"
  else
    bash -lc "$cmd"
  fi
}

# 以 oracle 用户执行 SQL*Plus 脚本
run_db() {
  run_oracle_cmd "export ORACLE_SID=${ORACLE_SID}; sqlplus -S -L / as sysdba @$1"
}

# ---------- 自动探测 ORACLE_SID ----------
detect_sid() {
  local s=""
  s=$(run_grid "srvctl config database -d ${DB_UNIQUE_NAME}" 2>/dev/null \
        | awk -F: '/[Dd]atabase instance/{gsub(/[[:space:]]/,"",$2); split($2,a,","); print a[1]; exit}')
  if [ -z "$s" ]; then
    s=$(ps -ef | grep -E "ora_pmon_" | grep -v grep | awk '{print $NF}' \
          | sed 's/ora_pmon_//' | grep -v '^+' | head -1)
  fi
  echo "$s"
}

if [ -z "$ORACLE_SID" ]; then
  ORACLE_SID="$(detect_sid)"
fi
if [ -z "$ORACLE_SID" ]; then
  echo "错误:未能自动探测 ORACLE_SID,请使用 -s 指定。"
  exit 1
fi

log "巡检开始时间 : $(date '+%Y-%m-%d %H:%M:%S')"
log "DB_UNIQUE_NAME: ${DB_UNIQUE_NAME}"
log "ORACLE_SID    : ${ORACLE_SID}"
log "输出目录      : ${OUT_DIR}"
log "执行用户      : $(id -un)"

# =============================================================================
# 1. 集群层(Grid)
# =============================================================================
sec "1. 集群层 (Grid Infrastructure)"

log "--- crsctl check crs"
run_grid "crsctl check crs" 2>&1 | tee -a "$LOG"

log "--- crsctl stat res -t"
run_grid "crsctl stat res -t" 2>&1 | tee -a "$LOG"

log "--- crsctl stat res -t -init"
run_grid "crsctl stat res -t -init" 2>&1 | tee -a "$LOG"

log "--- olsnodes -n -s -t"
run_grid "olsnodes -n -s -t" 2>&1 | tee -a "$LOG"

log "--- oifcfg getif"
run_grid "oifcfg getif" 2>&1 | tee -a "$LOG"

log "--- crsctl query css votedisk"
run_grid "crsctl query css votedisk" 2>&1 | tee -a "$LOG"

log "--- ocrcheck"
run_grid "ocrcheck" 2>&1 | tee -a "$LOG"

log "--- srvctl status database"
run_grid "srvctl status database -d ${DB_UNIQUE_NAME} -v" 2>&1 | tee -a "$LOG"

log "--- srvctl status service"
run_grid "srvctl status service -d ${DB_UNIQUE_NAME}" 2>&1 | tee -a "$LOG"

log "--- srvctl config database"
run_grid "srvctl config database -d ${DB_UNIQUE_NAME}" 2>&1 | tee -a "$LOG"

log "--- srvctl status asm"
run_grid "srvctl status asm -n $(hostname -s)" 2>&1 | tee -a "$LOG"

log "--- srvctl status listener / lsnrctl status"
run_grid "srvctl status listener" 2>&1 | tee -a "$LOG"
run_grid "lsnrctl status" 2>&1 | tee -a "$LOG"

log "--- asmcmd lsdg"
run_grid "asmcmd lsdg" 2>&1 | tee -a "$LOG"

log "--- asmcmd lsdsk --statistics"
run_grid "asmcmd lsdsk --statistics" 2>&1 | tee -a "$LOG"

# =============================================================================
# 2. 数据库 + ADG 巡检 SQL
# =============================================================================
sec "2. 数据库实例与 ADG 同步状态"

cat > "$OUT_DIR/sql/db.sql" <<'SQL'
SET PAGESIZE 300 LINESIZE 320 FEEDBACK OFF TRIMSPOOL ON
SET UNDERLINE =
ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS';

PROMPT ===== 实例状态 =====
SELECT inst_id, instance_number, instance_name, host_name, version,
       status, database_status, startup_time, thread#
FROM gv$instance
ORDER BY inst_id;

PROMPT ===== 集群互连 =====
SELECT inst_id, name, ip_address, is_public, source
FROM gv$cluster_interconnects
ORDER BY inst_id;

PROMPT ===== 服务分布 =====
SELECT inst_id, name, network_name, goal, clb_goal
FROM gv$active_services
ORDER BY inst_id, name;

PROMPT ===== 在线日志 =====
SELECT thread#, group#, sequence#, bytes, status, archived
FROM v$log
ORDER BY thread#, group#;

PROMPT ===== 会话概况 =====
SELECT inst_id, COUNT(*) AS session_cnt,
       SUM(CASE WHEN status="ACTIVE" THEN 1 ELSE 0 END) AS active_cnt
FROM gv$session
GROUP BY inst_id
ORDER BY inst_id;

PROMPT ===== 数据库角色与保护模式 =====
SELECT db_unique_name, database_role, protection_mode, open_mode,
       switchover_status, force_logging, flashback_on, current_scn
FROM v$database;

PROMPT ===== 传输/应用延迟(仅备库有数据) =====
SELECT name, value, unit, time_computed, datum_time
FROM v$dataguard_stats
WHERE LOWER(name) IN ('apply lag','transport lag')
ORDER BY name;

PROMPT ===== 归档目标状态 =====
SELECT dest_id, status, type, database_mode, recovery_mode, destination,
       error, gap_status, archived_thread#, archived_seq#,
       applied_thread#, applied_seq#
FROM v$archive_dest_status
WHERE status <> 'INACTIVE'
ORDER BY dest_id;

PROMPT ===== 归档缺口 =====
SELECT thread#, low_sequence#, high_sequence#
FROM v$archive_gap
ORDER BY thread#;

PROMPT ===== Data Guard 进程(RAC 按实例) =====
SELECT inst_id, process, pid, status, client_process, client_pid,
       thread#, sequence#, block#, delay_mins
FROM gv$managed_standby
ORDER BY inst_id, process;

PROMPT ===== 备库恢复/应用进度 =====
SELECT start_time, type, item, units, sofar, total, timestamp
FROM v$recovery_progress
WHERE type="MEDIA RECOVERY"
ORDER BY start_time DESC, item;

PROMPT ===== 备用日志组 =====
SELECT group#, thread#, sequence#, bytes, used, archived, status
FROM v$standby_log
ORDER BY thread#, group#;

PROMPT ===== 备库已应用序列 =====
SELECT thread#, MAX(sequence#) AS applied_seq
FROM v$archived_log
WHERE applied = 'YES'
GROUP BY thread#
ORDER BY thread#;

PROMPT ===== 主库当前日志序列 =====
SELECT thread#, MAX(sequence#) AS last_seq
FROM v$log
GROUP BY thread#
ORDER BY thread#;

PROMPT ===== 最近24小时 DG 告警 =====
SELECT *
FROM (
  SELECT timestamp, facility, severity, dest_id, message_num, error_code, message
  FROM v$dataguard_status
  WHERE severity IN ('Warning','Error','Fatal')
    AND timestamp >= SYSDATE - 1
  ORDER BY timestamp DESC, message_num DESC
) WHERE ROWNUM <= 100;

PROMPT ===== ASM 磁盘组 =====
SELECT name, type, state, total_mb, free_mb,
       required_mirror_free_mb, usable_file_mb, offline_disks
FROM v$asm_diskgroup_stat
ORDER BY name;

PROMPT ===== ASM 磁盘状态 =====
SELECT group_number, disk_number, name, path,
       mount_status, header_status, mode_status, state
FROM v$asm_disk
ORDER BY group_number, disk_number;

EXIT
SQL

run_db "$OUT_DIR/sql/db.sql" 2>&1 | tee -a "$LOG"

# =============================================================================
# 3. 巡检结论自动判定
# =============================================================================
sec "3. 巡检结论汇总"

cat > "$OUT_DIR/sql/check.sql" <<'SQL'
SET HEADING OFF FEEDBACK OFF PAGESIZE 0 LINESIZE 300 TRIMSPOOL ON
SELECT 'CHK_ROLE='||DATABASE_ROLE FROM V$DATABASE;
SELECT 'CHK_PROTECTION='||PROTECTION_MODE FROM V$DATABASE;
SELECT 'CHK_OPEN='||OPEN_MODE FROM V$DATABASE;
SELECT 'CHK_FORCE_LOGGING='||FORCE_LOGGING FROM V$DATABASE;
SELECT 'CHK_ASM_OFFLINE='||NVL(SUM(offline_disks),0) FROM V$ASM_DISKGROUP_STAT;
SELECT 'CHK_ARCHIVE_GAP='||COUNT(*) FROM V$ARCHIVE_GAP;
SELECT 'CHK_MRP='||NVL(MAX(CASE WHEN PROCESS='MRP0' THEN STATUS END),'NONE')
  FROM GV$MANAGED_STANDBY;
SELECT 'CHK_APPLY_LAG='||NVL(MAX(CASE WHEN LOWER(NAME)='apply lag' THEN VALUE END),'NA')
  FROM V$DATAGUARD_STATS;
SELECT 'CHK_TRANSPORT_LAG='||NVL(MAX(CASE WHEN LOWER(NAME)='transport lag' THEN VALUE END),'NA')
  FROM V$DATAGUARD_STATS;
SELECT 'CHK_INSTANCE_CNT='||COUNT(*) FROM GV$INSTANCE;
EXIT
SQL

CHKOUT="$OUT_DIR/check.out"
run_db "$OUT_DIR/sql/check.sql" > "$CHKOUT" 2>&1
get_chk() { grep -m1 "^CHK_$1=" "$CHKOUT" 2>/dev/null | cut -d= -f2-; }

RC=0
ok()   { log "  [PASS] $*"; }
warn() { log "  [WARN] $*"; [ "$RC" -lt 1 ] && RC=1; }
bad()  { log "  [FAIL] $*"; RC=2; }

ROLE="$(get_chk ROLE)"
PROT="$(get_chk PROTECTION)"
OPEN="$(get_chk OPEN)"
FORCELOG="$(get_chk FORCE_LOGGING)"
ASMOFF="$(get_chk ASM_OFFLINE)"
GAP="$(get_chk ARCHIVE_GAP)"
MRP="$(get_chk MRP)"
ALAG="$(get_chk APPLY_LAG)"
TLAG="$(get_chk TRANSPORT_LAG)"
ICNT="$(get_chk INSTANCE_CNT)"

log "  识别角色: ${ROLE:-未知} / ${OPEN:-未知} / ${PROT:-未知}"

case "$ROLE" in
  PRIMARY)  log "  [INFO] 当前为主库,跳过备库专用判定";;
  *STANDBY*) log "  [INFO] 当前为备库,执行同步层判定";;
  *) warn "未能识别数据库角色";;
esac

[ "$FORCELOG" = "YES" ] && ok "FORCE_LOGGING = YES" || warn "FORCE_LOGGING = ${FORCELOG},建议开启"

if [ -n "$ASMOFF" ] && [ "$ASMOFF" != "0" ]; then
  bad "ASM 存在离线磁盘: offline_disks=${ASMOFF}"
else
  ok "ASM 无离线磁盘"
fi

case "$ROLE" in
  *STANDBY*)
    if [ "${GAP:-1}" = "0" ]; then ok "无归档缺口"; else bad "存在归档缺口: ${GAP} 条"; fi

    case "$MRP" in
      APPLYING_LOG) ok "MRP0 状态 APPLYING_LOG";;
      WAIT_FOR_LOG|IDLE) warn "MRP0 状态 ${MRP},需确认是否有新日志";;
      WAIT_FOR_GAP) bad "MRP0 状态 WAIT_FOR_GAP,应用被缺口阻断";;
      NONE) bad "未发现 MRP0 进程,备库可能未应用日志";;
      *) warn "MRP0 状态异常: ${MRP}";;
    esac

    case "$ALAG" in
      NA|"") warn "未能读取 apply lag";;
      *00:00:00*) ok "apply lag = ${ALAG}";;
      *) warn "apply lag = ${ALAG},请持续观察";;
    esac

    case "$TLAG" in
      NA|"") warn "未能读取 transport lag";;
      *00:00:00*) ok "transport lag = ${TLAG}";;
      *) warn "transport lag = ${TLAG},请持续观察";;
    esac
    ;;
esac

[ -n "$ICNT" ] && [ "$ICNT" -ge 1 ] 2>/dev/null && ok "可见实例数 = ${ICNT}" || warn "实例数异常"

# =============================================================================
# 4. Data Guard Broker(可选)
# =============================================================================
if [ -n "${DG_BROKER_CONNECT:-}" ]; then
  sec "4. Data Guard Broker"
  log "--- show configuration verbose"
  run_oracle_cmd "dgmgrl -silent '${DG_BROKER_CONNECT}' 'show configuration verbose'" 2>&1 | tee -a "$LOG"
  log "--- show database verbose"
  run_oracle_cmd "dgmgrl -silent '${DG_BROKER_CONNECT}' 'show database verbose ${DB_UNIQUE_NAME}'" 2>&1 | tee -a "$LOG"
  log "--- validate database"
  run_oracle_cmd "dgmgrl -silent '${DG_BROKER_CONNECT}' 'validate database ${DB_UNIQUE_NAME}'" 2>&1 | tee -a "$LOG"
else
  log ""
  log "[INFO] 未设置 DG_BROKER_CONNECT,跳过 Broker 巡检"
fi

# =============================================================================
# 5. 主机资源与告警日志
# =============================================================================
sec "5. 主机资源与日志"

log "--- top"
top -b -n1 2>/dev/null | head -20 | tee -a "$LOG"

log "--- vmstat"
vmstat 1 5 2>/dev/null | tee -a "$LOG"

log "--- iostat -x"
if command -v iostat >/dev/null 2>&1; then
  iostat -x 1 3 2>/dev/null | tee -a "$LOG"
else
  log "iostat 不可用"
fi

log "--- free -g"
free -g 2>/dev/null | tee -a "$LOG"

log "--- df -h"
df -h 2>/dev/null | tee -a "$LOG"

log "--- 关键进程"
ps -ef | grep -E "ora_(pmon|mrp|lns|arc|lgwr)|ora_asm" | grep -v grep | tee -a "$LOG"

log "--- alert log tail 100"
run_oracle_cmd "adrci -exec 'show alert -tail 100'" 2>&1 | tee -a "$LOG"

# =============================================================================
# 6. 结果
# =============================================================================
sec "6. 巡检结束"
case "$RC" in
  0) log "  总体结论: 正常(PASS)";;
  1) log "  总体结论: 存在告警项,建议人工复核(WARN)";;
  2) log "  总体结论: 存在异常项,需立即处理(FAIL)";;
esac
log "  完整日志: ${LOG}"
log "  结束时间: $(date '+%Y-%m-%d %H:%M:%S')"

exit "$RC"



Source link

Leave a Reply

Your email address will not be published. Required fields are marked *