本文目录导读:

- 核心原则
- Oracle 数据库:最规范的方式
- PostgreSQL:结合 pg_archivecleanup
- 通用 Linux/文件级方法(不依赖特定数据库工具)
- 定时任务配置(以 Linux crontab 为例)
- 常见问题与排查
- 总结建议
实现定期清理归档日志(Archive Log)是数据库运维中一项至关重要的任务,特别是对于归档模式下的Oracle、PostgreSQL或SQL Server等数据库,日志文件若不加以控制,会迅速耗尽磁盘空间,导致数据库挂起甚至崩溃。
下面我将分别介绍Oracle、PostgreSQL和通用Linux环境下的主流实现方法。
核心原则
在自动化清理之前,请务必确认:
- 备份有效:确保这些归档日志已经被备份到了远程或磁带介质上。
- 保留策略:明确“保留最近N天”或“保留到下一个完整备份”的策略。
- 一致性:不要手动删除正在被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.conf或archive_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选项,确认无误后再启用 |
总结建议
- 优先使用数据库自带的工具(Oracle用RMAN,PG用
pg_archivecleanup),它们对元数据和一致性有保障。 - 对于无工具的环境,采用先备份后删除的策略,并且务必使用
fuser检查文件是否被占用。 - 监控前置:在清理脚本运行之前,最好通过
df -h或Zabbix等工具设置磁盘使用率告警(如达到85%就触发),而不是等到100%才处理。 - 定期测试恢复:清理策略再完美,也需要定期从备份介质中恢复一次归档日志,确保真正需要时数据能找回。