聊聊事务的30年发展历史

百家 作者:聊聊架构 2018-04-08 04:38:35
作者|Arjun Narayan
编辑|周元昊

数据库及分布式基础架构的相关社区花了数十年来理解事务的本质这一反复出现的问题。在阅读相关文献时需要读者理解其中的背景,不然就会被其中诸多矛盾的术语及认知所迷惑。为了澄清这点,本文阐述了数据库事务相关论述的演变过程。

在一开始(1990 年?),数据库连接还极其简单粗暴。在丛林法则下,没有行业标准的数据库与使用它们的程序员们必须处理许多异常现象。为了解决这些问题,ANSI SQL-92 标准首次尝试统一定义事务隔离级别。该标准选择了如下方式:

  1. 存在一些已知的异常现象,即脏读、不可重复读和幻读。

  2. 可以利用一些锁策略来防止部分甚至全部上述的异常现象。它们被称为“读未提交”(不进行隔离)、“读已提交”(没有脏读)、可重复读(没有脏读及不可重复读)。

  3. 最终的隔离级别避免了全部三种异常现象。它被称为可串行化(serializable),但是这和字面意思有些出入。暂且可以认为这是整个标准中的一个缺陷。

可串行化的历史相当久远。其定义可追溯到 20 世纪 60 年代,并通过事务中的历史记录来定义。 引用 Christos Papadimitriou 在一篇早期讨论事务的论文中所述:

可串行化是指,一系列原子性的用户更新、获取操作,且其全局的效果就像用户轮流,按一定顺序,独立执行各自的事务一样。

阅读该论文有一定难度,所以简单看来,Herlihy-Wing 已很好地解释了可串行化。但是其中的思想非常简单:每一个事务就像只发生在某一瞬间,而且它们之间存在一定的顺序(但并没有说其中的顺序对用户甚至事务本身需要明确!只需要事后可回溯)。

几年之后,微软数据库团队写了一篇名为《批判 ANSI SQL 隔离级别》的论文,其中指出 ANSI SQL 中定义的可串行化并不是真正的可串行化!ANSI 认为,只要消除了脏读、不可重复读和幻读,就是可串行化的。这一观点是不正确的。事实证明,如果消除这三种异常现象,得到的是另一种新的隔离级别,他们称之为快照隔离。

该论文另一个有价值的贡献是指出了,通过“是否存在特定的异常现象”来界定隔离级别并不是理想的方法。接着来讨论下事务的历史记录,这段时间的相关文献都是通过定义特定的锁策略,并证明其是否会产生异常现象来定义隔离级别的。这会带来一些困惑,因为同一隔离级别可以通过多种锁策略来实现,但其隔离级别的名称又与策略是相关联的,所以同一隔离级别会存在多个名称。

这时出现了一位大神来清理这一乱局:Atul Adya 与他的博士论文《弱一致性:一个通用理论和分布式事务的的乐观实现》。Adya 从追溯事务的历史记录开始。其策略基本上是“根据一些事务的历史记录,可以研究其中变量的转变图”,然后在图中标识出一些形状(其实大部分记录的是不同的周期),并表示“这其中存在问题”。然后,将这些问题的矛头指回到 ANSI 的定义上,并可以追溯到 ANSI 隔离级别的一些基础的数学定义中。该论文的巨大价值在于,终于可以精确且独立于具体实现锁策略地定义隔离级别!

除了给出四个 ANSI 级别的定义之外,他还指出了其它更微妙的异常情况,例如 G2,又称“反依赖循环”,该情况很难被察觉,其存在于快照隔离和可串行化之间的未知领域中。

Adya 的论文在数据库领域是开创性的。这是第一次连贯地通过事务中变量的转变图来给出隔离级别的数学定义。当年是 1999 年,基础设施还不完善。

接下来出现了下一个问题:当我们对事务有了更多的理解后,我们应该如何处理现存的那些混乱的数据库(即 Oracle 和 Postgres,MySQL 至今仍然只是一个玩具产品)?它们声称实现了可串行化,但实际上只是实现了快照隔离,因为它们是按 ANSI 定义来构建的。

Alan Fekete 等人在 2005 年提出了一个好办法,他们称之为“让快照隔离可串行化”。基本上就是通过一个普通的快照隔离数据库,并在 SQL 语句中进行一些校验,以确保其可串行化。他们使用 TPC-C 作为运行示例,该系统已被明确设计为始终可串行化,即使在快照隔离数据库上运行时也是如此。一般应用开发程序员,即使被迫使用的是快照隔离数据库,也可以通过这个技巧得到可串行化的隔离级别。

有了这个好想法,Fekete 在 2008 年的一篇名为《快照隔离数据库上的可串行化隔离》的论文中对这项工作进行了扩展。论文基本上是以该想法为基础,并将那些检查代码从应用程序代码中迁移到了数据库上。因此,用户不必废除已有的事务处理引擎,只需要依赖额外的校验,从而让数据库可串行化。该技术被称为 SSI(可串行化快照隔离),由于采用了两个技术定义,将它们结合起来重新命名一个全新的定义并不奇怪。

在 2012 年,就有开发者决定将这个好想法在 PostgreSQL 上实现,从而让 Postgres 最终拥有可串行化隔离级别。注意,这并不是默认的 postgres 模式,因为 ANSI 认为快照隔离(但仍被称为可串行化)已经足够了。需要指出 ANSI 的定义并没有被修复。

该策略在一篇名为《批判快照隔离》的论文中得到了延续。文中指出,SSI 引导算法可以被简化。原始的 SSI 算法检查双写冲突,为了扩展,Yabandeh 建议改为检测读写冲突。虽然这需要内存中的数据结构记录每次读取的最新时间戳的信息,但对于一些日常的负载来说,其具有更好的并发控制能力,因为它并不会中止读取操作,而只会中止写入操作。

也正是从此,大家开始意识到他们需要关心可串行性,一部分原因是 Jeff Dean 认为其非常重要。与此同时,持续呼吁该观点将近 20 年的 Michael Stonebraker 表示很无奈,大家显然只在 Google 明星工程师声明某件事的重要性时才会关心它。

当下学者们仍有很多焦虑,因为现在我们的处境非常尴尬:

  1. 根据理论,可串行化是唯一的选择。

  2. 很多人使用非串行化的数据库,但基本上并没有遇到问题?

  3. 因此,我们是否在浪费时间?可串行化是否真的有必要?我们到底需要的是什么?

Peter Bailis 在 2014 年的一篇博文中总结了这一点。他说:

尽管存在诸多的弱隔离,但我还没遇到任何数据库架构师、研究人员或用户,可以解释何时以及为什么(这可能更重要)“读已提交”的隔离级别足以满足应用的正确执行。众所周知,这些弱隔离模型代表了“实践中的 ACID”,但我认为我们并没有真正了解为何大量的应用程序看上去(!?)可以在该级别下正确运行。

反面观点多认为:那样的应用并不总能保证正常运行,当你发现问题时,就可能已经太迟了,所以不要尝试。该论点也来之不易,在大家使用 NoSQL 数据库大约十年后,该观点才开始被关注。

原文地址:https://ristret.com/s/f643zk/history_transaction_histories


想跟《Java 编程思想》的作者当面交流?

QCon 北京 2018 将于 4 月 20~22 日举行,目前已经邀请到《Java 编程思想》的作者 Bruce Eckel,《卓有成效的程序员》和《函数式编程思维》等畅销书的作者 Neal Ford,Apache Kafka 主要作者、项目委员会主席(PMC chair)Jun Rao,百度贴吧之父、滴滴产品高级副总裁俞军,Oracle Java 平台事业群 VP Georges Saab,还有 VR 领域的大牛,南澳大利亚大学教授、2013 IEEE VR 技术成就奖得主 Mark Billinghurst,另外 Prometheus 监控系统创始人之一 Julius Volz 也会分享 Prometheus 架构设计与最佳实践。Kotlin 核心开发团队的专家也会到场。

感兴趣的可以点击阅读原文链接或者扫描图片上方二维码了解更多信息。使用折扣码 archtime 报名可立减 200 元。有任何问题欢迎咨询购票经理 Hanna,电话:15110019061,微信:qcon-0410。

关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接