论文地址: 流沙上的建筑-谈系统稳定性 ——Helland&Campbell 2009

    上周我们研究了Bloom中的一致性分析数据库系统中的协调规避。这两种方法的一个共同主题是,应用程序(理解应用程序级语义)和数据存储之间的某种协作是解锁下一级性能的关键。我们可以看到CRDTs的相同方向,它将焦点转移到比简单的读写状态更高的抽象级别。在《流沙上的建筑》(早于上述所有内容)中,Helland&Campbell讨论了在追求ALPS的特性时这一方向的必然性。

    (日志传送)为大多数读者所熟知。经典的数据库系统有一个读取日志并将其发送到备份数据中心的过程。此机制的正常实现在主系统上提交事务(确认用户的提交请求)并异步发送日志。备份数据库会重放日志,不断地进行追赶。

    在这里,我们并没有误入到奇异的NoSQL模型或任何东西中,但是引入这一点异步有着重要的意义…

    日志传送与对客户端的响应是异步的。这必然会打开一个窗口,在该窗口中,工作已向客户端确认,但尚未发送到备份。在此窗口期间,如果主进程失败,则会将主进程中的工作锁定一段未知时间。备份将在不知道锁定工作的情况下继续进行。在大多数日志传送部署中,应用程序设计中不考虑这一点。我们认为这个窗口很少见,没有必要为它做计划。如果你运气不好,坏事就会发生。

    当我们为了节省延迟而从同步检查点转换为异步检查点时,我们就失去了权威真理的概念。在这种情况下,业务规则变成概率性的,一旦发现错误,您将需要一种机制来对其进行分类。

    在许多应用程序中,可以表示应用程序的业务规则,并允许在执行不同操作时重新排序。当操作发生在不同的系统上并相互影响时,必须保留这些业务规则。例如,商业规则可能是:“不要超额预订飞机超过15%”或“不要透支支票账户”

    交换操作可以独立执行,只要它们不违反系统规则。当提升到应用程序操作级别时,如果我们的抽象只在读和写操作中运行,那么它就可以工作:

    存储子系统上任意应用程序的分层禁止重新排序。只有采用交换运算,才能达到理想的松耦合。应用程序操作可以是可交换的。写不是可交换的。存储(即读写)是一个烦人的抽象…

    在业务层面,我们可以就所需的一致性程度做出明智的决定。

    请注意,可以有多个具有不同保证的业务规则。有些操作可以选择经典的一致性而不是可用性(也就是说,它们会减慢速度,减少延迟,并在承诺之前确保正确)。其他的行动可能更为轻率。例如:如果面值小于10000美元,则在本地清除支票。如果超过1万美元,就要仔细检查所有的复制品,以确保其清关;根据当地对库存的看法,安排“哈利波特”书籍的发货时间。相比之下,只有一本古腾堡圣经需要严格的协调!主要的一点是可用性(以及它的同类离线和延迟减少)可以用经典的一致性概念来交换。这种权衡可能经常应用于单个应用程序中的多个不同方面、多个粒度级别。

    (我们不能只在存储级别上操作)。

    事实上,作者认为只要我们允许部分知识,最好的计算模型就是记忆、猜测和回退。

    希望本地复制品能记住它所看到的!

    • 当应用程序基于本地信息做出决定时,它可能是错误的。“在任何允许绝对真理退化的系统中,任何行动充其量都是猜测。”这可能是一个很好的猜测(很可能是正确的),但仍然是一个猜测。
    • 所以有时候会犯错误,你需要一个回退的机制。这可能会触发需要人为干预的手动回退机制,也可能是自动化的。

    在现实世界中运作的每一个企业都需要一个回退机制,而不管一致性模型是什么,因为现实世界中的坏事有时发生在我们的计算机控制之外!例如,送货车可能发生事故,无法按计划送货。

    考虑一个用于预订资源的系统(例如,从库存中销售商品),其中多个副本处理预订请求,有时可能会失去通信。有两种基本模式,您更喜欢的是业务决策:

    您可以通过预先为每个副本分配总库存的配额来超额供应。在这种模式下,你永远不会出售你没有库存的东西,但你很可能会有多余的库存在复制品。
    你可以通过允许独立分配而不需要严格的协调来超额完成预定。这使得你可能会承诺一些你无法兑现的承诺,并需要一种回退机制。
    考虑这样一个情况:库存中的唯一一本书是计划交付的。由于一个过度供应的计划,没有库存的混乱,这本书是承诺给客户的。在准备装运时,它被仓库里的铲车碾过。所以,尽管供应过剩,你需要回退!即使计算机系统是完美的,商业也包括回退,因为事情会出错!

    (座位预订模式是过度供应和过度预订之间的常见折衷方案。当客户端决定是否继续处理事务时,将授予对资源的租约。如果租约在设置超时之前过期,则资源将返回池,客户端必须重新启动)。

    另外还提供了基于Dynamo的Amazon购物车和一个银行应用程序的例子。它们都支持可在不同副本上按不同顺序处理的交换操作。

    单靠存储系统无法提供我们所需的交换性,以创建具有异步检查点功能的健壮系统。我们需要重新订购业务。亚马逊的Dynamo本身并不能做到这一点。位于Dynamo存储系统之上的购物车应用程序负责最终一致性和交换性的语义。作者认为,现在是时候让我们从更新和存储系统的最终一致性的检查中走出来了。真正的操作是在检查基于应用程序的操作语义时发生的。

    ACID的经典定义是原子的、一致的、孤立的和持久的。它的目标是给人一种错觉,即只有一台计算机在处理特定事务时不做任何其他事情。我们讨论的例子指向的是一种新的ACID,ACID 2.0:结合的,交换的,幂等的,分布的

    ACID2.0的目标是,如果工作的每一部分都发生了:

    • 至少一次;在系统的任何地方;以任何顺序。这就定义了一种新的一致性。
    • 单个步骤发生在一个或多个系统上。该应用程序明确地容忍发生无序的工作。它也能容忍每台机器发生不止一次的工作。

    对于旧的ACID,您需要使用悲观或乐观的并发控制机制,“这些机制往往很脆弱……”,但是:

    当应用程序受限于交换性和关联性的附加要求时,世界变得容易得多。不再需要以同步方式跨故障单元检查状态。相反,在信息共享方面可能会非常懒惰。这将打开脱机、慢速链接、低质量数据中心等。令人惊讶的是,我们发现许多常见的业务实践都符合这些约束。从传统上如何执行工作的角度来看业务操作,可以看到许多支持这种方法的示例。在数据库领域,我们似乎对读和写的抽象太过执着,以至于我们忘记了看普通人是如何获得灵感的。

    我们在哪里可以找到设计ACID 2.0系统的灵感?

    现实世界中充斥着关于幂等性、交换性和关联性的算法。它们是真实世界业务平滑的一部分,也是我们在容错平台上必须支持的应用程序的一部分。一个主要的技巧是寻找机制来创建操作或资源的等价性。[…]每当作者在解释如何实现松散耦合的解决方案时,我们都会关注在计算机之前是如何完成的。