写点什么

CockroachDB 是如何实现分布式原子事务的?

  • 2015-09-11
  • 本文字数:1864 字

    阅读完需:约 6 分钟

作为一个分布式数据库, CockroachDB 有一个鲜明的特性,就是支持 ACID 事务。近日, Cockroach Labs 团队成员 Matt Tracy撰文介绍了CockroachDB 如何在不使用锁的情况下实现原子事务。

CockroachDB 的原子事务策略总共包含如下五个基本步骤。

1.“开关(Switch)”:CockroachDB 事务记录

在开始一个事务之前,写进程首先会创建一个包含如下字段的事务记录

  • 事务唯一标识 UUID
  • 事务当前状态,可以有三种取值,其中 PENDING 为初始状态,ABORTED 或 COMMITTED 为终止状态
  • 一个 Cockroach K/V 键,指定“开关”在分布式数据存储中的位置

写进程会使用一个专门的 CockroachDB 命令BeginTransaction()存储事务记录。事务记录或者开关不能并行访问,只能严格按照顺序进行读 / 写操作。事务记录的 PENDING 或 ABORTED 状态对应开关的“off”状态,COMMITTED 对应“on”。

2.“暂存(Stage)”:Write Intent

写进程会准备好多个数据库变更,但并不会覆盖任何现有值。为了暂存一个事务中的变更,CockroachDB 使用了一个名为Write Intent的结构。任何时候,一个值作为一个事务的一部分写入到一个键,它都会生成一个 Write Intent。Write Intent 结构中还包含指示事务记录存储位置的键。

另外,还有一个规则,就是任何键都有且仅有一个 Write Intent(Matt 在此并未考虑事务并发)。

3.“过滤(Filter)”:读取 Write Intent

对于任何有暂存值的键,在读取时都必须检查事务开关的状态。如果开关状态为“off”,则返回该键的原值;如果开关状态为“on”,则返回暂存值。也就是说,如果一个键有暂存值,那么对该键的所有读取操作都必须使用开关状态过滤,具体步骤如下:

  1. 如果现有 Write Intent 对应的事务记录仍然处于 PENDING 状态,则将其置为 ABORTED 状态。
  2. “清除(cleanup)”现有的 Write Intent。
  3. 返回该键的普通值(即不是 Write Intent)。如果之前的事务已经 COMMITTED,那么清除操作会将暂存值升级为普通值;否者,返回该键的原值。

4.“按开关(Flip)”:提交事务

当写进程准备好事务中的所有变更后,它会打开开关(即将事务记录更新成 COMMITTED,开关状态置为“on”)。事务生成的所有 Write Intent 都会立即生效;之后发生的任何读取操作在看到事务已经提交后都会返回 Write Intent 中的暂存值。

另外,将事务记录的状态置为 ABORTED 可以终止事务,之后发生的读取操作将忽略这个事务生成的 Write Intent。

5.“解除暂存(Unstage)”:清除 Write Intent

前面 4 个步骤已经可以提供原子事务;但是,第 2 步开销很大,因此,在事务完成后,CockroachDB 会尽快清除暂存值。如果事务成功,那么暂存值会取代原值;如果失败,那么暂存值会被丢弃。总之,如果一个键没有 Write Intent,那么读取操作就无需过滤,也就可以以适当的分布式方式完成。需要注意的是,解除暂存是异步的,并不需要在事务 COMMITTED 之前完成。

网友 RJ Ryan 对 Matt 所谓的“无锁(lockless)”提出了质疑。他认为,开关和 Write Intent 看起来跟锁类似。对此,Matt 答复说:

这篇博文谈到“锁”时,是指数据库记录锁,一个修改数据库某个部分的独占性许可。

开关(或事务记录)并不是一个数据库锁,因为它没有阻止其它数据库操作进行……对开关本身的操作会按顺序进行……但它不会阻止任何操作执行。

Write Intent 也不是数据库锁,因为它不会保证键的独占性访问;相反,它允许一个事务“发现”其它正在访问相同键的并发事务。当这种情况出现时,其中一个事务必须终止;不过,它并没有像锁一样采用“先来先服务”的策略,而是为每个事务赋予一个数值型的优先级,优先级最高的事务总是会胜出。

Matt 指出,如果读者对 CockroachDB 的完整事务模型感兴趣,可以查看 GitHub 上的详细设计文档 Tobias Schottdorf 也是 CockroachDB 项目的贡献者。他在回复网友的评论时指出,虽然 CockroachDB 的原子事务策略与使用 MS-DTC 的 SQL Server 分布式事务处理一样都是 2PC,但它们并不相同。XA 有准备和提交两个阶段,提交阶段实际上要做大量的工作。但在 Cockroach 中,“准备”阶段就将值写到了它们最终应该存在的位置,所以“提交”阶段只需要对单个键执行一次写操作,几乎不做什么工作。

另外,在介绍完 CockroachDB 的原子事务策略后,Matt 还特别介绍了 CockroachDB 的清除操作,感兴趣的读者可以进一步阅读


感谢郭蕾对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入 InfoQ 读者交流群)。

2015-09-11 19:004369
用户头像

发布了 1008 篇内容, 共 444.7 次阅读, 收获喜欢 346 次。

关注

评论

发布
暂无评论
发现更多内容

如何使用mock应对测试所需随机数据

华为云开发者联盟

测试 数据 Mock

第一张区块链完税证明在深圳开出,区块链政务应用再获突破

CECBC

区块链 电子证明

破除数据垄断,数据上链或是关键

CECBC

区块链 大数据

百度京Fun生活节 双旦福利HIGH 翻全城

DT极客

实用流程工具,浅析LR.NET配置型工作流引擎

雯雯写代码

.net 工作流

软件测试——网络协议知识(二)

测试人生路

软件测试 网络通信协议

云挖矿APP系统开发|云挖矿软件开发

系统开发

架构师 3 期 3 班 -week6- 总结

zbest

总结 week6

一周信创舆情观察(12.21~12.27)

统小信uos

ClickHouse利器—如何提高留存计算速度

行者AI

数据库

华为云·云享专家李万龙: IoT 梦想,从0到1的实现

华为云开发者联盟

技术 物联网 IoT

ClickHouse数据导入

一粒

kafka Logstash Clickhouse

架构师训练营知识点整理

garlic

架构师训练营第 1 期

真香系列!大牛耗时一年最佳总结,让你的app体验更丝滑!建议收藏

欢喜学安卓

android 程序员 面试 移动开发

我从 HX 辞职了

看山

辞职 闲聊

仅4步,就可通过SQL进行分布式死锁的检测与消除

华为云开发者联盟

数据库 sql 死锁

2020中国低代码平台市场发展年度报告(深度分析)

J2PaaS低代码平台

软件 低代码 开发工具 SaaS/IaaS/PaaS 软件开发、

深入浅出Android!2021京东最新Android面试真题解析,震撼来袭免费下载!

欢喜学安卓

android 程序员 面试 移动开发

Linux基本操作命令

行者AI

Linux

Flink Forward Asia 2020 -- Keynote 总结

Apache Flink

flink

架构师 3 期 3 班 -week6- 作业

zbest

作业 week6

wildfly 21的配置文件和资源管理

程序那些事

程序那些事 web服务器 应用配置 服务器部署

架构师训练营大作业

Gosling

架构师训练营第 1 期

牛笔了!难道Android真的凉了?Android面试题及解析

欢喜学安卓

android 程序员 面试 移动开发

写出一手烂代码的19条准则

Java架构师迁哥

Java中的常量

cdhqyj

Java

北京一咖啡店启动数字人民币应用场景测试 店员:目前处于内测阶段

CECBC

数字人民币

Rust布道者张汉东倾授,入门Rust初学者都要攻破哪些难点?

华为云开发者联盟

学习 rust 语言

Vmware+Ubuntu 配置静态IP

千泷

ClickHouse常见集群部署架构

一粒

nosql 架构 Clickhouse

CockroachDB是如何实现分布式原子事务的?_数据库_谢丽_InfoQ精选文章