`

Base: ACID外的另外一种选择

 
阅读更多

Base: ACID外的另外一种选择

 

在分区数据库中,为可用性牺牲一定的一致性能够显著提高可扩展性

DAN PRITCHETT, EBAY

 

在过去的十年中,Web应用变得日益流行。无论您是为最终用户构建应用程序还是为应用程序开发人员(即服务),您希望您的应用程序是最可能被广泛采用的,而广泛的应用将会使事务处理量增长。如果您的应用程序依赖于持久性,那么数据存储很可能将成为你(系统)的瓶颈。

 

任何应用程序可以有两种策略进行扩展。第一种,也是迄今为止最简单的,是垂直扩展:把应用迁移到大型机。垂直扩展对数据来说相当不错,但有一些局限性。最明显的局限性在于系统最大可用容量的扩展。垂直扩展也很昂贵,增加事务处理能力,通常需要采购一个(比现在用的系统)更大的系统。垂直扩展通常也会导致供应商锁定,而这将进一步增加了成本。)

[译者备注:供应商锁定是指你采用了一个技术,即将自己锁定在这家提供商身上,不能轻易转换提供商。]

 

水平扩展则提供了更多的灵活性,但也更复杂。水平数据扩展可以沿两个维度进行。功能扩展涉及到根据功能进行数据分组以及对这些功能组进行跨数据库部署。而将属同一功能域内的数据进行跨数据库的拆分,或叫分片,这是水平扩展的第二个维度。图1展示了水平数据扩展策略。

正如图1所示,这两种水平扩展的方法可以一起使用。userproductstransaction,可以分隔在不同的数据库中。此外,每个功能区也可以被分割在多个数据库以提高事务处理能力。正如图中所示,每个功能区可以彼此独立地扩展。

 

功能分区

实现高可扩展性,对功能进行分区是非常重要的。任何一个优秀的数据库架构将依据[不同的]功能把[对应]模式分组拆分到不同的表中。userproducts, transactioncommunication均是各个功能区的例子。利用数据库的概念,如外键,是一种在这些功能区之间保持一致性的通用方法。

 

依托数据库[本身提供的]约束机制来保证各个功能组之间的一致性,这对数据库部署策略来说是一个耦合的模式。应用这些约束的表必须驻留在一个单一的数据库服务器中,随着事务量的增长这将不利于进行水平扩展。在许多情况下,最简单的向外扩展办法是把不同功能组的数据迁移到分散的数据库服务器中。

 

能够扩展到支持非常高事务量的架构将功能不同的数据分布在不同的数据库服务器上。这需要把数据约束从依赖数据库转到依赖应用程序本身。但这会存在一些挑战,这篇文章稍后章节将会重点介绍。

 

CAP定理

埃里克·布鲁尔,加州大学伯克利分校教授,兼lnktomi的联合创始人和首席科学家,提出了一个猜想:Web服务无法确保所有下列的三个属性同时满足(缩写为CAP):

 

一致性:客户感知到一系列操作能够一下子执行完毕。

 

可用性:每一个操作必须有意想中的响应并终止。

 

分区耐受性:操作均能够执行完毕,即使个别组件不可用。

 

具体而言,Web应用程序,任何数据库设计中,最多只有可以支持到这些属性中的两个。显然,任何水平扩展策略是基于对数据进行分区,因此,设计人员不得不在一致性和可用性之间做选择。

 

ACID的解决方案

ACID数据库事务处理大大简化了应用程序开发人员的工作。正如缩写所指,ACID事务提供了以下的保证:

 

原子性:同一事务中的所有操作要么都完成,要么都没有完成。

 

一致性:数据库在事务的开始和结束时将处于一致的状态。

 

隔离性:每个事务的行为就好像它在数据库中是唯一执行的操作一样。

 

永久性:在事务完成后,该操作的结果将无法逆转。

 

数据库厂商很久前就认识到有必要进行数据库分区,并介绍了被称为2PC(两阶段提交)的技术,该技术提供了跨多个数据库实例的ACID保证。该协议分成两个阶段:

 

首先,事务处理协调器要求所涉及的每个数据库进行预提交操作,并上报是否可能进行提交操作。如果所有数据库同意可以进行提交,则第2阶段开始。

事务处理协调器要求每个数据库提交数据。

如果有任何数据库否决提交操作,则要求所有的数据库回滚部分的事务。缺点是什么呢?如果布鲁尔是正确的,我们获得了分区的一致性,那么我们就必然会影响到可用性,但怎么可能呢?

 

任何一个系统的[整体]可用性是由操作所涉及到的各个组件的可用性所决定的。该声明的最后部分是最重要的。系统可能用到的但不是必须的组件不应降低系统的整体可用性在两阶段提交中涉及两个数据库的事务的可用性将由每个数据库的可用性决定。例如,如果我们假设每个数据库的可用性是99.9%,那么事务的可用性变为99.8[译者:总体可用性=99.9%*99.9%=99.8%],或额外的停机时间为43分钟/每月。

 

ACID外的另外一种选择

既然ACID已经为分区数据库提供了一种一致性的选择,那么你该如何去获取可用性呢?答案之一是BASE(基本可用,软状态,最终一致)。

 

BASEACID是截然不同的。ACID是悲观的,并强制保证每一个操作完毕后的一致性,而BASE是乐观的,它接受该数据库的一致性将处在不定的状态中。虽然这听起来比较棘手,但在现实中,它是相当易于管理且可以获得ACID中无法获得的可扩展性。

 

BASE的可用性是通过容忍部分失败而不导致系统整体不可用而获得的。下面是一个简单的例子:如果user被划分在5个数据库服务器中,基于BASE的设计则鼓励比较特殊的操作方式:某个user数据库的故障仅影响分布在该主机上的20%的用户。这没有什么神奇的,但能够获得更高的系统可用性。

 

所以,现在你已经把数据分解到不同功能组且把最繁忙的功能组进行跨数据库的分区,那你将如何把BASE用到你的应用程序吗?相比典型的ACID应用,BASE需要更深入的分析一个逻辑事务中的操作情况。你应该关注什么?以下各节提供了一些指引。

 

一致性模式

根据的布鲁尔猜想,如果BASE允许分区数据库的可用性,那么放松一致性的机会是必然的。但这是非常困难的,因为企业的利益相关者和开发商趋向于断言,一致性对应用的成功是最重要的。从最终用户来看暂时的不一致不能被屏蔽,所以工程负责人和产品负责人两者都必须挑选放松应用一致性要求的机会。

【译者:这里的意思应该是由于企业利益相关者和开发商断言一致性非常重要,且暂时不一致对用户来说无法屏蔽,因此采取放松一致性策略的时候,工程和产品负责人需要参与一起讨论协商,达成共识】

 

2是一个简单的例子,展示了BASE在一致性方面的考虑。user表保存用户的信息,包括出售和购买的总金额。这些是运行中的总数。transaction表保存有关的每一笔交易,包括买家和卖家以及交易的金额。虽然这些表相比真正的表过于粗略,但包含了展示一致性方面必要的元素了。

 

一般情况下,跨功能组比在合在同一组内更容易放松一致性。示例模式有两个功能组:usertransaction。每次卖出一个物品,将会往transaction表添加一条记录和更新买方和卖方的计数。若SQL使用ACID式的事务,则对应的SQL将如在图3中所示。

 

user表中的总购买和出售列可以认为是transaction表的一个缓存。这是本系统的效率。鉴于此,一致性的约束可以放宽。我们可以设置买卖双方方的预期,让他们知道他们的余额不会立即反映一个交易的结果。其实这是并不少见,事实上人们常常会遇到这种交易和他们的余额之间延迟的情况(例如,ATM取款和手机打电话)。

 

如何修改SQL语句以支持放松一致性则取决于余额是如何定义的。如果它们是简单的估计,这意味着某些交易可以容忍丢失,那么修改就变得很简单了,如图4所示:

 

现在,我们已经把更新操作从user表和transaction表分离了。表之间的一致性无法得到保证。事实上,若第一和第二个事务之间发生了故障,将导致user表中的永久不一致,但如果规定余额只用于估算的,这可能已经足够了。

 

但如果估算是不能接受的呢?你将如何能够把更新操作从user表和transaction表解耦呢?这里介绍一个持久消息队列机制来解决这个问题。实现持久性消息有多种选择。但是,在实现队列中,最关键因素是确保在同一资源上的数据库上支持持久性[译者说明:即入队列的操作跟transaction在同一主机上,这样可以避免分布式事务的2PC]。这是必要的,

能够保证跟事务提交队列无需涉及到2PC(两阶段提交)。现在的SQL操作看起来有点不同,如图5所示。

 

这个例子需要一些自由的语法和非常简化的逻辑来说明这个概念。通过在同一事务中进行插入操作把永久消息入队列,能够捕获到更新正在运行的user表所需要的信息,该事务包含在单一的数据库实例中,因此不会影响系统的可用性。

 

一个单独的消息处理组件将出列的每个消息运用到对应的user表。这个例子貌似解决了所有的问题,但有一个问题。在入队列操作中,为了避免2PC,消息持久性是在事务主机上的。若消息出列操作在涉及user所在主机的事务内,则我们仍然需要2PC

 

在消息处理组件中处理2PC问题的一个解决方案是什么都不做。通过把更新操作解耦到一个单独的后端组件,你可以保留面向客户的组件的可用性。对业务需求来说,消息处理器较低的可用性可能是可接受。

 

然而,假设2PC在您的系统中是根本无法接受的。这个问题如何解决呢?首先,你需要了解幂等性的概念。一个操作如果可以执行一次或多次且都具有相同的结果,则该操作认为具有幂等性。具有幂等性的操作是非常有用的,因为它们允许部分失败,他们反复运用和执行但不改变系统的最终状态。

 

寻找幂等性时所选择例子的问题是:更新操作很少幂等。例如增加余额列的地方。应用这个操作不止一次显然会导致一个不正确的余额,哪怕只是简单地设置一个值的更新操作,然而如跟操作顺序相关,则也不是幂等的。如果系统不能保证以接收的先后顺序进行更新操作,系统的最终状态将是不正确的。后面有更多这块的讨论。

 

在余额更新的例子中,你需要一种方法来跟踪哪些更新已成功地执行和哪些依然未执行。其中一种技术是使用一个表,该表记录已被成功执行的事务标识符。

 

在图6中所示的表跟踪记录了余额已被更新的事务ID和余额已经增加的用户ID。现在,我们的示例伪代码如图7所示。

 

 

 

 

【译者说明:例子有些错误:

Select count(*) as processedfrom updates_applied where trans_id=message.trans_id and balance=message.balance and user_id=message.user_id;

用于查找对应的记录是否已经处理,若仍未处理,则进入下一步取出队列处理。】

 

这个例子依赖于在队列中能够提取一个消息并且一旦处理成功可以从队列中移除。如果有必要这可以用两个独立的事务:一个在消息队列和一个对用户数据库。除非数据库操作成功并提交否则队列操作可以不提交。而现在的算法支持部分失败,并仍然提供事务保证而无需借助于2PC

 

有一个简单的技术,以确保幂等的更新,唯一担心的就是顺序。让我们稍微改变一下我们的示例模式来说明这种挑战和解决方案(参见图8)。如果你也想追踪用户的最后购买和销售的日期。你可以依靠类似消息更新日期的模式,但有一个问题。

 

假设两个购买发生在一个短的时间窗口内,并且我们的消息系统并不确保按序操作。现在有一种情况,即依赖于处理消息的顺序,last purchase将会有一个不正确的值。幸运的是,通过稍微修改SQL语句这种更新可以进行处理,如在图9所示。

 

通过不允许last_purchase的值小于向后的某个时间,您所做的更新操作便跟顺序无关【译者说明:即update的时候只能update那些last_purchase小于交易的记录,这样就无需确保消息处理的顺序了,相当于是在user表同步保存了一个最新交易的时间戳】。您也可以使用这个方法来保护任何更新以避免无序。作为使用时间的替代方法,你也可以尝试一个单调递增的事务ID

 

消息队列的顺序

关于有序消息分发的不足也是值得注意的【译者:翻译不是很明确,原句是A short side note on ordered message delivery is relevant.】。消息系统提供了一种确保按他们接收消息顺序进行分发的能力。这可能是昂贵且往往是不必要的,而且,事实上,有时给人一种虚假的安全感。

 

这里提供的例子说明如何可以放宽消息的顺序,并仍然提供了一个数据库最终一致性的看法。放松顺序所需的开销是名义上的,并在大多数情况下是显著低于在消息系统中强制有序性[的开销]

 

此外,Web应用程序在语义上是一个事件驱动的系统而跟交互的风格无关。客户端请求以任意顺序到达系统。处理每个请求需要的时间各不相同。贯穿在整个系统各个组件的请求调度是不确定的,这造成非确定性的消息队列。顺序要求被保留只不过是以给人一种虚假的安全感。而简单的事实是不确定的输入会导致不确定的输出。

 

软状态/最终一致性

到此刻为止,焦点在于用一致性换取可用性。另一面是理解软状态和最终一致性对应用程序设计上的影响。

 

作为软件工程师,我们往往看我们的系统是一个封闭循环。我们认为,系统的行为具有可预性,即可预见的输入产生可预测输出。这对建立正确的软件系统是必要的。在许多情况下,好消息是,使用BASE并不改变为闭环系统的可预测性,但它确实需要研究[系统的]总体行为。

 

一个简单的例子可以说明这一点。考虑一个系统,用户可以将资产转让给其他用户。这里资产的类别是无关的,可以是在游戏中的金钱或物品。在这个例子中,我们将假设使用消息队列机制用于解耦,且我们已经分离了两个操作 -资产从一个用户转出和资产从另外一个用户存入。

 

随即,[我们]可以感到该系统是不确定和有问题的。资产从一个用户转出且未转入另外一个用户之间存在一段时间的延迟。这个时间窗口的大小可以由消息传送系统的设计来确定。无论如何,在开始和结束状态之间存在一个滞后时间,这个滞后时间中两个用户貌似资产都消失了[译者说明:此时用户A已经转出资产了,但用户B没收到资产,所以两个用户都没有资产,貌似资产消失了]

 

然而,如果我们从用户的角度来看,这种滞后可能是不相干或用户是感知不到的。无论是接收用户还是发送的用户可能均不知道什么时候该资产到帐。如果发送和接收之间的时间差只是几秒钟,这对资产转移进行直接沟通的用户来说无疑是感知不到或是可以一定容忍的。在这种情况下,系统的行为被认为是一致的且用户能够接受的,即使我们在实现中依赖软状态和最终一致性。

 

事件驱动的架构

如果你确实需要知道什么时候状态已经成为一致的吗?您可能需要一些运用于状态的算法,但只有当它已达到跟输入请求相关的一致的状态,简单的方法是依赖随状态变一致所产生的事件。【[译者说明:翻译不是很准,大家有好的可以分享,原句是:What if you do need to know when state has become consistent? You may have algorithms that need to be applied to the state but only when it has reached a consistent state relevant to an incoming request. The simple approach is to rely on events that are generated as state becomes consistent.

 

继续前面的例子,如果你需要通知用户的资产已经到账呢?在事务中创建一个提交资产给接收用户的事件,该事件提供了一个一旦到达某个已知的状态进行进一步处理的机制。 EDA(事件驱动的架构)可以提供显著改善的可扩展性和架构解耦。关于EDA应用的进一步的讨论则超出了本文的范围。

 

结论

扩展系统以显着支持大量事务需要一种新的方式考虑资源管理。当负载需要分散到大量的组件上时,传统的事务模式是有问题的。操作解耦和执行,在牺牲一定的一致性下,反过来可以提高可用性和可扩展性。BASE提供了一种思考这种解耦的模式。

 

参考文献

http://highscalability.com/unorthodox-approach-database-design-coming-shard

http://citeseer.ist.psu.edu/544596.html

DAN PRITCHETT一直是eBay的一名技术人员,在过去的四年里,他已经是ebay架构团队的成员。In this role, he interfaces with the strategy, business, product, and technology teams across eBay marketplaces, PayPal, and Skype.。他在如Sun Microsystems, Hewlett-Packard Silicon Graphics公司有拥有超过20年的经验,在技术方面,Pritchett有极深的经验,领域涉及包括从网络级协议和操作系统到系统设计以及软件模式。他从密苏里大学罗拉分校的计算机科学获得了理学学士。

 

分享到:
评论

相关推荐

    行业教育软件-学习软件-Acid-base titration 5.0 英文版.zip

    《酸碱滴定模拟软件Acid-base titration 5.0 英文版深度解析》 酸碱滴定是化学实验中的一个重要环节,用于测定溶液中酸或碱的浓度。在现代教育领域,为了使学生更好地理解和掌握这一过程,出现了各种教育软件。...

    OceanBase企业级数据库介绍.pptx

    OceanBase 使用 Paxos 和 Raft 两种协议来实现分布式事务和可靠性。Paxos 协议可以确保事务的一致性和可靠性,而 Raft 协议可以提供高可用性和可扩展性。 OceanBase 的优势: OceanBase 的透明可扩展性、分布式...

    Acid-base catalysis

    酸碱催化是化学反应中的一种重要机制,主要涉及酸或碱作为催化剂促进反应的过程。在本文中,我们将深入探讨酸碱催化的基础知识、不同类型的催化剂、表征方法以及各种催化反应。 1. 基本原理 酸碱催化理论基于Brø...

    OceanBase企业级分布式数据库介绍.pdf

    OceanBase是一种透明可扩展的企业级数据库,具有高性能、可扩展性和高可用性的特点。它可以满足企业级数据库的需求,解决传统数据库的单机不可扩展和成本高的问题。 透明可扩展的理论基础 OceanBase的透明可扩展...

    OceanBase OBCA认证模拟试题

    1. 分库分表架构:这种架构是解决集中式数据库扩展性问题的一种方法,但它确实引入了新的挑战,如不支持复杂的SQL操作和在分布式环境中保证事务的ACID属性(原子性、一致性、隔离性和持久性)变得困难。 2. 传统...

    OceanBase分布式数据库技术概述.pdf

    事务抽象的目标是提供一种机制, guaranteeing atomicity, consistency, isolation, and durability (ACID)。 故障恢复: 故障恢复是数据库管理系统中的一大挑战。所有处理持久化状态的程序都必须面对的难题。...

    SQL Base.rar

    SQL Base,全称为Structured Query Language Base,是一种基于SQL标准的关系型数据库管理系统,它提供了一种高效、稳定的方式来存储和管理数据。SQL Base通常用于小型到中型企业,为应用程序提供后台数据支持,尤其...

    分布式系统一致性(ACID、CAP、BASE、二段提交、三段提交、TCC、幂等性)原理详解1

    然后,BASE原则是大型分布式系统中常用的一种弱一致性模型,它是Basically Available(基本可用)、Soft state(软状态)和Eventually Consistent(最终一致性)的组合。它允许系统在短时间内容忍不一致,但最终会...

    CAP原理和BASE思想.docx

    BASE是相对于ACID的一种设计理念,适用于大规模分布式系统的场景,主要由以下三个概念构成: 1. **基本可用(Basically Available)**:系统在出现故障时,仍能提供服务,虽然服务质量可能会有所下降。 2. **软状态...

    OceanBase OBCA 部分题目

    OceanBase OBCA 认证涉及的是OceanBase数据库的相关知识,这是一个分布式的、高可用的、高性能的数据库系统。以下是对部分题目所涵盖知识点的详细解释: **分布式数据库的挑战和解决方案** - 分库分表架构可以解决...

    蚂蚁金服自研数据库OceanBase的设计与实践哲学.pdf

    3. 通用关系型数据库:OceanBase支持ACID(原子性、一致性、隔离性、持久性)特性,这使得它成为一个通用的关系型数据库,能够处理各种复杂的业务场景。 4. 原生分布式数据库:OceanBase被归类为NewSQL数据库,它在...

    企业级分布式数据库实践专场__深入OceanBase企业级数据库的分布式事务引擎.zip

    1. **两阶段提交(2PC)**:2PC是一种经典的分布式事务协调协议,分为准备阶段和提交阶段。在OceanBase中,当一个事务涉及到多个节点时,协调者会先询问所有参与者是否可以提交事务,只有所有参与者都同意后,才会...

    OceanBase云数据库在金融核心系统架构实践.pdf

    总而言之,OceanBase云数据库通过其独特的分布式架构和高可用设计,成功地适应了互联网时代金融核心系统的需求,提供了一种既能保证数据安全性,又能实现横向扩展的新型数据库解决方案。随着技术的不断演进,Ocean...

    java面试 distributed-system中知识点 BASE理论 整理.pdf

    最终一致性是系统所有数据副本经过一段时间的同步后,最终达到一致状态的一种保证。它不强求立即的一致性,而是强调在可接受的时间范围内确保数据的一致性。这对于许多互联网应用是可接受的,因为实时的强一致性往往...

    化工原料和产品中英文对照.doc

    2. **柠檬酸(Citric Acid)**:一种有机酸,广泛用于食品、饮料和制药行业,作为酸味剂和防腐剂。 3. **硝酸钙(Calcium Nitrate)**:一种肥料和炸药成分,也可用于水处理和植物营养。 4. **癸二酸(Sebacic ...

    一种面向海量分布式数据库的嵌套查询策略.pdf

    为了解决这一问题,文章提出了一种新的基于BloomFilter和HashMap的查询策略,旨在提升OceanBase的嵌套查询性能。 BloomFilter是一种空间效率高的概率型数据结构,用于快速判断一个元素是否在一个集合中。它利用位数...

    46弹力设计篇之“补偿事务”1

    4. **补偿事务**:在BASE理论中,补偿事务是一种处理事务的方法,当事务的一部分失败时,通过执行逆操作(补偿操作)来恢复系统的状态。例如,如果在订单处理中出现超卖,可以通过取消已分配但无法履行的订单来补偿...

    一种面向分布式读写分离系统的数据同步策略.pdf

    在众多分布式数据库的优化策略中,读写分离是一种常见的优化手段,其旨在通过分离数据库的读写操作来提高系统的性能和并发处理能力。 读写分离的基本思想是将数据库的读操作和写操作分离,写操作集中在单个节点进行...

Global site tag (gtag.js) - Google Analytics