SQLite虽然是一个轻量级的嵌入式数据库,但在很多生产环境中承担着重要角色,比如日志存储、配置中心、IoT设备数据落盘等。一旦数据库文件异常膨胀、磁盘写满或者出现长时间的锁等待,上层业务会直接受影响。Zabbix默认模板并不提供SQLite监控项,所以这篇文章就来实战演示如何通过自定义UserParameter把SQLite的各项指标接入Zabbix,实现集中监控和告警。

一、SQLite有哪些值得监控的指标
在动手写监控脚本之前,先要明确采集什么。SQLite不是C/S架构的数据库,没有像MySQL那样现成的SHOW STATUS命令,它的监控主要围绕数据库文件本身和PRAGMA指令输出的状态信息展开。
第一个是数据库文件大小。SQLite是单文件数据库,db.sqlite这个文件的体积直接反映了数据量增长情况。特别是开启了WAL模式之后,除了主数据库文件,还会有-wal和-shm两个附属文件,如果应用忘记checkpoint,wal文件可能膨胀到几个GB,把磁盘吃满。监控这三个文件的大小非常必要。
第二个是页统计信息。通过PRAGMA page_count、PRAGMA page_size、PRAGMA freelist_count可以拿到总页数、页大小和空闲页数。空闲页比例过高说明数据库经过大量删除操作后产生了碎片,这时候就需要考虑执行VACUUM来回收空间。计算公式是freelist_count除以page_count,如果超过20%就应该告警。
第三个是完整性和锁状态。PRAGMA integrity_check能检测数据库是否损坏,不过这个命令在大库上执行很慢,建议低频采集(比如一天一次)。另外可以用PRAGMA journal_mode确认当前日志模式是否为预期的wal,模式被意外改动往往意味着配置被人为修改过。
二、编写SQLite状态采集脚本
采集脚本建议用Bash编写,放在/etc/zabbix/scripts/目录下,由Zabbix Agent调用。脚本接收两个参数:数据库文件路径和要采集的指标名称,这样一套脚本就能覆盖多个数据库实例,避免为每个库写一份重复代码。
下面是一个完整的脚本示例,先判断数据库文件是否存在,再根据第二个参数分发到不同的采集逻辑。注意所有sqlite3命令都加了超时控制,防止数据库被锁住时脚本卡死拖垮Agent进程。
#!/bin/bash
# 用法: sqlite_status.sh <db_file> <metric>
DB_FILE="$1"
METRIC="$2"
# 文件不存在直接返回错误,Zabbix会显示ZBX_NOTSUPPORTED
if [ ! -f "$DB_FILE" ]; then
echo "ZBX_NOTSUPPORTED: db file not found"
exit 1
fi
case "$METRIC" in
filesize)
# 主库文件加wal文件的总大小,单位字节
SIZE=$(stat -c %s "$DB_FILE")
WAL_FILE="${DB_FILE}-wal"
if [ -f "$WAL_FILE" ]; then
SIZE=$((SIZE + $(stat -c %s "$WAL_FILE")))
fi
echo "$SIZE"
;;
page_count)
timeout 5 sqlite3 "$DB_FILE" "PRAGMA page_count;"
;;
freelist_count)
timeout 5 sqlite3 "$DB_FILE" "PRAGMA freelist_count;"
;;
page_size)
timeout 5 sqlite3 "$DB_FILE" "PRAGMA page_size;"
;;
journal_mode)
timeout 5 sqlite3 "$DB_FILE" "PRAGMA journal_mode;"
;;
wal_size)
WAL_FILE="${DB_FILE}-wal"
if [ -f "$WAL_FILE" ]; then
stat -c %s "$WAL_FILE"
else
echo 0
fi
;;
integrity)
RESULT=$(timeout 60 sqlite3 "$DB_FILE" "PRAGMA integrity_check;" 2>/dev/null | head -1)
if [ "$RESULT" = "ok" ]; then echo 1; else echo 0; fi
;;
*)
echo "ZBX_NOTSUPPORTED: unknown metric"
exit 1
;;
esac
脚本写好后记得赋予执行权限:chmod +x /etc/zabbix/scripts/sqlite_status.sh。可以先手动跑一遍验证输出,比如./sqlite_status.sh /data/app/mydb.sqlite page_count,确认能正常返回数字。还要注意运行Agent的用户(通常是zabbix)需要对数据库文件所在目录有读权限,否则会采集失败。
三、配置Zabbix Agent的UserParameter
脚本就绪后,接下来在/etc/zabbix/zabbix_agentd.conf末尾添加自定义监控参数。UserParameter的语法是UserParameter=键值[*],命令,方括号里的星号表示接受任意参数,命令中的$1、$2对应传进来的第一个和第二个参数。
# SQLite自定义监控项 # 参数1为数据库文件路径,参数2为指标名 UserParameter=sqlite.status[*],/etc/zabbix/scripts/sqlite_status.sh "$1" "$2"
这里有一个非常经典的坑要提醒:在zabbix_agentd.conf中写UserParameter时,参数引用要写成$1而不是1。如果不加反斜杠,Zabbix Agent会把$1解析成Agent自己的位置参数导致内容为空,传给脚本的就变成了空字符串,这是新手配置自定义监控项时最常见的报错原因。改完配置后重启Agent:systemctl restart zabbix-agent。
然后在被监控机或Zabbix Server上用zabbix_get工具做连通性测试。命令格式为zabbix_get -s 被监控机IP -k 'sqlite.status[/data/app/mydb.sqlite,page_count]',注意键值里的方括号和逗号,路径中如果包含空格需要谨慎处理,建议数据库文件路径不要带空格。返回数字说明整条链路已经通了。
四、在Zabbix前端创建监控项与触发器
链路测试通过后,就可以在Zabbix前端配置了。进入主机的监控项列表,点击创建监控项,名称写成类似SQLite database size这样的描述,键值填sqlite.status[/data/app/mydb.sqlite,filesize],信息类型选数字(无正负),单位填B,更新间隔根据指标重要性设置,文件大小这类指标5到10分钟采集一次就够了,integrity这种重量级检查建议设为1h甚至更长。
常用的几条监控项可以整理成如下清单,方便逐条创建:
sqlite.status[/data/app/mydb.sqlite,filesize]:数据库总大小,单位Bsqlite.status[/data/app/mydb.sqlite,wal_size]:wal文件大小,单位Bsqlite.status[/data/app/mydb.sqlite,freelist_count]:空闲页数量sqlite.status[/data/app/mydb.sqlite,journal_mode]:日志模式,文本类型sqlite.status[/data/app/mydb.sqlite,integrity]:完整性检查结果,1正常0异常
监控项建好之后是触发器。针对文件大小可以设置两条:一条是硬阈值告警,比如表达式{host:sqlite.status[/data/app/mydb.sqlite,filesize].last()}>10737418240表示超过10GB触发严重告警;另一条是增长率告警,用avg函数配合#num参数,例如最近5次采样的平均值比再之前5次高出50%就触发警告,这种动态基线比死阈值更灵敏,能提前发现异常写入。
空闲页比例的触发器需要一点小技巧,因为Zabbix表达式中不能直接做两个监控项的除法判断比例,可以建一个可计算监控项,公式写成last(sqlite.status[/data/app/mydb.sqlite,freelist_count])/last(sqlite.status[/data/app/mydb.sqlite,page_count])*100,然后对这个计算结果设置阈值,大于20触发碎片整理提醒。
五、常见问题排查与优化建议
实际部署中总会遇到几个典型问题。第一种是前端报ZBX_NOTSUPPORTED,多半是脚本没有执行权限、路径写错或者metric名称拼写不对,回到Agent机器上手动执行脚本就能定位。第二种是采集值一直为空或报权限错误,检查/var/log/zabbix/zabbix_agentd.log,通常是zabbix用户读不了数据库文件,用sudo -u zabbix ./sqlite_status.sh模拟执行即可复现。
第三种是数据断断续续。如果SQLite正在被应用频繁写入,脚本里的sqlite3命令可能碰到database is locked,timeout控制虽然保证了脚本不死等,但会导致该周期数据缺失。解决办法是给只读查询加上.timeout 3000参数,或者在脚本中用PRAGMA query_only降低锁冲突概率,同时把采集间隔适当放宽。
最后一点优化建议:如果服务器上有多个SQLite数据库要监控,不必为每个库复制一遍UserParameter,现有的通配键值已经支持。可以考虑用低级别发现(LLD)自动发现指定目录下的所有.sqlite文件,配合原型监控项批量生成,这样新增数据库时零手工配置,维护成本会低很多。整套方案跑通之后,SQLite这个平时最容易被忽视的小数据库也能享受和企业级数据库同等的监控待遇了。
SQLite监控Zabbix自定义监控项UserParameter修改时间:2026-09-09 16:43:26