本文作者:陈奕霖(sticnarf),PingCAP 研发工程师,TiKV Committer,热衷于开源技术,在分布式事务领域有丰富经验,目前致力于优化 TiDB 的分布式事务性能。
TiDB 提供了原生的分布式事务支持,实现低延迟的分布式事务是持续的优化方向。TiDB 5.0 引入的 Async Commit 特性大大改善了事务提交的延迟,这一特性主要由本文作者陈奕霖(sticnarf),以及赵磊(youjiali1995),Nick Cameron(nrc) 和周振靖(MyonKeminta)实现。
本文将向大家介绍 Async Commit 的设计思路、原理以及关键的实现细节。
Percolator 的额外延迟
TiDB 事务基于 Percolator 事务模型。读者可以参考我们之前的博客详细了解 Percolator 事务模型的提交过程。

上图是引入 Async Commit 之前的提交流程示意图。用户向 TiDB 发送 COMMIT 语句之后,TiDB 至少要经历以下的步骤才能向用户返回提交结果:
-
并发地 prewrite 所有的 keys;
-
从 PD 获取时间戳作为 Commit TS;
-
提交 primary key。
整个提交过程的关键路径包括了至少两次 TiDB 和 TiKV 之间的网络交互。只有提交 secondary keys 的操作在 TiDB 后台异步完成。
在 TiDB 的事务模型中,我们可以大致将 TiDB 节点认为是事务的协调者,而 TiKV 节点是事务的参与者。传统二阶段提交中我们一般默认协调者的数据存储在节点本地,但 TiDB 事务模型中,所有的事务相关数据都在 TiKV 上。也正是因此,传统二阶段提交中,第一阶段结束后事务状态即可确定;而 TiDB 需要完成第二阶段的一部分,将事务状态存储到 TiKV 上,才能向用户响应。
不过这也意味着,TiDB 之前的事务模型是有提升空间的。能否改进 Percolator 事务模型,让事务的状态在完成第一阶段后,无需额外的网络交互即可确定呢?
改进事务完成条件
引入 Async Commit 之前,事务的 primary key 被提交才意味着这个事务被提交。Async Commit 力图实现的,就是把确定事务状态的时间提前到完成 prewrite 的时候,让整个提交的第二阶段都异步化进行。也就是说,对于 Async Commit 事务,只要事务所有的 keys 都被成功 prewrite,就意味着事务提交成功。
下图是 Async Commit 事务的提交流程(你可能发现原来获取 Commit TS 的环节没有了,在 prewrite 前多了从 PD 获取时间戳作为 Min Commit TS 的操作,这里的原因会在后文中介绍):

为了达到这个目标,我们有两个主要问题要解决:
-
如何确定所有 keys 已被 prewrite。
-
如何确定事务的 Commit TS。
如何找到事务所有的 keys
引入 Async Commit 之前,事务的状态只由 primary key 决定,所以只需要在所有 secondary key 上存储到 primary key 的指针。如果遇到未提交的 secondary key,查询 primary key 的状态即可知道当前事务的状态:

判断 Async Commit 事务则需要知道所有 keys 的状态,所以我们需要能从事务的任意一个 key 出发,查询到事务的每一个 key。于是我们做了一点小的修改,保留从 secondary key 到 primary key 指针的同时,在 primary key 的 value 里面存储到到每一个 secondary key 的指针:

最低0.47元/天 解锁文章
869

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



