怎样实现定期清理归档日志

wen 实用脚本 28

本文目录导读:

怎样实现定期清理归档日志

  1. 核心原则
  2. Oracle 数据库:最规范的方式
  3. PostgreSQL:结合 pg_archivecleanup
  4. 通用 Linux/文件级方法(不依赖特定数据库工具)
  5. 定时任务配置(以 Linux crontab 为例)
  6. 常见问题与排查
  7. 总结建议

实现定期清理归档日志(Archive Log)是数据库运维中一项至关重要的任务,特别是对于归档模式下的Oracle、PostgreSQL或SQL Server等数据库,日志文件若不加以控制,会迅速耗尽磁盘空间,导致数据库挂起甚至崩溃。

下面我将分别介绍OraclePostgreSQL通用Linux环境下的主流实现方法。

核心原则

在自动化清理之前,请务必确认:

  1. 备份有效:确保这些归档日志已经被备份到了远程或磁带介质上。
  2. 保留策略:明确“保留最近N天”或“保留到下一个完整备份”的策略。
  3. 一致性:不要手动删除正在被Data Guard(数据卫士)或备用库使用的归档日志。

Oracle 数据库:最规范的方式

Oracle不推荐简单的rm命令(虽然也能用),因为它会破坏RMAN(Recovery Manager,恢复管理器)的元数据。

最佳实践:使用 RMAN 脚本 + CRON

步骤 1:创建 RMAN 删除脚本 (/u01/scripts/del_arch.sh)

#!/bin/bash
export ORACLE_SID=ORCL
export ORACLE_HOME=/u01/app/oracle/product/19.0.0/dbhome_1
export PATH=$ORACLE_HOME/bin:$PATH
LOG=/u01/logs/rman_del_arch_$(date +%Y%m%d).log
rman target / log=${LOG} <<EOF
# 删除超过 7 天的已备份归档日志
DELETE ARCHIVELOG ALL COMPLETED BEFORE 'SYSDATE-7';
# 或者删除超过 3 天且已备份的 (更安全)
# DELETE ARCHIVELOG ALL COMPLETED BEFORE 'SYSDATE-3' BACKED UP 1 TIMES TO DISK;
EXIT;
EOF

说明

  • COMPLETED BEFORE 'SYSDATE-7':保留最近7天的归档。
  • BACKED UP 1 TIMES:确保只删除那些至少已经被备份过一次的日志。

步骤 2:添加定时任务

# crontab -e
# 每天凌晨 2 点执行
0 2 * * * /bin/bash /u01/scripts/del_arch.sh > /dev/null 2>&1

PostgreSQL:结合 pg_archivecleanup

PostgreSQL的归档日志通常通过archive_command生成,清理需要配合pg_archivecleanup工具,并利用restore_command或定期任务。

场景 A:使用 pg_archivecleanup 配合复制

这是最推荐的方法,通常在recovery.confarchive_cleanup_command中配置。

配置(在备用库或主库上):

-- 在主库的 postgresql.conf 中设置
archive_cleanup_command = 'pg_archivecleanup /path/to/archive_dir %r'
-- %r 是恢复过程中最后使用的 WAL 文件名,超过它的日志会被自动清理

场景 B:定期任务脚本(无流复制时)

#!/bin/bash
#!/bin/bash
export PGHOME=/usr/pgsql-14
export PATH=$PGHOME/bin:$PATH
ARCHIVE_DIR=/var/lib/pgsql/14/archive_wals
RETENTION_DAYS=7
echo "Deleting WALs older than ${RETENTION_DAYS} days..."
# 使用 find 结合 pg_archivecleanup 或直接判断时间
# find 用于找出文件,然后逐一调用 pg_archivecleanup 清理
find ${ARCHIVE_DIR} -type f -name "0000000100000*" -mtime +${RETENTION_DAYS} | while read wal_file
do
  filename=$(basename $wal_file)
  # 确保该WAL已经被归档并且不再需要(可以通过pg_stat_archiver检查)
  pg_archivecleanup ${ARCHIVE_DIR} ${filename} 2>&1
done

关键点:PostgreSQL的WAL(Write-Ahead Logging,预写式日志)清理必须事先确保该WAL文件已经被应用或不需要用于恢复。


通用 Linux/文件级方法(不依赖特定数据库工具)

如果你的数据库(如MySQL、国产数据库,或简单的日志文件)没有提供类似RMAN的工具,可以采用find + grep + rm

通用清理脚本 (clean_archive.sh)

#!/bin/bash
ARCHIVE_DIR="/u01/archivelog/"
RETENTION_DAYS=5
LOG_FILE="/var/log/archive_cleanup.log"
echo "$(date) - Starting cleanup of archives older than ${RETENTION_DAYS} days" >> ${LOG_FILE}
# 1. 安全遍历:找到文件后,先检查是否为当前数据库实例使用的文件
# 2. 使用 -delete 直接删除(测试时建议 -print 代替 -delete)
find ${ARCHIVE_DIR} -type f -mtime +${RETENTION_DAYS} -name "*.arc" -o -name "*.log" | while read file
do
    # 检查文件是否被数据库或备份进程持有(fuser 命令)
    if ! fuser -s "$file" 2>/dev/null; then
        rm -fv "$file" >> ${LOG_FILE}
    else
        echo "Skipping locked file: $file" >> ${LOG_FILE}
    fi
done
# 3. 清理空目录
find ${ARCHIVE_DIR} -type d -empty -delete
echo "$(date) - Cleanup completed" >> ${LOG_FILE}

重要安全措施

  • fuser -s:检查文件是否被数据库进程打开(避免“活锁”)。
  • -mtime:指定过期的天数。
  • -name:匹配日志扩展名,防止误删重要文件。

定时任务配置(以 Linux crontab 为例)

编辑crontab:

crontab -e
```需根据实际脚本路径调整):
```cron
# Oracle RMAN 清理 - 每天凌晨 2:30
30 2 * * * /bin/bash /u01/scripts/del_arch.sh > /dev/null 2>&1
# PostgreSQL 清理 - 每天凌晨 3:00
0 3 * * * /bin/bash /var/lib/pgsql/scripts/pg_cleanup.sh
# 通用日志清理 - 每小时检查一次(对于高负载系统)
0 * * * * /root/scripts/clean_general_archives.sh > /dev/null 2>&1

常见问题与排查

问题现象 可能原因 解决方案
磁盘空间仍被不断耗尽 清理频率不够 增加定时任务频率,或设置阈值告警
RMAN 报错 ORA-19625 手动删除了归档文件 使用CROSSCHECK ARCHIVELOG ALL;同步RMAN目录,然后DELETE EXPIRED ARCHIVELOG ALL;
PostgreSQL 无法启动 错误删除了当前需要的 WAL 检查archive_status目录,确保保留最后的WAL文件
普通文件清理误删系统文件 通配符写错或未加-name限制 先在测试环境执行find-print选项,确认无误后再启用

总结建议

  1. 优先使用数据库自带的工具(Oracle用RMAN,PG用pg_archivecleanup),它们对元数据和一致性有保障。
  2. 对于无工具的环境,采用先备份后删除的策略,并且务必使用fuser检查文件是否被占用。
  3. 监控前置:在清理脚本运行之前,最好通过df -h或Zabbix等工具设置磁盘使用率告警(如达到85%就触发),而不是等到100%才处理。
  4. 定期测试恢复:清理策略再完美,也需要定期从备份介质中恢复一次归档日志,确保真正需要时数据能找回。

抱歉,评论功能暂时关闭!