网易首页 > 网易号 > 正文 申请入驻

放弃MySQL改用SQLite:日请求10万,写不再阻塞读

0
分享至




一、传了十几年的那句话,官文档自己不认

有人在技术群里问:一个内容站,日请求十万上下,读写比大概二十比一,还有必要单独养一台 MySQL 吗?底下最高赞的回复是「换 SQLite 试试」。点赞的人里一半在调侃,另一半是认真的。

认真的那部分人有底气。SQLite 官方那篇《Appropriate Uses For SQLite》写得明明白白:一般来说,日请求量在 10 万次以下的站点用 SQLite 都能跑得很好;10 万次是保守估计,不是硬上限,SQLite 已经被证明能扛住十倍于此的流量。同一份文档还附了一个样本:sqlite.org 官网自己就是用 SQLite 跑的,2015 年时每天处理 40 万到 50 万次 HTTP 请求,其中 15% 到 20% 是会碰数据库的动态页面,每个动态页面大约 200 条 SQL,整套东西跑在一台与另外 23 台虚拟机共享物理机的 VM 上,多数时候负载低于 0.1。

这里必须把口径说清楚:官方给的是「日请求 10 万次」,是 hits/day,不是日活 10 万人。这两个数字差着一个量级,日活 10 万的站点日请求往往是几百万次。标题里那个 10 万,出处就在上面这一段,拿它当容量规划可以,别当成日活去套自己的业务。

真正让 SQLite 从「本地小工具」变成「能上生产」的,不是硬件变快了,也不是谁胆子大,是一条 PRAGMA:journal_mode=WAL。

二、Tailscale 把主库换成 SQLite,后来踩了什么坑

### 一次有据可查的迁移

要说清楚 SQLite 上生产这件事,绕不开 Tailscale。这家做组网的公司把控制平面的主库放在 SQLite 上,而且把全过程写成了公开博客。

时间是 2022 年 4 月,作者是 David Crawshaw,文章标题就叫《A database for 2022》。按他的说法,他们最早的「数据库」是写进磁盘的一个 JSON 大对象,峰值 150MB;后来换成 etcd;最后换成 SQLite。不选 MySQL 和 PostgreSQL 的理由很实在:团队里几个人都运维过这类客户端/服务器数据库,不想再折腾一遍主从复制;而且他们有一条硬性要求——整个测试套件要能在本地跑起来,不用虚拟机也不用容器,数据库一旦变成独立进程,这一条就守不住了。

更值得抄的是他们做的取舍判断:控制平面短时不可用,后果是「新节点登录不上,但已经连通的网络照常工作」。这句话是整件事的前提。换成「挂一分钟就丢订单」的业务,结论会完全相反。

架构上,控制平面被拆成多个分片,每个分片一个 SQLite 库,由单个 Go 进程独占访问。他们在后来的事故复盘里写了一句原话:这种单写者设计,正是 SQLite 期望的使用方式。迁移本身是三段式:先让封装层同时写 etcd 和 SQLite,再把读取的真相源切到 SQLite,最后关掉 etcd。这套「双写—切读—下线」的节奏,任何一次数据库迁移都能照搬。

生态这一层也交代一下:SQLite 本身是公有领域代码,商用无需授权;把 WAL 持续复制到对象存储、让 SQLite 拥有准实时备份的 Litestream 是 Apache-2.0 协议,GitHub 上一万四千多 star;Expensify 那套把 SQLite 包成分布式事务层的 Bedrock 是 LGPL-3.0,一千二百多 star。地址分别是 github.com/benbjohnson/litestream 和 github.com/Expensify/Bedrock。

### WAL 到底改了什么

SQLite 默认用的是回滚日志模式。写事务提交时要把改动写回主库文件,这个动作需要拿到整库排他锁,在这段时间里读写是互斥的。

WAL 把这个顺序倒过来:写不碰主库,只往一个 -wal 文件尾部追加;读的人照旧读主库,顺带看一眼 -wal 里有没有更新的页。于是读者不必等写者,写者也不必等读者。这句话的边界要盯准:WAL 让读写不再互斥,但它没有给你并行的写——任何时刻仍然只有一个写事务存在。

上生产要配的几件事,代码就这几行:

import sqlite3conn = sqlite3.connect("app.db", timeout=5.0)   # timeout 即 busy_timeout,单位秒conn.execute("PRAGMA journal_mode=WAL")         # 返回 wal 才算生效,网络盘上会退回 deleteconn.execute("PRAGMA synchronous=NORMAL")       # WAL 下常见选择,FULL 更稳但更慢conn.execute("PRAGMA busy_timeout=5000")        # 拿不到锁最多等 5 秒,别用默认的 0conn.execute("PRAGMA foreign_keys=ON")          # 外键默认是关的

还有一条容易被忽略:写事务一律用 BEGIN IMMEDIATE。Tailscale 就被这个咬过——他们 ATTACH 了两个库,用默认的 BEGIN DEFERRED 时,加锁顺序取决于先写哪张表,两笔事务顺序不同,就会和唯一的写者撞成死锁。改成 BEGIN IMMEDIATE,在事务开始时就拿写锁,问题消失。

三、实测 80 倍差距,以及 WAL 没给你的那部分

### 同一台机器上的对照实验

讲道理不如跑一遍。下面两个实验在同一台机器上完成:Apple M2 Pro、10 核、16GB 内存、本地 SSD,SQLite 3.50.4,Python 3.13。表里有 2 万行预置数据,模拟一个读多写少的内容站。

第一个实验很直观:开一个读事务持有 3 秒,模拟后台导出或统计这类慢查询,同时另一个进程尝试写入并提交。

import sqlite3import timedef long_reader(path, hold_seconds, started):    """开一个读事务并持有若干秒,模拟导出/统计类慢查询。"""    conn = sqlite3.connect(path, timeout=10.0)    conn.execute("BEGIN")    conn.execute("SELECT count(*) FROM events").fetchone()    started.set()    time.sleep(hold_seconds)    conn.execute("SELECT count(*) FROM events").fetchone()    conn.commit()def try_write(path, busy_timeout):    """独立进程写入一行并提交,返回耗时与异常。"""    time.sleep(0.5)    conn = sqlite3.connect(path, timeout=busy_timeout)    t0 = time.perf_counter()    try:        conn.execute("INSERT INTO events (ts, payload) VALUES (?, 'new')", (int(time.time()),))        conn.commit()    except sqlite3.OperationalError as e:        return time.perf_counter() - t0, str(e)    return time.perf_counter() - t0, None

结果相当干脆:

journal_mode=delete  busy_timeout=5.0s | 长读事务持有 3.0s 期间的写入提交:耗时 2.424s,成功提交journal_mode=wal     busy_timeout=5.0s | 长读事务持有 3.0s 期间的写入提交:耗时 0.001s,成功提交journal_mode=delete  busy_timeout=0.0s | 长读事务持有 3.0s 期间的写入提交:耗时 0.000s,异常「database is locked」journal_mode=wal     busy_timeout=0.0s | 长读事务持有 3.0s 期间的写入提交:耗时 0.005s,成功提交

默认模式下,一次后台慢查询就能让写入干等 2.4 秒;把 busy_timeout 设成 0,等都不等,直接甩一句 database is locked。这两行,就是很多人对 SQLite 全部坏印象的来源。

第二个实验是 4 个读进程加 1 个写进程同时压 8 秒,每种配置跑 3 次取中位数,每笔写事务批量插 20 行,两边都设 synchronous=FULL:

配置

读吞吐

写吞吐

写事务延迟 p50 / p95

delete,读连接等锁 5 秒

3,201 次/秒

48,988 行/秒

0.31ms / 0.61ms

WAL,读连接等锁 5 秒

264,448 次/秒

203,600 行/秒

0.08ms / 0.17ms

delete,读连接不等锁

74,136 次/秒,8 秒内锁冲突 383 万次

1,535 行/秒

4.22ms / 63.06ms

WAL,读连接不等锁

261,493 次/秒,锁冲突 0 次

176,125 行/秒

0.08ms / 0.21ms

读吞吐差了 80 多倍,写吞吐差 4 倍,写延迟 p95 从 63 毫秒掉到 0.2 毫秒。第三行那个 383 万次锁冲突最说明问题:默认模式下,读进程几乎每两次尝试就撞上一次锁。

这就是迁移前后的真实差距,不是换了个数据库,是换了个锁模型。

### 三个必须先想清楚的边界

先泼第一盆冷水:WAL 不解决写写并发。WAL 模式下依然只允许一个写事务存在,第二个写者要么等 busy_timeout,要么拿到 SQLITE_BUSY。网上流传的「WAL 开启并发写」是彻底的误传,官方文档的原话是「读者不阻塞写者、写者不阻塞读者」,从来没说过两个写者能同时写。Turso 在 2025 年做过 MVCC 并发写的预览,SQLite 官方也有实验性的 begin concurrent 分支,但都没进主线。

第二盆冷水:那个著名的「SQLite 单机跑出 400 万 QPS」,来自 Expensify 2018 年的博客。成色要看清楚——那是一台 192 核、1TB 内存、3TB NVMe 的裸金属服务器,跑的是 447GB 数据集全内存缓存的只读随机求和操作,而且用的是他们改过的 SQLite 分支,连 POSIX advisory lock 都关掉了。这个数字证明的是 SQLite 的上限,不是你那台 4 核云主机的容量。

第三盆冷水最该记住。2026 年 8 月,Tailscale 发了一篇事故复盘:半年内 19 次数据库损坏,根因是 SQLite 源码里 checkpoint 与写事务之间的一场竞态,SQLite 开发者把它命名为 WAL-Reset bug,估计已经存在至少 16 年,修复随 SQLite 3.51.3 发布。他们自己总结的教训值得抄在本子上:之所以会撞上这个罕见 bug,是因为他们手动接管了 checkpoint 流程、而且跑得非常激进——把一项无聊技术用成了非标准姿势,风险就自己回来了。

所以该问的不是「SQLite 扛不扛得住」,而是「你的负载形状对不对得上」。对得上的是这四条:读远多于写、单机部署、数据量可控、短时不可用不致命。对不上的是:写密集且并发高、必须多机或跨机房高可用、数据量会持续膨胀到单机装不下、数据库文件放在网络文件系统上——WAL 依赖共享内存原语,NFS 上不该用。

四、真要迁的话,把这三件事做扎实

第一件,锁参数配齐再上线:WAL 模式、合理的 busy_timeout、写事务统一 BEGIN IMMEDIATE。三件事做完,上一节里那 383 万次锁冲突基本就消失了。

第二件,备份走 WAL 流式复制,别只拷主库文件。WAL 模式下最新数据可能还躺在 -wal 里,只拷 .db 文件拿到的是旧数据甚至坏数据。Litestream 这类工具做的就是这件事;用不上工具,至少让定时任务跑一遍 PRAGMA integrity_check,别等出事才发现。

第三件,迁移按「双写—切读—下线」三段走,一次只动一步。Tailscale 从 etcd 切到 SQLite 用的就是这个节奏,任何数据库迁移都能复用:先让新库跟着写,再把读切过去观察一段时间,最后才关旧库。一步到位的切换,出问题时没有回头路。

至于 checkpoint,除非你非常清楚自己在做什么,否则交给 SQLite 自己管。Tailscale 那 19 次损坏,就是手动激进 checkpoint 换来的代价。

五、你的库,真的需要一台单独的数据库服务器吗

SQLite 换掉的不是 MySQL,它换掉的是「网络往返 + 独立进程 + 一整套运维」这一层。当数据量单机装得下、读写比又是压倒性的读多写少时,这一层就是纯成本,还顺带把本地跑测试的快乐还给了你。

真想问一句:你现在手上跑着的那个项目,数据库是不是也就是一台 2 核 4G 的小机器?如果把它换成进程内的 SQLite,你是真的会出问题,还是只是不敢?评论区报一下你的读写比和日请求量,看看谁的库其实早就可以下班了。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
比今年还强!安东尼奥重组U23国足,王钰栋搭档布尼亚明,冲击2028年奥运会

比今年还强!安东尼奥重组U23国足,王钰栋搭档布尼亚明,冲击2028年奥运会

小秦哥聊体育
2026-10-02 19:26:55
孙心然震惊世界网球圈,首轮6比1、3比0连赢9局

孙心然震惊世界网球圈,首轮6比1、3比0连赢9局

刘哥谈体育
2026-10-02 11:11:05
拒绝加入詹姆斯字母行列!文班:看到有球员为预测平台宣传很可悲

拒绝加入詹姆斯字母行列!文班:看到有球员为预测平台宣传很可悲

罗说NBA
2026-10-02 05:38:12
痒是大病预警!提醒:3处发痒,不是过敏,或是这4病

痒是大病预警!提醒:3处发痒,不是过敏,或是这4病

健康科普365
2026-10-01 17:35:12
杭州商K集体停业,投资2亿的顶端商K豪华门头一片漆黑

杭州商K集体停业,投资2亿的顶端商K豪华门头一片漆黑

Mr王的饭后茶
2026-09-23 09:32:37
3.4 亿退休人员,有人每月 16000 元退休金是什么概念?

3.4 亿退休人员,有人每月 16000 元退休金是什么概念?

白米饭怎么吃
2026-08-22 22:10:21
莎莎短发亮相首钢园!中国大满贯女单签表出炉,王曼昱陷死亡半区,孙颖莎首轮叶伊恬,1/8决赛或碰桥本帆乃香

莎莎短发亮相首钢园!中国大满贯女单签表出炉,王曼昱陷死亡半区,孙颖莎首轮叶伊恬,1/8决赛或碰桥本帆乃香

影话星宸聊球
2026-10-02 21:01:48
游本昌最后遗容曝光,静卧大厅中央覆盖党旗,胡歌陈龙赶来送别

游本昌最后遗容曝光,静卧大厅中央覆盖党旗,胡歌陈龙赶来送别

洲洲影视娱评
2026-10-01 15:01:13
曾潜水63小时救出12名少年,泰国洞穴救援英雄布朗不幸去世!

曾潜水63小时救出12名少年,泰国洞穴救援英雄布朗不幸去世!

麓谷隐士
2026-10-02 00:05:04
文班亚马又拒绝合同!真够正义的!

文班亚马又拒绝合同!真够正义的!

柚子说球
2026-10-02 09:10:49
轻松拿下中网开门红,萨巴伦卡:你们都在等着看德约科维奇吧

轻松拿下中网开门红,萨巴伦卡:你们都在等着看德约科维奇吧

澎湃新闻
2026-10-02 20:54:12
说谁呢?可能是他!赛后邵佳一语出惊人:也许有的国脚还在想着联赛和亚冠

说谁呢?可能是他!赛后邵佳一语出惊人:也许有的国脚还在想着联赛和亚冠

足球大腕
2026-10-02 23:15:48
前列腺去世的人越来越多!建议:3不喝、2不吃、2坚持,别大意!

前列腺去世的人越来越多!建议:3不喝、2不吃、2坚持,别大意!

健康科普365
2026-10-02 22:30:03
游客在堵车途中遇断网,突然发现前车尾部贴着“连我车载WiFi密码8个8”,车主:车辆有比较强的网络性能,堵车或停靠时经常有人“蹭网”

游客在堵车途中遇断网,突然发现前车尾部贴着“连我车载WiFi密码8个8”,车主:车辆有比较强的网络性能,堵车或停靠时经常有人“蹭网”

农民日报
2026-10-02 20:13:21
成都警方:一男子驾车逆行并辱骂他人被查处

成都警方:一男子驾车逆行并辱骂他人被查处

界面新闻
2026-10-02 17:12:07
北京胡同老人真心话:腾退拿几百万,晚年反而更难了

北京胡同老人真心话:腾退拿几百万,晚年反而更难了

据说说娱乐
2026-10-02 19:19:22
重磅消息突袭!油价大跳水,欧洲股市直线拉升!

重磅消息突袭!油价大跳水,欧洲股市直线拉升!

证券时报
2026-10-02 17:50:08
1959年,印尼总统访日,日本人知道他好色,专门为他安排了一名19岁的绝色艺伎,没想到,就是这个女人,竟然改变了他的一生。

1959年,印尼总统访日,日本人知道他好色,专门为他安排了一名19岁的绝色艺伎,没想到,就是这个女人,竟然改变了他的一生。

回京历史梦
2026-10-01 06:35:14
记者:C罗曾考虑世界杯退出国家队,热苏斯每天打电话说服他留下

记者:C罗曾考虑世界杯退出国家队,热苏斯每天打电话说服他留下

懂球帝
2026-10-02 16:25:27
亚运会还没结束,中国游泳队在这里又摘两金!

亚运会还没结束,中国游泳队在这里又摘两金!

五星体育
2026-10-02 10:45:16
2026-10-02 23:39:00
侃故事的阿庆
侃故事的阿庆
几分钟看完一部影视剧,诙谐幽默的娓娓道来
746文章数 9580关注度
往期回顾 全部

科技要闻

“分手”15天后,华为与赛力斯签约新五年

头条要闻

媒体:澳想攒个大局"抗衡中国" 一看嘉宾名单尴尬了

头条要闻

媒体:澳想攒个大局"抗衡中国" 一看嘉宾名单尴尬了

体育要闻

30天30队·快船:被莱纳德挂在半空的未来?

娱乐要闻

潘玮柏老婆被猜怀二胎 中秋vlog露馅

财经要闻

珠宝黑马爆雷,老板全家跑路泰国!

汽车要闻

方程豹9月热销破4万 首款皮卡鲨鱼将于四季度上市

态度原创

游戏
旅游
数码
时尚
艺术

《GTA6》迈阿密热火联动!罪城服装周边开卖秒售罄

旅游要闻

含“塔”量超高,国庆前两天南京接待游客507.8万人次

数码要闻

英伟达宣布将推出DGX SPARK 64GB 可在本地运行最高1000亿参数AI模型

伊姐十一热推:电视剧《无可替代》;电视剧《雷霆令》......

艺术要闻

中国第二高楼的“毛笔”方案,落选为什么让人遗憾?

无障碍浏览 进入关怀版