liuziyi

liuziyi

Oracle 开启归档日志自动化脚本

一、脚本能力说明

脚本 enable_archivelog.sh 完成四件事:

  1. 归档目录不存在时自动创建,并设置权限、校验可用空间;
  2. 判断当前模式:已是 ARCHIVELOG 则跳过重启,仅补配归档目标;NOARCHIVELOG 则重启并切换;
  3. 配置归档目标 LOG_ARCHIVE_DEST_1 并启动自动归档;
  4. 设置归档保留时间:RMAN 恢复窗口 + 过期归档清理(保留天数可参数化)。

适用:Oracle 10gR2~23ai 主库(单实例/RAC),以 oracle 用户执行。

二、脚本内容

#!/bin/bash
# ============================================================
# enable_archivelog.sh
# 功能:创建归档目录 → 开启归档模式 → 设置归档保留时间
# 适用:Oracle 10gR2 ~ 23ai 主库(单实例 / RAC)
# 执行:oracle 用户,具备 SYSDBA 操作系统认证
# ============================================================
set -euo pipefail

ARCHIVE_DEST="${ARCHIVE_DEST:-/u01/app/oracle/archivelog}"
RETENTION_DAYS="${RETENTION_DAYS:-7}"
MIN_FREE_GB="${MIN_FREE_GB:-20}"
DO_CLEANUP="${DO_CLEANUP:-1}"
ASSUME_YES="${ASSUME_YES:-0}"
DRY_RUN="${DRY_RUN:-0}"
CLEANUP_ONLY=0

log() { printf '[%s] %s\n' "$(date '+%F %T')" "$*"; }
die() { log "错误: $*" >&2; exit 1; }

on_error() {
  log "执行中断,请立即检查实例状态(是否停留在 MOUNT)"
  log "必要时手工执行:sqlplus \"/ as sysdba\" 后执行 ALTER DATABASE OPEN;"
}
trap on_error ERR

usage() {
  cat <<'EOF'
用法: enable_archivelog.sh [选项]
  --dest <目录>        归档日志目录,默认 /u01/app/oracle/archivelog
  --days <N>           归档保留天数,默认 7
  --min-free-gb <N>    归档目录最小可用空间(GB),默认 20
  --no-cleanup         不执行过期归档清理
  --cleanup-only       只执行保留策略与过期清理,不切换模式
  --yes                跳过交互确认
  --dry-run            只检查与只读查询,不做变更
  -h, --help           显示帮助
环境变量: ARCHIVE_DEST / RETENTION_DAYS / MIN_FREE_GB / DO_CLEANUP / ASSUME_YES / DRY_RUN
EOF
}

while [ $# -gt 0 ]; do
  case "$1" in
    --dest)        ARCHIVE_DEST="$2"; shift 2 ;;
    --days)        RETENTION_DAYS="$2"; shift 2 ;;
    --min-free-gb) MIN_FREE_GB="$2"; shift 2 ;;
    --no-cleanup)  DO_CLEANUP=0; shift ;;
    --cleanup-only) CLEANUP_ONLY=1; shift ;;
    --yes)         ASSUME_YES=1; shift ;;
    --dry-run)     DRY_RUN=1; shift ;;
    -h|--help)     usage; exit 0 ;;
    *) echo "未知参数: $1" >&2; usage; exit 2 ;;
  esac
done

# ---------- 环境检查 ----------
command -v sqlplus >/dev/null 2>&1 || die "未找到 sqlplus,请确认 ORACLE_HOME 与 PATH"
[ -n "${ORACLE_HOME:-}" ] || die "ORACLE_HOME 未设置"
[ -n "${ORACLE_SID:-}" ] || die "ORACLE_SID 未设置"
case "$RETENTION_DAYS" in ''|*[!0-9]*) die "--days 必须为正整数" ;; esac
[ "$RETENTION_DAYS" -ge 1 ] || die "--days 必须大于等于 1"
if [ "$(id -u)" -eq 0 ]; then
  log "警告: 建议以 oracle 用户执行,root 下操作系统认证可能失败"
fi

# ---------- 归档目录 ----------
prepare_dir() {
  case "$ARCHIVE_DEST" in
    +*)
      log "归档目标为 ASM: $ARCHIVE_DEST,跳过目录创建与空间检查"
      return 0
      ;;
  esac

  if [ ! -d "$ARCHIVE_DEST" ]; then
    log "归档目录不存在,创建: $ARCHIVE_DEST"
    if [ "$DRY_RUN" = "1" ]; then
      return 0
    fi
    mkdir -p "$ARCHIVE_DEST" || die "创建目录失败: $ARCHIVE_DEST"
  fi

  [ "$DRY_RUN" = "1" ] && return 0

  chmod 750 "$ARCHIVE_DEST" || log "警告: 设置目录权限失败"
  if [ "$(id -u)" -eq 0 ]; then
    chown oracle:oinstall "$ARCHIVE_DEST" || log "警告: 调整目录属主失败"
  fi

  FREE_KB=$(df -Pk "$ARCHIVE_DEST" | awk 'NR==2 {print $4}')
  FREE_GB=$(( FREE_KB / 1024 / 1024 ))
  log "归档目录可用空间: ${FREE_GB} GB"
  [ "$FREE_GB" -ge "$MIN_FREE_GB" ] || die "可用空间不足 ${MIN_FREE_GB} GB,请扩容后重试"
}

# ---------- 状态查询 ----------
get_db_state() {
  sqlplus -S "/ as sysdba" <<'SQL' | tr -d ' \n'
SET HEADING OFF
SET FEEDBACK OFF
SET PAGESIZE 0
SET LINESIZE 200
SET TRIMOUT ON
SET TRIMSPOOL ON
SELECT log_mode || '|' || database_role FROM v$database;
EXIT
SQL
}

# ---------- 开启归档(已归档模式时仅补配置) ----------
configure_online() {
  log "配置归档目标并启动自动归档"
  if [ "$DRY_RUN" = "1" ]; then
    log "[dry-run] 将设置 LOG_ARCHIVE_DEST_1 并启动归档"
    return 0
  fi
  sqlplus -S "/ as sysdba" <<SQL
SET ECHO ON
SET FEEDBACK ON
SET PAGESIZE 200
SET LINESIZE 200
WHENEVER SQLERROR EXIT FAILURE
ALTER SYSTEM SET LOG_ARCHIVE_DEST_1='LOCATION=${ARCHIVE_DEST}' SCOPE=BOTH SID='*';
ALTER SYSTEM ARCHIVE LOG START;
EXIT
SQL
}

switch_archivelog() {
  log "开始切换归档模式(实例将重启)"
  if [ "$DRY_RUN" = "1" ]; then
    log "[dry-run] 将关闭实例、启动到 MOUNT、切换 ARCHIVELOG 后打开"
    return 0
  fi
  sqlplus -S "/ as sysdba" <<SQL
SET ECHO ON
SET FEEDBACK ON
SET PAGESIZE 200
SET LINESIZE 200
WHENEVER SQLERROR EXIT FAILURE
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
ALTER SYSTEM SET LOG_ARCHIVE_DEST_1='LOCATION=${ARCHIVE_DEST}' SCOPE=BOTH SID='*';
ALTER DATABASE ARCHIVELOG;
ALTER DATABASE OPEN;
ALTER SYSTEM ARCHIVE LOG START;
EXIT
SQL
  log "归档模式切换完成"
}

# ---------- 保留时间与清理 ----------
do_retention() {
  command -v rman >/dev/null 2>&1 || { log "警告: 未找到 rman,跳过保留策略配置"; return 0; }

  if [ "$DRY_RUN" = "1" ]; then
    log "[dry-run] 将设置 RMAN 恢复窗口 ${RETENTION_DAYS} 天,并清理 ${RETENTION_DAYS} 天前已备份归档"
    return 0
  fi

  log "设置 RMAN 恢复窗口为 ${RETENTION_DAYS} 天"
  rman target / <<RMAN
CONFIGURE RETENTION POLICY TO RECOVERY WINDOW OF ${RETENTION_DAYS} DAYS;
CONFIGURE ARCHIVELOG DELETION POLICY TO BACKED UP 1 TIMES TO DEVICE TYPE DISK;
CROSSCHECK ARCHIVELOG ALL;
DELETE NOPROMPT EXPIRED ARCHIVELOG ALL;
EXIT
RMAN

  if [ "$DO_CLEANUP" = "1" ]; then
    log "清理 ${RETENTION_DAYS} 天前且已备份至少 1 次的归档日志"
    rman target / <<RMAN
DELETE NOPROMPT ARCHIVELOG UNTIL TIME 'SYSDATE-${RETENTION_DAYS}' BACKED UP 1 TIMES TO DEVICE TYPE DISK;
EXIT
RMAN
  fi
}

# ---------- 结果验证 ----------
verify() {
  sqlplus -S "/ as sysdba" <<'SQL'
SET LINESIZE 200
SET PAGESIZE 200
SET FEEDBACK ON
COLUMN log_mode FORMAT A14
COLUMN open_mode FORMAT A20
COLUMN destination FORMAT A60
COLUMN status FORMAT A10
SELECT log_mode, open_mode FROM v$database;
SELECT dest_id, destination, status, error FROM v$archive_dest WHERE status = 'VALID';
SELECT group#, thread#, sequence#, archived, status FROM v$log ORDER BY thread#, group#;
ARCHIVE LOG LIST;
EXIT
SQL
}

# ---------- 主流程 ----------
log "归档目录: $ARCHIVE_DEST | 保留天数: $RETENTION_DAYS | 清理开关: $DO_CLEANUP | dry-run: $DRY_RUN"
prepare_dir

if [ "$CLEANUP_ONLY" = "1" ]; then
  do_retention
  verify
  log "完成(仅保留策略与清理)"
  exit 0
fi

STATE=$(get_db_state)
LOG_MODE="${STATE%%|*}"
DB_ROLE="${STATE##*|}"
log "当前模式: $LOG_MODE,数据库角色: $DB_ROLE"

[ "$DB_ROLE" = "PRIMARY" ] || die "当前角色为 $DB_ROLE,非主库,禁止执行本脚本"

if [ "$LOG_MODE" = "ARCHIVELOG" ]; then
  log "数据库已处于 ARCHIVELOG 模式,跳过模式切换"
  configure_online
else
  if [ "$ASSUME_YES" != "1" ]; then
    printf '即将重启实例并切换为归档模式,输入 YES 继续: '
    read -r ANSWER
    [ "$ANSWER" = "YES" ] || die "已取消"
  fi
  switch_archivelog
fi

do_retention
verify
log "全部完成"

三、使用方式

# 1) 预检(不修改任何东西)
./enable_archivelog.sh --dest /u01/app/oracle/archivelog --days 7 --dry-run

# 2) 正式执行:创建目录 + 开启归档 + 保留 7 天
./enable_archivelog.sh --dest /u01/app/oracle/archivelog --days 7

# 3) 非交互执行(脚本平台/批量运维)
./enable_archivelog.sh --dest /u01/app/oracle/archivelog --days 7 --yes

# 4) 只做保留策略与过期清理,不切换模式
./enable_archivelog.sh --cleanup-only --days 15

# 5) 每天凌晨 2 点清理一次过期归档(保留 7 天)
0 2 * * * ARCHIVE_DEST=/u01/app/oracle/archivelog RETENTION_DAYS=7 /path/enable_archivelog.sh --cleanup-only --yes >> /var/log/archivelog_cleanup.log 2>&1

四、关键设计说明

1. 目录自动创建
--dest 指定的路径不存在时自动 mkdir -p,权限设为 750;以 root 执行时自动 chown oracle:oinstall。若目标是 ASM(如 +DATA/ARCH),脚本跳过创建,需事先用 asmcmd mkdir 建好目录。

2. 保留时间的两层含义(都已实现)

配置 作用
CONFIGURE RETENTION POLICY TO RECOVERY WINDOW OF N DAYS 定义 RMAN 的恢复窗口,决定 N 天内可恢复到任意时间点所需的备份与归档被保留
DELETE ARCHIVELOG UNTIL TIME 'SYSDATE-N' BACKED UP 1 TIMES 真正删除 N 天前的归档日志,且只删已备份至少 1 次的,避免误删未备份归档
CONFIGURE ARCHIVELOG DELETION POLICY TO BACKED UP 1 TIMES 保证 FRA/归档目录空间回收时也不会删掉未备份的归档

保留天数建议不小于全备周期(例如每周全备一次,则保留 ≥ 8 天),否则恢复链会断。

3. 幂等性
已是 ARCHIVELOG 时不再重启,只补配归档目标并启动归档,可安全重复执行。

4. 风险控制

  • 切换归档需要重启实例,脚本会先要求输入 YES 确认(--yes 可跳过);
  • 执行前校验 DATABASE_ROLE=PRIMARY,物理备库直接拒绝;
  • 任一 SQL 失败即中断,并提示检查实例是否停留在 MOUNT;
  • 目录可用空间低于 --min-free-gb 直接终止,防止归档写满挂库。

五、验证与字段依据

脚本内所有只读查询均已在知识图谱中核对视图与字段(适用 10gR2~26ai):

视图 使用字段 用途
V$DATABASE LOG_MODE、OPEN_MODE、DATABASE_ROLE 判断是否已归档、是否主库
V$ARCHIVE_DEST DEST_ID、DESTINATION、STATUS、ERROR 确认归档目标 VALID 且无报错
V$LOG GROUP#、THREAD#、SEQUENCE#、ARCHIVED、STATUS 确认在线日志可正常归档

执行完成后预期看到:LOG_MODE = ARCHIVELOG、ARCHIVE LOG LIST 显示 Automatic archival: Enabled、V$ARCHIVE_DEST 中目标 STATUS=VALID、ERROR 为空。

六、注意事项

  • 版本:未从你的问题中识别到具体 Oracle 版本,脚本采用 10gR2~23ai 通用语法;LOG_ARCHIVE_DEST_1 的 SID='*' 写法在单实例同样适用。
  • 12c 及以上 CDB:归档模式是 CDB 级属性,脚本须在 CDB 根容器以 SYSDBA 执行,PDB 内无法切换。
  • RAC:归档目录必须是所有节点可见的共享存储(ACFS/NFS/ASM),否则各节点归档会写到本地盘,无法互相恢复。
  • SQL 校验说明:脚本中的 ALTER DATABASE ARCHIVELOG、ALTER SYSTEM SET ...、ALTER SYSTEM ARCHIVE LOG START 属于 Oracle 管理类 DDL,当前 SQL 解析器不支持该语法类别(返回 parse_error),因此未能通过工具自动校验;这些是 Oracle 标准管理命令,建议先在测试库执行一遍再上生产。只读查询部分已全部校验通过。
  • 与本机备份平台的关系:开启归档只解决 ORA-19602;本机仍无 rman 客户端,需在备份平台把该 Oracle 服务器纳管为 SSH 主机,远端 RMAN 才能执行。

posted on 2026-11-02 17:02  刘子毅  阅读(8)  评论(0)    收藏  举报

导航