SQLite WAL 模式踩坑笔记:高并发读写下的几个细节

最近把一个内部服务的存储从 PostgreSQL 换成 SQLite + WAL 模式,跑了一个多月,遇到几个不太显眼但挺关键的坑,记录一下。

为什么用 WAL

默认的 rollback journal 模式在写事务期间会阻塞所有读,对我们这种"读多写少但读不能停"的场景非常不友好。WAL(Write-Ahead Logging)的好处是:

  • 读和写互不阻塞

  • 多个读事务可以并发执行

  • 写性能在多数场景下更好

开启方式很简单:

```sql

PRAGMA journal_mode=WAL;

```

这个 pragma 是持久的,设一次后数据库文件本身的 header 就改了,下次连接不用重设。

坑 1:`-shm` 和 `-wal` 文件不能漏

WAL 模式下数据库会变成三个文件:

```

mydb.sqlite

mydb.sqlite-shm

mydb.sqlite-wal

```

备份脚本如果只复制主文件,恢复出来的数据会是上次 checkpoint 时的状态,**最近的写会全部丢**。正确做法是先调用 `PRAGMA wal_checkpoint(TRUNCATE);` 把 WAL 落盘清空,再复制主文件。或者直接用 SQLite 的在线备份 API(`sqlite3_backup_init`)。

坑 2:`busy_timeout` 必须显式设

WAL 不是万能的。写事务之间还是互斥的,如果两个进程同时尝试写,后来的会立即拿到 `SQLITE_BUSY`。默认 busy handler 直接返回错误,应用层就要写一堆重试逻辑。更好的做法是:

```sql

PRAGMA busy_timeout=5000;

```

这样 SQLite 会在内部等待最多 5 秒,期间持续重试拿写锁。注意这是**每个连接**都要单独设的,不会从某个全局配置继承。

坑 3:长读事务会让 WAL 无限增长

WAL checkpoint 只能 checkpoint 那些已经被所有 reader 看完的页。如果有一个长读事务一直挂着(比如一个忘记关掉的 cursor),WAL 文件会持续增长,永远 checkpoint 不掉。我们生产环境出现过 WAL 涨到 30GB 的情况。

排查方法是查看 `PRAGMA wal_checkpoint(PASSIVE);` 的返回值,第一个数字是 WAL 中的总页数,第二个是已 checkpoint 的页数,第三个是已 checkpoint 但还没复用的页数。如果第二个长期远小于第一个,就说明有 reader 卡住。

坑 4:`synchronous=NORMAL` vs `FULL`

WAL 模式下默认的 `synchronous=FULL` 仍然会在每次提交都 fsync WAL 文件,性能损失比较大。官方文档明确说:在 WAL 模式下用 `NORMAL` 是安全的,崩溃恢复仍然能保证一致性,只是断电瞬间最后那个事务可能丢失。

```sql

PRAGMA synchronous=NORMAL;

```

我们的测试里这个改动让批量插入吞吐量提升了大概 3 倍。

总结

切到 WAL 之后整体延迟和并发表现都好了很多,但 SQLite 的"省心"是建立在你理解它内部行为的前提下的。建议至少把 `journal_mode`、`busy_timeout`、`synchronous`、`wal_autocheckpoint` 这几个 pragma 的语义看一遍再上生产。

相关推荐
天若有情6736 小时前
程序员原创|借鉴JS事件冒泡,根治电脑文件混乱的“冒泡整理法”
开发语言·javascript·windows·ecmascript·电脑·办公·日常
特种加菲猫7 小时前
继承,一场跨越时空的对话
开发语言·c++
小码哥_常7 小时前
告别MySQL!大厂集体转投PostgreSQL,到底藏着什么玄机?
后端
玩转单片机与嵌入式8 小时前
玩转边缘AI(TInyML):需要掌握的C++知识汇总!
开发语言·c++·人工智能
茉莉玫瑰花茶8 小时前
Qt 信号与槽 [ 1 ]
开发语言·数据库·qt
刀法如飞8 小时前
Go数组去重的20种实现方式,AI时代解决问题的不同思路
后端·算法·go
AI人工智能+电脑小能手9 小时前
【大白话说Java面试题】【Java基础篇】第30题:JDK动态代理和CGLIB动态代理有什么区别
java·开发语言·后端·面试·代理模式
swipe9 小时前
别再把 AI 聊天做成纯文本:从 agui 这个前后端项目,拆解“可感知工具调用”的流式 AI UI
后端·langchain·llm
GetcharZp9 小时前
GitHub 爆火!纯 Go 编写的文件同步神器 Syncthing,凭什么成为程序员的标配?
后端