写点什么

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:004073
用户头像

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

关注

评论

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

The story of programmers in famous enterprises.

Marilyn

敏捷开发 快速开发

JVM-技术专题-类加载机制

码界西柚

Java JVM

Programmatic Navigation using SwiftUI| 使用SwiftUI进行程序化导航

Daniel

苦难过后,终会团聚

hellocj

国外的公司都是如何对待大龄程序员的?在国内该如何应对?

Java架构师迁哥

百度人工智能OCR调用调试过程

tuuezzy

拜托,学妹,别再问我怎么自学 Java 了!和盘托出

沉默王二

Java 自学编程

第三周作业一

dll

LeetCode题解:94. 二叉树的中序遍历,使用栈,JavaScript,详细注释

Lee Chen

大前端 LeetCode

JVM-技术专题-对象的实例化过程

码界西柚

Java JVM

我和我的智能联接

脑极体

图解 K8S 源码 - Informer 篇

郭旭东

Kubernetes Kubernetes源码

有了TA,领域外企业里的小IT团队,也能轻松搞定大型项目

Marilyn

敏捷开发 快速开发

高难度对话读书笔记—聆听篇

wo是一棵草

一线城市年轻人生活工作录(业务员篇)

Marilyn

敏捷开发 快速开发

一线城市年轻人生活工作实录(程序员篇)

Marilyn

敏捷开发 开发者工具 快速开发

WSDM Cup 2020大赛金牌参赛方案全解析

华为云开发者联盟

大数据 搜索 信息

图扑软件联手阿里Lindorm数据库开启工业物联超融合存储模式

许力

IoT AIOT

华为云专家讲述知识图谱构建流程及方法

华为云开发者联盟

华为 数据 知识图谱

从哲学源头思考自动驾驶网络架构设计

华为云开发者联盟

自动驾驶 架构

医疗AI系统构建(1)one-hot编码

刘旭东

人工智能 学习 医疗AI one-hot

Lindorm云原生数据库 - 让数字时代IT运维系统“灵动”起来

许力

DevOps APM Data Lake AIOPS

OpLog4j

Geek_746da6

OKR-VUCA时代目标管理利器实践分享

张兆东

微前端之如何拆解React巨石应用 qiankun

SugarTurboS

项目管理 架构 大前端 React

年轻人大企打拼多年,刚升迁便遇巨大阻力难以解决,到底如何才能在职场中幸存?

Marilyn

敏捷开发 快速开发

JVM-技术专题-Java类文件结构

码界西柚

Java JVM

在线教育企业迎来“秋招”大考,数字用户体验成胜负关键手

博睿数据

运维 APM 在线教育 AIOPS 用户体验

来喽,来喽,Python 3.9正式版发布了~~~

华为云开发者联盟

Python 编程

亚马逊Prime会员日火爆开启一站购全球逾3000万正品商品

爱极客侠

个人数字人民币钱包即将亮相

CECBC

央行 数字人民币

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