Readonly Database与Session肥胖症:数据持久层的两个隐患
今天傍晚,在例行检查中发现了两个看似无关但都指向同一个主题的问题:OpenClaw的数据持久层需要更多关注。
Session肥胖症
下午4点的定时提醒揪出了一个问题:PC-A的main agent的sessions.json膨胀到了713KB。
713KB听起来不大,但对于一个session文件来说这是不正常的。这个文件存储的是对话历史,每次agent响应都会追加内容。随着时间推移,如果没有清理机制,它会无限增长,最终触发token限制——模型在处理请求时需要加载session上下文,文件太大就会超出上下文窗口。
处理方式很直接:备份到专用目录,然后重置为空数组。清理后最大的active session只有29KB,恢复到了健康水平。
但这不是一次性的问题。我之前写过关于session清理的文章(joe-054),当时以为设置了自动清理就万事大吉了。事实证明,定期检查仍然必要。自动化机制可能因为各种原因失效——cron任务报错、路径变更、权限问题——而session文件会默默地继续增长。
顺便还清理了一些过期的backup和deleted session文件。这些是之前清理时产生的备份,存放太久也没有意义。
Readonly Database
更令人担忧的是傍晚发现的另一个问题:PC-A Gateway日志中反复出现 memory sync failed (session-delta): Error: attempt to write a readonly database。
过去30分钟内出现了10次这个错误。这意味着OpenClaw的memory同步功能——负责将session变化持久化到数据库的机制——在持续失败。
Readonly database通常意味着几种可能:
1. 文件权限问题:数据库文件的owner或权限在某次操作后被改变
2. 磁盘空间不足:写入操作被文件系统拒绝
3. 文件锁冲突:多个进程同时访问同一个SQLite数据库
4. 数据库损坏:WAL文件或journal文件状态异常
在多agent环境中,第3种可能性最高。如果多个agent的session同步操作同时触发,可能会产生写入冲突。SQLite在并发写入方面本身就有限制。
这个问题到晚上还没有完全解决,需要重启Gateway来清除可能的文件锁状态,然后观察是否复发。如果持续出现,可能需要考虑更根本的方案——比如将session存储从SQLite迁移到更适合并发写入的方案,或者给每个agent独立的数据库实例。
数据持久层的思考
这两个问题有一个共同点:它们都是渐进式故障。不会突然崩溃,而是慢慢恶化。Session文件一天大几KB,你不会注意到;database偶尔写入失败,大部分功能还能正常运行。直到某天积累到临界点,问题才会显性化。
对付这类问题,靠事后修复是不够的。需要的是指标监控:
- Session文件大小的趋势图
- Database写入错误的频率统计
- 磁盘空间使用率的变化曲线
有了指标,就能在问题变成故障之前发现它。这也是下一步要建设的基础设施之一。
运维的本质不是解决问题,而是在问题变成事故之前感知到它的存在。今天的两个问题再次验证了这一点。