MongoDB、Cassandra、HBase的事务设计策略

2015 年 11 月 10 日

NoSQL 数据库(如 MongoDB、Cassandra、Hbase、DynamoDB、Riak)让应用程序开发变得更简单。它们提供了相当灵活的数据模型和丰富的数据类型,而且与许多传统数据库系统相比,更易于安装和配置。但缺少原子事务支持却是一大退步。Daniel Abadi 是耶鲁大学的一名副教授,主要从事数据库系统架构和实现研究。近日,他在一篇文章中剖析了NoSQL 数据库不支持原子事务的原因,并提供了两种实现可扩展、事务型NoSQL 数据库的方案。

原子事务允许对数据库中的不同数据项同时进行写操作,这些操作要么全部执行,要么全部不执行。而且,结合恰当的并发控制机制,原子性可以确保并发及后续事务要么可以看到原子事务所有已完成的写入,要么一个都看不到。缺少原子事务,应用程序开发人员就需要自己处理一组写操作仅有部分成功的情况。

也许有人会认为,NoSQL 数据库比较新,还没有时间实现原子事务支持。实际上,Cassandra 的“批量更新”特性可以视为向这个方向前进了一小步。不过,NoSQL 数据库已经出现了将近十年,它们没有实现事务支持显然有更深层次的原因,那就是对可扩展性的关注。按照设计,大多数NoSQL 系统都要能够跨多台不同的机器扩展,数据库中的数据分布在不同的机器上。一个事务中的写入操作可能会访问多个分区(在多台机器上)的数据,这就是“分布式事务”。在分布式事务中确保原子性需要参与事务的机器相互协作。每一台机器都必须确定,事务在其它机器上能够成功提交。而且,需要有一个协议,确保事务写入操作涉及的机器在写入数据状态稳定之前都不会出现故障。这个协作过程不仅会消耗大量的资源,而且会增加数据库请求延迟。更大的问题是,在协作过程完成之前,其它操作无法读取该事务写入的数据。并发事务延迟会导致其它与出现延迟的事务在时间上存在重叠的事务延迟,最终导致系统“阻塞(cloggage)”。分布式事务所需的分布式协作会严重影响数据库系统的性能,包括事务吞吐量和事务延迟。因此,大多数NoSQ 系统都选择了不支持事务。

MongoDB、Riak、Hbase 和 Cassandra 都支持单个的事务操作。这是因为单个键的所有信息都存储在单台机器上。因此,单个键的事务操作并不涉及上述复杂的分布式协作。由于分布式事务需要分布式协作,所以似乎必须在性能可扩展性和分布式事务支持之间进行权衡。事实上,许多NoSQL 数据库提供商都是基于这个假设,在构建可扩展系统时,为了防止服务器性能退化,放弃支持分布式原子事务。

Daniel 指出,这是完全错误的。可扩展系统是可以支持高性能分布式原子事务的。他们最近发表了一篇论文,提出了一种在可扩展系统中支持原子事务的、新的权衡策略,具体是在公平性、隔离性和吞吐量(FIT)三者之间进行取舍。其中,公平性是指任何事务的执行都不会因为其它事务被故意延迟,而隔离性可以确保相互冲突的事务可以看到其它事务的写入操作。一个支持分布式原子事务的可扩展数据库至少可以实现上述三个属性中的两个。FIT 三者之间的取舍可以产生三种支持分布式原子事务的方案:

  • 保证公平性和隔离性而牺牲吞吐量的系统;
  • 保证公平性和吞吐量而牺牲隔离性的系统;
  • 保证隔离性和吞吐量而牺牲公平性的系统。

换句话说,下面两种方法都可以构建出具备高分布式事务吞吐量的可扩展系统。

放弃隔离性

如上所述,导致数据库系统阻塞的根本原因是分布式协作。更确切地说,如果一个事务正在执行,那么其它需要访问共享数据的事务必须等到分布式协作完成后才能进行。这种等待就是由强隔离性所保证的,因为它确保事务可以看到与它冲突的事务。如果放弃隔离性,那么其它事务就看不到其它事务的操作,也就不必等待分布式协作完成就可以执行和提交。而且,有一类数据库约束可以确保分布式数据库在事务弱隔离情况下的正确性。更多信息可以阅读 Peter Bailis 的文章《多分区原子读(RAMP)》。

放弃公平性

分布式协作同隔离机制在时间上存在重叠。所以,可以通过重新设定分布式协作的顺序最小化两者之间的时间重叠,从而减轻二者之间的相互影响。以此为基础构建的系统放弃了公平性,可以选择最合适的时间进行分布式协作,Daniel 将这样的系统称为“隔离性- 吞吐量”系统。比如,可以在事务之外进行协作,协作所需的时间不会增加并发事务的执行时间。

G-Store 就是一个很好的“隔离性 - 吞吐量”系统示例。它支持多键事务,并将事务范围限制为应用程序动态定义的键集,即 KeyGroup。该键集可以随需创建和销毁。当应用程序定义了一个 KeyGroup,G-Store 会将相应的键值对全部复制到一个领导节点上,该键集上的所有事务都会在该领导节点上执行。因此,G-Store 事务并不需要在事务执行期间执行分布式提交协议。这里的关键是,G-Store 仍然必须执行分布式协作,但协作过程在事务执行之前完成——在需要考虑事务隔离性之前。一旦协作过程完成,事务很快就会完成,共享数据的并发事务就不需要等待分布式协作。这样,G-Store 就实现了高吞吐量和强隔离性。

因此,实现高吞吐量分布式事务的关键是按照上述方法在时间上将分布式协作同隔离机制分开。


感谢郭蕾对本文的审校。

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

2015 年 11 月 10 日 18:004976
用户头像

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

关注

评论

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

第十周总结

fmouse

极客大学架构师训练营

初学小白你不知道的C语言经典算法(附带答案)

ShenDu_Linux

c++ 程序员 算法 C语言 数据结构与算法

在Spring data中使用r2dbc

程序那些事

WebFlux R2DBC 程序那些事 spring data spring-data-r2dbc

试试,阿里P7的笔试题:多线程按序打印如何实现?

Java架构师迁哥

今日份学习之Spring Boot自动配置实现原理

比伯

Java 编程 架构 面试 计算机

如果不想你被称做掉包侠,那么请有效地学习机器学习算法知识

计算机与AI

学习

架构师训练营第十周总结

_

总结 极客大学架构师训练营

食堂就餐卡系统设计

cc

架构师训练营—第十周作业

Geek_shu1988

第十周作业

fmouse

极客大学架构师训练营

程序员:我熟悉多线程!面试官:都不敢写精通,还敢要26K?

Crud的程序员

编程 程序员 面试 多线程

架构师训练营一期学习心得

cc

redis 基础数据 sets 业务场景分析

sinsy

redis 业务场景分析

在网上的AG账户登录异常说是涉嫌套利不给办理取出怎么办?

Geek_a6658e

专业出黑团队

大家都知道jmeter,但是它会让你的工作效率至少提升80%

996小迁

Java 编程 程序员 架构 面试

Java-Mock简化单元测试

落日楼台H

Java 测试 单元测试 Mock Mock测试框架

刘华:上云后,你的架构设计可以更飞

刘华Kenneth

云计算 架构设计 技术选型 云平台

《华为数据之道》读书笔记:第 5 章 面向“联接共享”的数据底座建设

方志

大数据 数据中台 数据仓库 数字化转型

架构师训练营第 1 期 -- 第十周作业

发酵的死神

极客大学架构师训练营

架构师训练营第十周作业

_

极客时间架构师一期 第十周作业

架构师Week6总结

lggl

总结

一万三千字的HashMap面试必问知识点详解

云流

Java 编程 面试 计算机

架构师训练营 1 期第 10 周:模块分解 - 总结

piercebn

极客大学架构师训练营

架构师训练营—第十周学习总结

Geek_shu1988

一次有效的产品需求头脑风暴

Bruce Talk

敏捷开发 Agile Product Owner

刘华:我最近听到最对味的话,就是“先Scale down再Scale out”

刘华Kenneth

DevOps 敏捷

作业-第6周

arcyao

架构师训练营第六周作业

丁乐洪

尾调用与尾递归

哈希说

算法

LeetCode题解:860. 柠檬水找零,模拟情境,JavaScript,详细注释

Lee Chen

算法 LeetCode 前端进阶训练营

STL 源码剖析之五大组态常量介绍

herongwei

c++ 源码 后端 stl

MongoDB、Cassandra、HBase的事务设计策略-InfoQ