跳到正文
原文
苏三说技术· 苏三·· 3天前AI 评分34

微信为什么使用SQLite保存聊天记录?

AI 导读

微信聊天记录默认不上云,而是以SQLite文件形式存在用户手机本地,服务器只负责转发消息。腾讯在SQLite之上封装了WCDB框架,加入SQLCipher的AES-256-CBC加密,并借助FTS5倒排索引实现快速搜索,实测1万条长文本查询中位响应约0.14毫秒,比LIKE快15倍。数据库文件超过约240MB时会自动拆分。

正文

前言

一个嵌入式数据库,撑起了十三亿人的聊天记录

前阵子有个小伙伴问了我一个挺有意思的问题:“三哥,微信每天产生那么多聊天消息,服务器是怎么存的?是不是也用MySQL?”

我反问他:“你知道你手机里存了多少条聊天记录吗?”

他想了一下:“我用了五年微信,估计几十万条吧。”

“那你打开微信,搜索几年前的某条聊天记录,要等多久?”

“挺快的,基本秒出。”

这就是答案。你的聊天记录根本没有存在腾讯的服务器上,而是存在你自己的手机里——用一个叫SQLite的数据库。

十三亿人的聊天记录,全部以SQLite文件的形式,安安静静地躺在一部部手机里。

腾讯的服务器只负责“转发消息”,不负责“长期保存”。

这个设计决策,背后是一整套关于成本、架构和用户体验的权衡。

今天这篇文章,我就把微信为什么用SQLite、怎么用的、以及从中学到了什么,从头到尾给你拆解一遍。

希望对你会有所帮助。

一、你的聊天记录,不在腾讯服务器上

有些小伙伴可能会说:“聊天记录不是应该存在服务器上吗?不然换手机怎么同步?”

微信的聊天记录,默认是不上云的。

你换了一部新手机,登录微信之后,聊天记录是空的。

你得用“聊天记录迁移”功能,把旧手机里的数据导过去。

这个设计在当时被很多人吐槽——QQ可以漫游聊天记录,微信为什么不行?

但如果你理解了微信的体量,就会明白这个决策背后的逻辑。

假设微信把十三亿用户的聊天记录全部存在服务器上,是什么概念?

每个人每天产生几十条消息,一条消息平均几百字节。

十三亿人,每天就是几十PB的数据增量。

存一年,就是EB级别。

这需要建多少数据中心?花多少钱?

而且,聊天记录是“冷数据”——90%的消息在发送后的几天内就不会再被查看了。

为了这90%的冷数据,去建一个EB级的存储集群,成本上完全不划算。

所以微信做了一个“反直觉”的选择:聊天记录存在本地,服务器只负责转发。

这带来的直接好处是:

  • 服务器成本极低:腾讯不需要为每个用户的聊天记录建存储

  • 隐私保护更好:你的聊天记录只在你自己的设备上

  • 响应速度极快:搜索本地数据,不需要网络往返

代价就是——聊天记录不漫游,换设备要手动迁移。

但这个代价,微信认为可以接受。

二、一张图看懂微信的本地存储架构

二、一张图看懂微信的本地存储架构:该节配图

关键理解:微信本地使用的是 WCDB(WeChat Database) ——这是腾讯基于SQLite封装的一套数据库框架。

底层还是SQLite,但腾讯在上面加了一层SQLCipher加密。

每个聊天会话对应一个表,表名通常是Chat_格式。

每个数据库文件(msg_X.db)在超过约240MB时会自动拆分为msg_1.db、msg_2.db……。

三、SQLite为什么适合微信?

3.1 SQLite的本质

一个库,不是一个服务。

这是理解SQLite最关键的一点。

MySQL是一个“服务端数据库”。

你启动一个MySQL进程,它监听3306端口,客户端通过网络连接它,发送SQL,拿回结果。

它有连接池、有用户管理、有权限控制。

SQLite是一个“嵌入式数据库库”。

它没有独立的进程,没有网络层。

你的程序直接调用它的C函数,它直接读写本地文件。

SQLite的整个引擎,就是一个几百KB的C语言库。

// SQLite的使用方式——直接调用库函数
sqlite3 *db;
sqlite3_open("msg_0.db", &db); // 打开数据库文件
sqlite3_exec(db, "SELECT * FROM Chat_abc", callback, 0, 0); // 执行SQL
sqlite3_close(db); // 关闭

这个架构差异,决定了SQLite的适用场景。

微信是一个手机App。

手机App不能启动一个独立的数据库服务进程——那会消耗额外的内存和CPU。

微信需要的是一个能直接嵌入App、随用随开的数据库引擎。

SQLite正好满足这个需求。

3.2 单文件存储:聊天记录就是一个文件

SQLite的另一个特点是单文件存储。一个数据库就是一个.db文件,所有的表、索引、数据都在里面。

这对微信意味着什么?

备份和迁移变得极其简单。

你想把聊天记录从旧手机导到新手机?

拷贝几个.db文件就行。

你想备份到电脑?

微信的“备份与恢复”功能,本质上就是在拷贝这些文件。

如果用MySQL,你得导出SQL、传输、导入,中间还有版本兼容问题。

SQLite的单文件格式,跨平台、跨版本,直接拷贝就能用。

3.3 FTS5:全文搜索的“秘密武器”

微信聊天记录搜索为什么那么快?

答案在FTS5——SQLite内置的全文搜索扩展。

传统的SQL搜索用LIKE '%关键词%',需要逐行扫描,数据量一大就慢得不行。

FTS5用的是倒排索引——它维护一个从“词”到“文档ID”的映射表,搜索时直接查索引,不需要扫全表。

实测数据:在1万条长文本中查询,FTS5的中位响应时间约0.14毫秒,比LIKE快15倍。

微信的聊天记录搜索,底层用的就是FTS5。

你输入“张三 发票”,它能在几十万条消息里瞬间定位到相关记录。

四、WCDB:腾讯在SQLite上做了什么?

微信用的不是“裸SQLite”,而是腾讯自研的WCDB框架。

它在SQLite之上加了几层关键能力:

第一层:SQLCipher加密

你的聊天记录数据库是加密的。

macOS版微信使用AES-256-CBC加密,密钥为32字节。

这意味着即使有人拿到了你的.db文件,没有密钥也打不开。

第二层:性能优化

WCDB针对微信的场景做了大量优化。比如:

  • 批量写入:微信的消息是高频小批量写入,WCDB对此做了专门优化

  • 连接池管理:多个聊天窗口同时操作数据库时,WCDB管理连接复用

  • 监控与诊断:WCDB内置了性能监控,能发现慢查询

第三层:多线程并发

SQLite默认只支持单写多读——同一时间只能有一个写操作,但可以有多个读操作。

WCDB在应用层做了协调,让多个聊天窗口的读写尽可能不互相阻塞。

五、SQLite的“天花板”在哪里?

SQLite很强大,但它不是万能的。

理解它的局限性,才能理解微信为什么“本地用SQLite,服务器用别的”。

5.1 并发写入的限制

SQLite的核心限制是:同一时间只能有一个写操作。

WAL(Write-Ahead Logging)模式改善了这个情况——写操作和读操作可以并行,但写和写之间仍然是串行的。

这对微信意味着什么?

每个用户的聊天记录,在本地是串行写入的。

你同时给三个人发消息,这三条消息的写入是排队进行的。

在手机端,这个限制影响不大——你不可能同时产生成千上万条消息。

但如果在服务器端,几百万用户同时写,SQLite就撑不住了。

5.2 没有网络层,没有用户管理

SQLite没有网络层,所以它不能作为“服务器数据库”使用。

它也没有用户管理、权限控制——因为它假设只有一个应用程序在访问它。

这些限制,在手机端恰好不是问题。微信App是唯一的访问者,不需要用户管理,不需要网络层。

六、从微信的设计中学到了什么?

微信的SQLite使用,给我们几个重要的架构启示:

启示一:不是所有数据都需要“上云”

“数据上云”是趋势,但“全部上云”是浪费。冷数据存本地,热数据存云端,这个分层策略在成本上更合理。微信的聊天记录是“冷数据”——存了之后很少读,不值得为它建EB级云存储。

启示二:嵌入式数据库被严重低估

很多人觉得SQLite是“玩具数据库”。但事实上,SQLite的部署量可能比所有其他数据库加起来都多。你的手机里有几十个App在用SQLite,你的浏览器在用SQLite,你的IDE也在用SQLite。

启示三:加密是本地存储的底线

聊天记录存在本地,意味着设备丢失=数据泄露。微信用SQLCipher加密数据库,用AES-256保护密钥,这是本地存储的底线。如果你的App也在本地存敏感数据,加密是必须的,不是可选的。

七、优缺点

SQLite的优点

1. 零配置,零运维没有独立的服务器进程,不需要安装、配置、启动。一个文件就是整个数据库。

2. 单文件存储,跨平台一个.db文件,可以在Windows、macOS、Linux、iOS、Android之间直接拷贝使用。

3. ACID事务支持SQLite支持完整的ACID事务——原子性、一致性、隔离性、持久性。这意味着数据不会因为崩溃而损坏。

4. 全文搜索(FTS5)内置的FTS5扩展提供高性能全文搜索,比LIKE快15倍。

5. 极低的内存占用整个引擎就是一个几百KB的C库,运行时内存占用极低。

6. 加密支持通过SQLCipher扩展,可以对数据库进行AES-256加密。

SQLite的缺点

1. 单写多读的并发限制同一时间只能有一个写操作,写和写之间串行。不适合高并发写入场景。

2. 没有网络层不能作为服务器数据库使用,无法支持多客户端网络访问。

3. 没有用户管理没有内置的权限控制、用户管理功能。

4. 大规模数据性能有限在TB级数据上,性能会明显下降。微信的解决方案是分片——超过240MB就拆分成新文件。

八、适用场景

场景

推荐程度

理由

移动App本地存储

✅✅✅ 强烈推荐

微信、QQ等都在用,零配置嵌入

桌面应用数据存储

✅✅✅ 强烈推荐

浏览器、IDE的本地缓存

单用户数据管理

✅✅✅ 强烈推荐

个人笔记、本地知识库

嵌入式设备

✅✅✅ 强烈推荐

资源受限环境下的数据存储

服务端高并发数据库

❌ 不推荐

单写多读限制,不适合高并发写入

多用户网络访问

❌ 不推荐

没有网络层,无法作为服务器数据库

九、写在最后

回到最初的问题:微信为什么使用SQLite保存聊天记录?

答案不复杂——因为聊天记录是“冷数据”,存本地比存云端更合理。

十三亿人的聊天记录,如果全部存在腾讯的服务器上,是EB级的存储成本。

而且这些数据90%的时间是“沉睡”的,为了这10%的搜索需求,去建一个EB级的存储集群,投入产出比极低。

SQLite的嵌入式架构,恰好匹配了“本地存储”的需求。

零配置、单文件、ACID事务、全文搜索——这些特性让微信可以在不增加服务器成本的前提下,提供快速的本地搜索体验。

当然,这个设计也有代价——聊天记录不漫游。

换手机要手动迁移,丢手机就丢记录。但这个代价,微信认为可以接受。

技术选型从来不是“什么最好”,而是“什么最适合”。

微信选了SQLite,不是因为SQLite比MySQL“更好”,而是因为SQLite更适合“本地存储”这个场景。

如果你正在设计一个需要本地数据存储的系统,SQLite值得你认真考虑。

它可能不是最“高大上”的选择,但它可能是最务实的选择。

十、参考资源

  • SQLite官方文档:https://www.sqlite.org

  • SQLite适用场景指南:https://www.sqlite.org/whentouse.html

  • WCDB开源项目:https://github.com/Tencent/wcdb

来源:苏三说技术 · mp.weixin.qq.com