我们公司有一台跑着达梦数据库的服务器,平时稳稳当当的,结果有一天,所有业务突然卡死了,页面打不开,后台报错连不上数据库。运维同事火急火燎地跑过来,说数据库挂起了。挂起是什么感觉?就像你在高速上开车,突然踩了刹车,发动机还在转,但就是动不了。经过一番排查,发现罪魁祸首是日志归档空间满了。数据库因为没法写入新的归档日志,直接进入了“挂起”状态,所有读写操作都被堵住了。这事儿看着吓人,其实解决起来有套路,而且防患于未然更重要。下面我就把整个来龙去脉和解决方法掰扯清楚。

一、问题重现:数据库突然“罢工”了

想象一下,你家里的垃圾桶满了,你还拼命往里扔垃圾,结果垃圾桶撑爆了,垃圾撒了一地,你连门都打不开。达梦数据库的归档日志空间就是那个垃圾桶。数据库在运行过程中,会产生很多日志文件(叫做归档日志),这些文件是用于灾难恢复的。如果归档空间满了,数据库没法继续写日志,为了保证数据一致性,它会把自己冻结起来——这就是挂起。

我遇到过的情况是,数据库运行了几个月,归档目录默认放在一个很小的磁盘分区上,随着业务量增大,日志越积越多,分区被占满。数据库突然报错“归档日志空间不足”,然后所有连接都被拒绝,应用程序超时。这时候你连进去查SQL都困难,因为控制台也连不上(如果已经挂死)。解决办法是先从操作系统层面释放空间,再让数据库恢复正常。

二、为什么日志归档空间不够会导致挂起?

达梦数据库有两种日志模式:非归档模式和归档模式。生产环境一般都开归档模式,因为为了保证数据不丢,归档日志要完整保存。数据库在运行中,每切换一次日志文件,就会把旧的日志文件拷贝到归档目录下。如果归档目录满了,数据库写不进去新的归档文件,它不知道该怎么办,干脆罢工——这就是挂起的原因。

你可以把归档日志想象成快递单号,每笔交易都对应一张单子。如果装单子的柜子满了,新单子没地方放,快递员就只能停下手里的活,等着你清柜子。数据库也一样,它宁可停止服务,也不愿意丢失数据痕迹。所以,解决这个问题最直接的办法就是:清理掉没用的旧归档日志,腾出空间。

三、手把手解决:快速清理归档日志

当数据库已经因为归档空间不足挂起时,第一步不是登录数据库(因为很可能已经连不上),而是直接登录操作系统,手动删除或转移部分归档日志文件,让数据库能喘口气。下面以Linux环境为例,演示具体操作。

3.1 查看当前归档使用情况

首先,用操作系统命令看一下归档目录占了多少空间。

# 假设归档目录是 /dmdata/arch
df -h /dmdata/arch

# 或者看目录下文件大小总和
du -sh /dmdata/arch

# 列出目录下所有归档文件,按时间排序
ls -lth /dmdata/arch/*.log

一般归档文件命名类似 ARCH_20250401_000001.log,每个文件几十到几百兆。如果目录占用接近100%,问题就明确了。

3.2 手动清理过期归档日志

如果数据库挂起了,你先手动删掉一些明显很旧的文件。比如只保留最近7天的日志,其余删除。

# 删除7天前的归档文件
find /dmdata/arch -name "*.log" -mtime +7 -exec rm -f {} \;

# 注意:如果数据库是正常运行的,删除前最好确认这些日志对应的备份已经存在
# 现在只是应急,先释放空间再说

删除完成后,用 df -h 查看磁盘使用率是否降下来。通常释放个10%到20%的空间就够数据库恢复了。

3.3 让数据库脱离挂起状态

空间释放后,你可以用达梦自带的工具连接数据库,执行一条命令让数据库恢复正常。

-- 技术栈:达梦数据库SQL
-- 以DBA身份登录(假设SYSDBA密码已知)
-- 如果挂起状态下无法连上,可以使用命令行工具 disql

-- 先查看数据库状态
SELECT STATUS$ FROM V$INSTANCE;

-- 如果状态是 SUSPEND,执行以下命令解除挂起
ALTER DATABASE RECOVER WITH ARCHIVELOG;

-- 然后切换日志,让归档能正常写入
ALTER SYSTEM SWITCH LOGFILE;

-- 再次查看状态,应该是 OPEN 或 MOUNT
SELECT STATUS$ FROM V$INSTANCE;

如果数据库没有完全挂死,而是有连接但报错归档空间不足,那么直接执行 ALTER SYSTEM SWITCH LOGFILE 可能会报错,需要先清理空间再切换。

3.4 设置自动清理策略(预防再次发生)

手动清理是救火,长期来看要配置自动清理。达梦数据库自带归档日志删除功能,可以基于时间或保留个数来清理。

-- 技术栈:达梦数据库SQL
-- 开启自动归档删除(保留最近7天的日志)
SP_SET_PARA_VALUE(1, 'ARCH_DEL_DAYS', 7);

-- 或者按保留个数,比如保留100个日志文件
SP_SET_PARA_VALUE(1, 'ARCH_DEL_NUM', 100);

-- 修改后立即生效,不需要重启
-- 验证参数是否生效
SELECT PARA_NAME, PARA_VALUE FROM V$DM_INI WHERE PARA_NAME LIKE 'ARCH_DEL%';

这里解释一下参数含义:ARCH_DEL_DAYS 表示每天自动删除超过该天数的归档日志,ARCH_DEL_NUM 表示在归档日志总数超过该值时,自动删除最旧的部分。一般生产环境建议两者都设置,以保底。

四、如何预防再次发生:归档日志管理方案

我们已经知道,归档空间不足会挂起数据库,那么平时就要做好规划和管理。这里分享几个实用的方案。

4.1 合理规划归档空间

不要把归档目录放在系统根分区或空间很小的分区。最好单独挂载一个大的磁盘,比如200GB或更大,根据业务量预估。可以用以下命令计算日志生成速率:

# 统计最近一小时生成的归档文件大小总和
find /dmdata/arch -name "*.log" -newer /tmp/timefile -type f -exec ls -l {} \; | awk '{sum+=$5} END {print sum/1024/1024 " MB"}'

得到每小时生成量后,乘以24再乘以保留天数,就可以算出需要的空间。例如每小时100MB,保留7天,就需要约16.8GB。再预留50%的余量,就是25GB。

4.2 启用自动归档清理任务

除了数据库自身的自动删除,还可以结合系统crontab脚本定时清理,双重保险。

# 在Linux上添加定时任务,每天凌晨2点执行归档清理
# 编辑crontab: crontab -e
# 添加如下一行:
0 2 * * * /dmdata/scripts/clean_arch.sh

脚本内容:

#!/bin/bash
# 技术栈:Shell脚本
# 清理超过30天的归档日志文件,但保留最近一次备份后的日志
ARCH_DIR="/dmdata/arch"
BACKUP_LOG="/dmdata/backup/backup_control.log"

# 如果备份日志文件存在,获取最后一次备份时间
if [ -f "$BACKUP_LOG" ]; then
    LAST_BACKUP_DATE=$(tail -1 $BACKUP_LOG | awk '{print $1}')
else
    LAST_BACKUP_DATE=$(date --date="7 days ago" +%Y%m%d)
fi

# 删除所有归档日期早于最后一次备份日期的日志
find $ARCH_DIR -name "*.log" ! -newermt "$LAST_BACKUP_DATE" -type f -delete

# 记录日志
echo "$(date '+%Y-%m-%d %H:%M:%S') 已清理归档日志,保留自 $LAST_BACKUP_DATE 以来的文件" >> /var/log/clean_arch.log

注意,删除之前要确保这些日志对应的全量备份已经存在,否则灾难恢复时可能缺链。

4.3 监控告警机制

光有清理还不够,万一清理任务失败了呢?所以要监控归档空间使用率,达到80%就报警。可以利用Prometheus+Grafana,或者简单的脚本发送邮件。

#!/bin/bash
# 技术栈:Shell脚本
# 检查归档目录使用率
USAGE=$(df /dmdata/arch | awk 'NR==2 {print $5}' | sed 's/%//')
THRESHOLD=80
if [ "$USAGE" -gt "$THRESHOLD" ]; then
    echo "归档目录使用率 $USAGE%,超过阈值 $THRESHOLD%" | mail -s "Database Archive Space Alert" dba@example.com
fi

把这个脚本放到crontab里每半小时执行一次,就能提前发现问题。

五、应用场景与优缺点分析

应用场景

  • 任何使用达梦数据库并开启归档模式的生产系统,尤其是不允许停机、数据敏感的业务。
  • 日志量较大、磁盘空间有限的环境,例如云服务器默认只有40G系统盘。
  • 缺少专业DBA、运维自动化程度较低的小团队或初创公司。

技术优缺点

  • 优点:通过清理过期日志释放空间,成本低,操作简单,能快速恢复服务。
  • 缺点:手工删除日志存在风险,如果误删了未备份的日志,导致无法恢复数据。自动清理策略依赖稳定的备份节奏,如果备份失败或者延迟,日志可能过早被删。

六、注意事项

  1. 先备份再删除:生产环境删除归档日志前,最好确保这些日志对应的全量备份已经完成并可用。可以先用 ckpt 命令检查哪些日志已被备份。
  2. 不要随意删除当前正在使用的日志文件:达梦数据库的在线日志(redo log)不能手动删除,那是数据库自己管理的内存文件。删了会导致数据库崩溃。我们只清理归档目录下的文件。
  3. 挂起状态下的操作顺序:先释放操作系统空间,再执行 ALTER DATABASE RECOVER 命令,如果先连数据库执行命令,可能因为空间不足而失败。
  4. 参数调优ARCH_DEL_DAYSARCH_DEL_NUM 两个参数同时设置时,生效规则是:先判断个数是否超限,再判断天数。比如设置保留10个文件,即使文件还没到7天,只要个数超出就会删除。建议根据实际日志生成量算好后合理设置。

七、文章总结

达梦数据库因归档日志空间不足而挂起是一个典型的“容灾痼疾”,但只要我们理解它的原因——归档目录满了导致数据库自我保护——就能迅速找到对策。应急时手动清理旧日志、执行解除挂起命令;长期来看,合理规划磁盘、启用自动清理策略、增加监控告警,这三板斧就能让数据库安稳运行。整个过程中,数据库并没有真正的损伤,只是需要人为干预一下“垃圾清理”而已。记住,预防胜于治疗,平时多看一眼磁盘使用率,就能避免一次业务中断。