数据库
首页 > 数据库> > Sqlite 并发读写的演进之路

Sqlite 并发读写的演进之路

作者:互联网

概论

sqlite 底层的存储基于 B-tree,B-Tree 对底层存储的基本读写单位是页面,而每个页面都由全局唯一的页面编号与之对应,一般来说页面编号从 1 开始递增。类 B-Tree 的存储引擎修改数据的流程如下图所示:

图片

从上图中,需要区分 B-Tree 类的存储引擎几个核心的模块:

最上层的 B-Tree 算法模块,在进行写事务的时候,是首先向页面管理器发起读页面到内存中的请求,注意到 B-Tree 模块并不会直接跟数据库文件打交道,而是经过页面管理器模块(下面会展开说),修改了页面之后标记为“脏页面”,页面管理器最终负责将脏页面落盘到数据库文件中。

现在来谈谈“页面管理器”模块的具体工作,也有的实现称为“缓存管理器(buffer manager)”。这个模块负责:在内存中管理页面

在内存中管理页面。这涉及到两部分内容:

错误的恢复,事务的管理、比如:

有了这些基础的了解,我们来看看 sqlite 在并发读写方面的演进之路

journal

最早的页面管理器实现是基于 Journa l文件的,这个文件存储页面在修改之前的内容:

图片

可以看到的是:

WAL

从上面的分析可以看出,以 Journal 文件的机制,每次写事务:

从 sqlite3.7.0 版本开始(SQLite Release 3.7.0 On 2010-07-211,sqlite 引入了更常见的 WAL 机制来解决页面的读写并发问题,WAL 的原理如下图所示:

图片

WAL 机制中,事务对页面的修改:

虽然同一时间仍然只能有一个写事务在进行,但是读事务同时存在多个。其核心原因是因为修改并没有马上直接落盘到数据库文件中,这样修改的可见性就可以由 wal 索引来控制,即:写事务尽管写,读事务尽管读,只要控制这些写事务的修改不在 wal 索引中可见即可。WAL 虽然支持“一写多读”,而不是 Journal 文件那样的“一写全卡住”,但是还有一个问题没有解决:在做 checkpoint 操作的时候,连写事务也不能进行了。

两个可能的优化方案

以下介绍 sqlite 目前在讨论的两个优化方案,之所以说是“可能”,因为看这部分代码还并没有合并到主干中,目前暂时还在分支里,参见:https://github.com/sqlite/sqlite/tree/begin-concurrent-pnu-wal2。

WAL2:

为了解决“checkpoint”时无法进行写事务”的痛点,sqlite 目前在尝试新的 WAL-2 机制。图片

引入 WAL-2 之后,同时有两个 WAL 文件,这样可以:checkpoint 其中一个 WAL 文件时,继续写另一个 WAL 文件,下一次再进行 checkpoint 时进行切换,这样 checkpoint 就不会阻塞住写操作。

BEGIN CONCURRENT:

目前的 WAL 机制,都只能支持同一时间一个写事务,BEGIN CONCURRENT 机制可以实现多个写并发,这篇 SQLite: Begin Concurrent 文档中,大概描述了一下这个优化的思路:

The key to maximizing concurrency using BEGIN CONCURRENT is to ensure that there are a large number of non-conflicting transactions. In SQLite, each table and each index is stored as a separate b-tree, each of which is distributed over a discrete set of database pages. This means that:

  • Two transactions that write to different sets of tables never conflict, and that
  • Two transactions that write to the same tables or indexes only conflict if the values of the keys (either primary keys or indexed rows) are fairly close together.

简单的理解上面的这段话:

目前这两个优化,由于还并没有合并到主干,所以我也还没有具体看实现,后续体现在 sqlite 主干中的存储引擎方面的优化,再梳理出来。

引用链接

[1] SQLite Release 3.7.0 On 2010-07-21:

https://www.sqlite.org/releaselog/3_7_0.html
[2] SQLite: Begin Concurrent:

https://www.sqlite.org/cgi/src/doc/begin-concurrent/doc/begin_concurrent.md
[3] sqlite3.36版本 btree实现(三)- journal文件备份机制 - codedump的网络日志:

https://www.codedump.info/post/20211222-sqlite-btree-3-journal
[4] sqlite3.36版本 btree实现(四)- WAL的实现 - codedump的网络日志:

https://www.codedump.info/post/20220106-sqlite-btree-4-wal

文章首发于公众号:Databend

标签:文件,Sqlite,WAL,管理器,修改,读写,事务,并发,页面
来源: https://www.cnblogs.com/databend/p/16692920.html