本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57b58022433221be01499480
作者:张三华
前言
随着微信iOS客户端业务的增长,在数据库上遇到的性能瓶颈也逐渐凸显。在微信的卡顿监控系统上,数据库相关的卡顿不断上升。而在用户侧也逐渐能感知到这种卡顿,尤其是有大量群聊、联系人和消息收发的重度用户。
我们在对SQLite进行优化的过程中发现,靠单纯地修改SQLite的参数配置,已经不能彻底解决问题。因此从6.3.16版本开始,我们合入了SQLite的源码,并开始进行源码层的优化。
本文将分享在SQLite源码上进行的多线程并发、I/O性能优化等,并介绍优化相关的SQLite原理。
多线程并发优化
1. 背景
由于历史原因,旧版本的微信一直使用单句柄的方案,即所有线程共有一个SQLite Handle,并用线程锁避免多线程问题。当多线程并发时,各线程的数据库操作同步顺序进行,这就导致后来的线程会被阻塞较长的时间。
2. SQLite的多句柄方案及Busy Retry方案
SQLite实际是支持多线程(几乎)无锁地并发操作。只需
- 开启配置
PRAGMA SQLITE_THREADSAFE=2 - 确保同一个句柄同一时间只有一个线程在操作
倘若再开启SQLite的WAL模式(Write-Ahead-Log),多线程的并发性将得到进一步的提升。
此时写操作会先append到wal文件末尾,而不是直接覆盖旧数据。而读操作开始时,会记下当前的WAL文件状态,并且只访问在此之前的数据。这就确保了多线程读与读、读与写之间可以并发地进行。
然而,阻塞的情况并非不会发生。
- 当多线程写操作并发时,后来者还是必须在源码层等待之前的写操作完成后才能继续。
SQLite提供了Busy Retry的方案,即发生阻塞时,会触发Busy Handler,此时可以让线程休眠一段时间后,重新尝试操作。重试一定次数依然失败后,则返回SQLITE_BUSY错误码。

本文分享了微信iOS客户端在面对SQLite性能瓶颈时的优化实践,包括多线程并发和I/O性能的提升。通过合入SQLite源码,解决了多线程并发问题,如优化Busy Retry方案,减少了卡顿和SQLITE_BUSY的发生。同时,对I/O性能进行优化,如保留WAL文件大小以提升读写速度,并利用mmap提升性能。其他优化措施包括禁用文件锁和内存统计锁,以减少不必要的阻塞和性能损耗。
最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



