数据库故障排查:常见错误码、日志分析、系统资源监控、诊断脚本
做嵌入式数据库开发这些年,我遇到过不少"跑着跑着就挂了"的情况。说实话,数据库出问题不可怕,可怕的是你不知道从哪下手。今天我就把压箱底的排查思路捋一捋,希望能帮你少走些弯路。
一、常见错误码:读懂数据库的"求救信号"
每个错误码背后都有故事。我习惯把错误码分成三类:连接类、存储类、逻辑类。
| 错误码 | 含义 | 常见原因 |
|---|---|---|
| SQLITE_BUSY (5) | 数据库被锁住 | 多线程并发写操作,未设置超时 |
| SQLITE_FULL (13) | 磁盘空间不足 | 日志文件暴涨,或数据文件撑满分区 |
| SQLITE_CORRUPT (11) | 数据库文件损坏 | 意外断电、文件系统异常 |
| SQLITE_IOERR (10) | I/O 操作失败 | 存储介质故障、权限问题 |
| SQLITE_NOMEM (7) | 内存分配失败 | 堆内存耗尽,或碎片过多 |
我的小习惯:每次拿到错误码,先查官方文档确认含义,别靠猜。我曾经因为把 SQLITE_BUSY 当成死锁,折腾了一整天,结果只是没设 busy_timeout。
二、日志分析:从蛛丝马迹中找到根因
日志是数据库的"黑匣子"。我一般按这个顺序翻日志:
- 先看错误日志——找 ERROR 或 FATAL 级别的记录
- 再看慢查询日志——定位性能瓶颈
- 最后看系统日志——确认是否有外部干扰
举个例子,有一次客户反馈数据库写入特别慢。我打开慢查询日志,发现有个 UPDATE 语句跑了 3 秒多。再一看,那张表没有建索引,全表扫描了 50 万行。加了个索引,问题秒解。
日志分析三要素:
- 时间戳——确认问题发生的时间窗口
- 线程 ID——追踪并发冲突
- 操作类型——区分读写还是元数据操作
三、系统资源监控:别让数据库"饿死"
数据库跑不动,很多时候不是它自己的问题,而是系统资源被抢光了。我常用的监控指标有这几个:
- CPU 使用率——超过 80% 就要警惕
- 内存占用——看 RSS 和 Swap 使用量
- 磁盘 I/O——iowait 高说明磁盘是瓶颈
- 文件描述符——嵌入式设备容易漏关句柄
你想想看,如果磁盘 I/O 已经 100%,数据库再怎么优化 SQL 也没用。我曾在某款 IoT 设备上遇到过,日志轮转没做好,一天就写满了 2GB 的 TF 卡,数据库直接报 SQLITE_FULL。
注意:嵌入式设备资源有限,别把 PC 端的监控思路直接搬过来。我建议用 top、iostat、vmstat 这些轻量工具,别装 agent。
四、诊断脚本:把排查流程自动化
手动排查太慢了。我写了个小脚本,一键收集关键信息。核心思路就三步:
- 收集系统资源快照
- 检查数据库文件完整性
- 导出最近 100 条错误日志
#!/bin/sh
# 嵌入式数据库诊断脚本
echo "=== 系统资源 ==="
free -m
df -h
iostat -x 1 3
echo "=== 数据库完整性 ==="
sqlite3 /data/mydb.db "PRAGMA integrity_check;"
echo "=== 最近错误日志 ==="
tail -100 /var/log/db_error.log
echo "=== 当前连接数 ==="
lsof | grep mydb.db | wc -l
这个脚本我用了好几年,每次出问题先跑一遍,80% 的情况能直接定位。剩下的 20%,再结合业务逻辑慢慢分析。
避坑指南:我曾经在脚本里直接调用了 VACUUM,结果生产环境跑了一半磁盘满了,数据库直接锁死。诊断脚本只做只读操作,别写数据。
五、知识体系总览
下面这张图是我梳理的排查框架,你可以照着这个顺序来,基本不会漏掉关键环节。
说白了,数据库故障排查就是个"排除法"。先看错误码,再翻日志,接着查资源,最后用脚本收尾。按这个顺序走,基本不会漏。
嗯,今天就聊到这儿。这些经验都是真金白银换来的,希望能帮到你。