Oracle 开启归档日志自动化脚本
一、脚本能力说明
脚本 enable_archivelog.sh 完成四件事:
- 归档目录不存在时自动创建,并设置权限、校验可用空间;
- 判断当前模式:已是 ARCHIVELOG 则跳过重启,仅补配归档目标;NOARCHIVELOG 则重启并切换;
- 配置归档目标
LOG_ARCHIVE_DEST_1并启动自动归档; - 设置归档保留时间: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 才能执行。
浙公网安备 33010602011771号