CN116529724A - 在无共享分布式数据库中快速检测和修复故障的系统和方法 - Google Patents

在无共享分布式数据库中快速检测和修复故障的系统和方法 Download PDF

Info

Publication number
CN116529724A
CN116529724A CN202180070442.1A CN202180070442A CN116529724A CN 116529724 A CN116529724 A CN 116529724A CN 202180070442 A CN202180070442 A CN 202180070442A CN 116529724 A CN116529724 A CN 116529724A
Authority
CN
China
Prior art keywords
host
transaction
instance
engine
row
Prior art date
Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
Granted
Application number
CN202180070442.1A
Other languages
English (en)
Other versions
CN116529724B (zh
Inventor
W·H·小布里奇
D·布罗尔
M·许
B·克洛茨
N·J·S·迈克诺顿
A·米拉瓦拉普
U·潘查克沙拉雅
G·F·斯沃特
T·拉希里
J·R·洛埃扎
Current Assignee (The listed assignees may be inaccurate. Google has not performed a legal analysis and makes no representation or warranty as to the accuracy of the list.)
Oracle International Corp
Original Assignee
Oracle International Corp
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Priority claimed from US17/123,405 external-priority patent/US11392616B2/en
Application filed by Oracle International Corp filed Critical Oracle International Corp
Publication of CN116529724A publication Critical patent/CN116529724A/zh
Application granted granted Critical
Publication of CN116529724B publication Critical patent/CN116529724B/zh
Active legal-status Critical Current
Anticipated expiration legal-status Critical

Links

Abstract

提供了一种无共享数据库系统,其中每个表的行被指派给“切片”,并且每个切片的多个副本(“复本”)跨多个节点的持久存储装置存储。从表的特定行读取数据的请求可以由存储该行所指派到的切片的复本的任何节点处置。对于每个切片,切片的单个复本被指定为“主复本”。所有DML操作都由具有目标行所指派到的切片的主复本的节点执行。然后将改变传播到同一切片的其它复本(“二级复本”)。

Description

在无共享分布式数据库中快速检测和修复故障的系统和方法
对相关申请的交叉引用、权益声明
本申请根据35U.S.C.§120要求作为于2020年10月14日提交的申请序列No.17/070,277的部分继续申请的权益,该申请No.17/070,277通过引用整体并入本文,就好像在本文完整阐述了一样。申请人特此撤销母申请或其审查历史中对权利要求范围所做的任何弃权声明,并告知USPTO本申请中的权利要求可以比母申请中的任何权利要求更广泛。
技术领域
本发明涉及存储系统,并且更具体而言,涉及无共享数据库系统(shared-nothingdatabase system)。
背景技术
在多处理系统上运行的数据库通常分为两类:共享持久存储数据库和无共享数据库。共享持久存储数据库预期计算机系统中的所有持久存储设备对所有处理节点都是可见的。因此,共享持久存储数据库系统中的协调器进程可以将任何工作颗粒(work granule)指派给任何节点上的进程,而不管包含在该工作颗粒执行期间将被访问的数据的持久存储装置的位置。共享持久存储数据库可以在无共享和共享持久存储计算机系统两者上运行。为了在无共享计算机系统上运行共享持久存储数据库,可以向操作系统添加软件支持,或者可以提供附加的硬件以允许进程直接访问远程持久存储设备。
无共享数据库假设只有当数据被包含在与进程属于同一节点的持久存储装置中时,该进程才能访问该数据。因此,只有在要在工作颗粒中处理的数据驻留在与进程相同的节点中的持久存储装置中的情况下,无共享数据库中的协调器进程才能将工作颗粒指派给该进程。无共享数据库可以在共享持久存储装置和无共享多处理系统两者上运行。为了在共享持久存储机器上运行无共享数据库,可以提供一种机制来对数据库进行逻辑分区,并将每个分区的所有权指派给特定节点。
基于前述,显然期望提供一种对无共享数据库系统的哪个节点能够处理工作的限制较少的无共享数据库系统。例如,当任务正在读取存储在数据库系统中的特定数据项的特定版本时,期望提供如下无共享数据库系统,其中有多个节点能够执行该任务。能够执行同一任务的节点的数量越大,工作负载就越容易在可用节点之间平衡。此外,期望执行读取操作的节点能够读取截至指定的快照时间的数据。为了进一步提高性能,期望在不获得锁的情况下执行读取操作,并且即使在读取尚未提交的事务所触及的数据项时也不阻塞。
本节中描述的方法是可以采用的方法,但不一定是先前已经设想或采用的方法。因此,除非另有说明,否则不应仅由于将本部分中所述的任何方法包括在本部分中而认为本方法中的任何方法都有资格作为现有技术。另外,不应当假设本节中描述的任何方法仅仅因为它们被包括在本节中就已被充分理解、是例行或常规的。
附图说明
图中:
图1是根据实施例的分布式数据库系统的框图,图示了主机、数据库和表空间(table space)之间的关系;
图2是根据实施例的分布式数据库系统的框图,其中表的行被映射到切片(slice),并且为每个切片存储多个副本;
图3是图示根据实施例的切片的副本的内容的框图;
图4是图示根据实施例的两行R1和R2的时间顺序条目链(chronological entrychains)的框图;
图5是图示根据实施例的在条目被添加到时间顺序条目链的尾部之后行R1的时间顺序条目链的框图;
图6是图示根据实施例的在链中的增量日志条目(delta log entry)被应用于行堆(row heap)之后行R1的时间顺序条目链的框图;
图7是图示根据实施例的增量日志的循环缓冲器性质的框图;
图8是图示根据实施例的行堆条目的内容的框图;
图9图示了根据实施例的在数据库命令的语句的执行期间发送的主机间消息(inter-host message);
图10图示了根据实施例的在事务提交期间发送的主机间消息;
图11是可以被用作采用本文描述的技术的分布式数据库系统中的客户端或主机的计算机系统的框图;
图12是图示根据实施例的具有在六个主机上执行的两个引擎集群和一个控件集群(control cluster)的分布式数据库系统的框图;
图13是更详细地图示来自图12的主机的框图;
图14是图示根据实施例的当主机发生故障时在控件集群和主机之间发送的消息的框图;
图15是图示根据实施例的当主机发生故障时重新配置主机集群所采取的步骤的流程图;以及
图16是图示根据实施例的包括控件集群的分布式数据库系统的框图,其中所有主机能够通过两个不同的网络彼此通信。
具体实施方式
在下面的描述中,出于解释的目的,阐述了许多具体细节以便提供对本发明的透彻理解。然而,将清楚的是,可以在没有这些具体细节的情况下实践本发明。在其它情况下,以框图形式示出了众所周知的结构和设备,以避免不必要地混淆本发明。
总体概述
提供了一种无共享数据库系统,其中通过将每个表的行指派给“切片”并跨无共享数据库系统的多个节点的持久存储装置存储每个切片的多个副本(“复本”)来提高并行性和工作负载平衡。当用于表的数据以这种方式分布在无共享系统的节点之间时,用于从表的特定行读取数据的请求可以由存储该行被指派到的切片的复本的任何节点处置。
根据实施例,对于每个切片,切片的单个复本被指定为“主复本”。以表的特定行为目标的所有DML操作(例如,插入、删除、更新等)都由具有指派给该特定行的切片的主复本的节点执行。然后将DML操作所做的改变从主复本传播到同一切片的其它复本(“次级复本”)。
切片
如上面所提到的,“切片”是表的行被指派到的实体。可以以多种方式进行行到切片的指派,并且本文描述的技术不限于任何特定的行到切片指派技术。例如,表可以具有主键,并且每个切片都可以被指派有主键落在特定范围内的行。在这种实施例中,其主键是字母的表可以将其行指派给三个切片,其中第一切片包括其主键以A-K范围内的字母开头的行,第二切片包括其主键以L-T范围内的字母开头的行,而第三切片包括其主键以U-Z范围内的字母开头的行。
作为另一个示例,可以使用散列函数进行行到切片指派。例如,可以使用产生范围1-3内的散列值的散列函数来将行指派给三个切片。任何给定行被指派到的切片是根据在散列函数被应用于该行的主键时所产生的散列值确定的。
对于任何给定的表,其行被指派到的切片的数量可以基于多种因素而变化。根据一个实施例,切片的数量被选择为使得没有单个切片将存储超过1GB的数据。因此,作为一般规则,表中包含的数据越多,表的行被指派到的切片的数量就越大。
在表没有指定的主键列的情况下,为了将表的行指派给切片,数据库系统创建列并用可以充当主键的值来填充它。这种系统创建的主键列的值可以是例如随着每个新行而增加的整数值。这仅仅是可以如何创建系统生成的主键值的示例,并且本文描述的技术不限于生成主键值的任何特定方法。
复本
“复本”是切片的被存储的副本。根据一个实施例,每个切片具有至少两个复本。如上面所提到的,每个切片都有一个被指定为该切片的主复本的复本,以及一个或多个次级复本。从切片读取数据的请求可以由其持久存储装置具有该切片的复本的任何节点执行。然而,对切片执行DML操作(例如,插入、删除、更新)的请求仅由其持久存储装置具有该切片的主复本的节点执行。
主机
如本文所使用的,术语“主机”是指构成无共享节点的硬件组件。例如,主机可以是具有一个或多个处理器、本地易失性存储器和本地持久存储装置的计算机系统。主机的易失性存储器和持久存储装置是“本地的”,因为由主机向易失性存储器和持久存储装置发出的I/O命令不会通过主机间网络连接行进。如下文将更详细描述的,一个主机可以通过使用远程直接存储器访问(RDMA)操作通过主机间网络连接直接与另一个主机的易失性存储器或持久存储装置进行交互。
持久存储装置
如上面所提到的,每个主机都有本地持久存储装置,该主机托管的复本存储在其上。持久存储装置可以有多种形式,包括但不限于磁盘存储装置、NVRAM、NVDIMM、FLASH/NVMe存储装置等。此外,持久存储装置可以包括存储技术的组合,诸如NVRAM和磁盘存储装置,或者NVRAM和FLASH/NVMe。为了解释的目的,假设主机使用的持久存储装置是NVRAM。然而,本文描述的技术不限于任何持久存储技术。
引擎实例
如本文所使用的,术语“引擎实例”是指在主机内执行的、用于存储、操纵和检索以复本形式存储在该主机本地的持久存储装置上的数据的代码。单个主机可以执行任何数量的引擎实例。“引擎集群”,在本文也称为“数据库系统”,包括一个或多个引擎实例,这些引擎实例一起工作以服务来自客户端的数据库命令。下文更详细地描述引擎集群。
在一个实施例中,每个主机为主机托管其数据的每个数据库执行不同的引擎实例。例如,如果主机H1正在托管数据库D1中的表的复本和数据库D2中的表的复本,那么主机H1将执行一个引擎实例来访问属于数据库D1的复本,并执行第二个引擎实例来访问属于数据库D2的复本。
出于解释的目的,下文将给出涉及单个数据库的示例,其中每个主机正在执行单个引擎实例。然而,本文描述的技术不限于这种实施例。
数据库和表空间
数据库通常包括一组表和对应的支持结构(诸如索引)。数据库包括一个或多个表空间。根据实施例,每个表空间被指派给一个或多个主机。指派了表空间的(一个或多个)主机对驻留在该表空间中的表的复本进行存储。
例如,图1是图示包括六个主机H1、H2、H3、H4、H5和H6的数据库系统100的框图。在所示示例中,数据库系统100管理两个数据库D1和D2。数据库D1有两个表空间D1T1和D1T2,并且数据库D2有三个表空间D2T1、D2T2和D2T3。
表空间D1T1被指派给主机H1、H2、H3和H4。因此,表空间D1T1的“足迹(footprint)”跨越主机H1-H4,并且主机H1、H2、H3和H4中的每一个都托管表空间D1T1的“表空间成员”。类似地,表空间D1T2指派给主机H4、H5和H6。因此,主机H4、H5和H6各自托管D1T2的表空间成员。
表空间D2T1被指派给主机H1、H2和H3。这说明单个主机可以托管来自多个数据库的表空间成员(例如,H1托管来自数据库D1的D1T1表空间成员,以及来自数据库D2的D2T1表空间成员)。表空间D2T2被指派给主机H3和H4。表空间D2T3被指派给主机H5和H6。
基于这些指派,属于D2T2的表的复本将例如存储在主机H3和H4的持久存储装置中。类似地,属于表空间D1T2的表的复本将存储在主机H4、H5和H6的持久存储装置中。
在一些实施例中,数据库可以托管在可用主机的子集上。例如,数据库D1可能托管在主机H1-H4上。该数据库的表空间的主机被限制到该数据库的主机。因此,如果数据库D1限于主机H1-H4,那么表空间D1T1和D1T2将仅托管在主机H1-H4上。在这些情形下,驻留在表空间D1T2中的表的复本无法如图1中所示托管在H5或H6上。
示例数据库系统
参考图2,它是包括引擎实例的集群的数据库系统200的框图。图2中所示的数据库系统200包括五个主机(200A、202A、204A、206A、208A)。每个主机包括本地易失性存储器(200C、202C、204C、206C、208C)和本地持久存储装置(200D、202D、204D、206D、208D)。每个主机都在执行引擎实例(200B、202B、204B、206B、208B)。
引擎实例200B、202B、204B、206B、208B管理对存储由数据库系统200管理的数据库的数据的复本的访问。在所示实施例中,数据库包括单个表T,该表的行已被映射到五个切片(S1、S2、S3、S4和S5)。数据库存储切片S1、S2、S4和S5的两个复本,以及切片S3的三个复本。具体而言,切片S1的主复本(S1D1)托管在主机200A处。切片S1的次级复本(S1D2)托管在主机202A处。切片S2的主复本(S2D1)托管在主机204A处。切片S2的次级复本(S2D2)托管在主机200A处。切片S3的主复本(S3D1)托管在主机202A处。切片S3的次级复本(S3D2和S3D3)分别托管在主机208A和204A处。切片S4的主复本(S4D1)托管在主机208A处。切片S4的次级复本(S4D2)托管在主机206A处。切片S5的主复本(S5D1)托管在主机206A处。切片S5的次级复本(S5D2)托管在主机204A处。
因为主机200A-208A中的每一个作为无共享节点操作,所以主机上的引擎实例只能直接访问位于其本地持久存储装置中的复本。如上面所提到的,从切片读取数据的操作可以由该切片的任何复本本地的任何引擎实例执行。因此,从切片S2读取数据的请求可以被指引到引擎实例200B(其能够访问S2的次级复本)或引擎实例204B(其能够访问S2的主复本)。然而,DML操作仅在切片的主复本上执行。因此,对切片S2中的数据进行操作的任何DML操作都必须被指引到引擎实例204B,因为只有引擎实例204B能够访问切片S2的主复本。
切片到引擎实例映射
根据实施例,为了确保将数据库请求引导到适当的引擎实例,每个主机维护切片到引擎实例映射(slice-to-engine-instance map),该映射指示每个引擎实例正在托管的复本。例如,图2中所示的系统200的切片到引擎实例映射可以包含以下信息:
切片到引擎实例映射与行到切片映射结合使用,以便识别任何给定请求应当被引导到的主机。例如,响应向表T中插入新行的请求,接收该请求的引擎实例确定新行的主键,并使用行到切片映射来确定新行所属的表T的切片。为了解释的目的,假设新行属于切片S2。主机然后检查切片到引擎实例映射以确定切片S2的主复本被托管在主机204A上。如果接收到请求的引擎实例是引擎实例204B,则引擎实例204B执行插入到主复本S2D1中。如果接收到请求的主机不是引擎实例204B,那么接收到请求的引擎实例将请求发送到引擎实例204B。选择适当的引擎实例以协调任何给定数据库请求的执行的过程将在下文中更详细地描述。
在上面给出的示例中,所请求的操作是DML操作(插入)。因此,只有控制所讨论的主复本的引擎实例才能执行该操作。然而,如果操作只是简单地从切片S2读取数据,那么该操作可以由引擎实例204B(其具有S2的主复本)或者引擎实例200B(其具有S2的次级复本)执行。
复本的内容
如上面所提到的,复本存储表中的已映射到由该复本表示的切片的那些行。例如,假设切片S1是表T1(其主键是社会保险号(SSN))的切片。进一步假设表T1中主键落在000-00-0000至399-99-9999范围内的所有行都映射到切片S1。在这些情形下,S1的每个复本将存储表T1中主键落在000-00-0000至399-99-9999范围内的所有行。
在图2中所示的系统中,切片S1的复本驻留在主机200A(其具有主复本S1D1)和主机202A(其具有次级复本S1D2)上。因此,复本S1D1和S1D1二者都将存储表T1中主键落在000-00-0000至399-99-9999范围内的所有行。然而,根据一个实施例,为了支持基于快照的对数据的检索,复本存储比当前版本的行(这些行被映射到由复本表示的切片)更多的行。
参考图3,其图示了根据实施例的用于提高性能和支持版本控制的复本内的各种结构。具体而言,复本S1D1包括包含增量日志条目310和312的增量日志304,以及最初不包括条目的行堆302。复本S1D1还包括本地索引306,其包括索引320、322和324。复本S1D1中包含的每个结构,以及这些结构如何用于高效地访问存储在切片S1中的行的特定版本,将在下面被更详细地描述。
增量日志:临时存储或行数据
增量日志304和行堆302共同用于存储属于切片S1的行的各版本。增量日志304用作行数据的短期存储,而行堆302用作行数据的长期存储。对行所做的改变首先放置在增量日志304内的条目中,然后最终“应用”于行堆302以在行堆302中创建新条目。因此,增量日志304中的条目表示尚未反映在行堆302中的、对切片S1的行的改变。增量日志条目中表示的改变可以是已提交或未提交的。任何给定行的数据都可以分布在增量日志304中的条目和行堆302中的条目之间。
例如,假设切片S1最初是空的。此时,事务TX1可以将两行(R1和R2)插入到表T1中,其中这些行具有落入与切片S1相关联的范围内的主键。当执行TX1时,引擎实例200B(切片S1的主复本S1D1本地的引擎实例)将使得生成两个日志记录(每个新插入的行有一个)。这两个日志记录将被存储在增量日志304中。为了说明的目的,假设增量日志条目310是用于事务TX1作为行R1插入的数据的日志条目,而增量日志条目312是用于事务TX1作为行R2插入的数据的日志条目。
根据一个实施例,增量日志304被实现为用于临时存储增量日志条目的循环缓冲器。增量日志的循环性质在图7的增量日志714中示出。当在切片上执行DML操作时,新的日志条目被添加到该切片的主复本的增量日志中。此外,这些日志条目被传播到该切片的次级复本,在那里日志条目被添加到这些次级复本处的增量日志中。
增量日志中较旧的增量日志条目被“应用”于行堆,以便为要添加到增量日志的新条目腾出空间。如果做出反映在新行堆条目中的改变的事务已提交,那么该新行堆条目包括该事务的提交时间。否则,新的行堆条目包括该事务的事务ID。在一些情况下,新的行堆条目将包含“全行版本”。即,新的行堆条目将包括用于行的所有列的值,因为在对该行做出该行堆条目中所反映的改变时这些值是存在的。
在所应用的增量日志包含用于表的所有列的值的情况下,应用增量日志条目时所创建的行堆条目可以简单地从增量日志条目获得其列值。在应用的增量日志不包含用于表的所有列的值,并且新的行堆条目要包含全行版本的情况下,必须构造全行版本。为了构造行的全行版本,管理所讨论的复本的引擎实例将以下各项“缝合在一起”:(a)增量日志条目中的列值和(b)从用于该行的较旧行堆条目中获得的值。
不是创建全行版本,而是可以通过创建包含行的稀疏行版本的行堆条目来应用增量日志条目。行的稀疏行版本包含比该行的所有列值要少的内容。
如下文将更详细解释的那样,在新行堆条目为稀疏的情况下,读取操作所需的行的缺失值可以通过跟随指向同一行的前一个行堆条目的指针来获得。如果该前一个行堆条目也是稀疏的并且不包含所有需要的列值,那么重复跟随指向该行的前一个行堆条目的指针的过程,直到获得满足该读取操作所需的所有值为止。
日志记录
增量日志条目存储在增量日志304内的日志记录中。根据一个实施例,日志记录可以存储在事务片段的执行期间为切片生成的所有增量日志条目。因此,如果同一个事务片段将行R1和R2二者插入到切片S1中,那么对应的增量日志条目310和312二者都将被包含在同一个日志记录315中。当诸如日志记录315之类的日志记录包括多个增量日志条目时,直到日志记录中包含的所有增量日志条目都已应用于行堆302,该日志记录才会被解除分配(deallocated)。
为了解释的目的,在下面给出的示例中假设每个日志记录具有单个增量日志条目。然而,本文描述的技术不受限于可以包含在单个日志记录中的增量日志条目的数量。
行堆:行数据的长期存储
如上面所解释的,当增量日志条目“应用”于行堆时,创建行堆条目。一旦应用,增量日志条目就可以被解除分配,使得增量日志中被所应用的增量日志条目占用的空间可以被重新用于存储新的增量日志条目。对于任何给定的行,用于该行的增量日志条目和用于该行的行堆条目使用指针连接以形成链表。在链表内,条目按时间顺序排列以形成行的时间顺序条目链。下文将更详细地描述时间顺序条目链。
参考图8,它图示了根据实施例的行堆条目800的内容。行堆条目800包括事务信息806、对同一行的先前版本的引用808、堆条目具有值的列的指示符810以及这些列的值812。
事务信息806包括关于做出了包含在行堆条目中的改变的事务的信息。例如,在事务提交之前,事务信息806可以包括事务的事务ID。事务ID可以被用于在事务表中查找事务的状态。在事务提交和行堆条目800被清理之后,事务信息806可以包括事务的提交时间。
先前行引用808包含对另一个行堆条目的引用。先前行引用所指向的行堆条目是如下行堆条目:(a)与行堆条目800针对相同的表行,并且(b)包括紧接在做出行堆条目800中反映的改变之前所提交的该行的值。如果行堆条目800是所讨论的行的第一个行堆条目,那么先前行引用808将为空。如下文将描述的,由先前行引用创建的链接形成被称为行的时间顺序条目链的链表的一部分。
列编号信息810指示其数据存储在行堆条目800中的列的编号。如果行堆条目800是稀疏行条目(即,该条目包含比表的所有列少的列值),那么行堆条目800针对其具有数据的列可以使用位图来指示。例如,如果表T有四列,并且行堆条目800是针对表T的一行但是只有第一列和第四列的值,那么列编号字段810可以包括位图“1001”,第一位和第四位被设置以指示第一列和第四列的值包含在行堆条目800中。
数据列字段812包含列的实际值。如果行堆条目800是与行的初始插入对应的行堆条目,那么数据列字段812将包含所有列的值。如果行堆条目800与对已插入的行执行的后续DML操作对应,那么数据列字段812可以包含所有列的值(如果行堆条目800是全行版本)或列的子集的值(如果行堆条目800是稀疏行版本)。
其它元数据字段814包括与行堆条目800相关联的其它元数据。例如,其它元数据字段814可以包括各种标志,以及核实行堆条目没有被破坏的校验和。
行的时间顺序条目链
如上面所解释的,对行的最新改变可以包含在增量日志条目中,其中增量日志条目指向包含该行的较旧版本的行堆条目。然而,给定行不限于单个增量日志条目和/或单个行堆条目。更确切地说,同一行(例如,R1)可以有任何数量的增量日志条目和任何数量的行堆条目。
根据一个实施例,用于行的条目(增量日志条目和行堆条目)按时间顺序链接以形成该行的“时间顺序条目链”。行的时间顺序条目链的“尾部”包含对该行的最近改变,而行的时间顺序条目链的“头部”包含该行最旧的可用版本。
行的时间顺序条目链可以包括零个或更多个增量日志条目,后跟零个或更多个行堆条目。例如,如图4中所示,行R1的条目链中的条目包括:
·增量日志条目332,其包含在时间T100提交的对R1的改变
·增量日志条目334,其包含在时间T90提交的对R1的改变
·行堆条目342,其包含在提交时间T50对R1所做的改变,以及
·行堆条目346,其包含在提交时间T10最初插入的R1的所有值。
在这个示例中,行R1具有包括两个增量日志条目和两个行堆条目的时间顺序条目链。行R1的时间顺序条目链中的条目之间的指针在图4中示出,其中增量日志条目332(其具有对R1的最近的改变)位于R1的时间顺序条目链的尾部并且行堆条目346(其具有R1的最旧的可用数据)位于R1的时间顺序条目链的头部。
相比之下,图4中行R2的时间顺序条目链仅包含单个条目(行堆条目344)。因此,与行R2的主键相关联的散列表条目直接指向行堆条目344。
如下文将解释的,用于行的时间顺序条目链包括用于重构行的所有可用版本的数据。因此,系统能够提供截至任何指定的快照时间的行的数据,只要那个快照时间不比存储在该行的时间顺序条目链中的该行的最旧版本更旧即可。
散列表访问
根据一个实施例,每个引擎实例都维护按复本(per-duplica)的散列表,用于访问它能够访问的每个复本中的行。例如,引擎实例200B维护散列表350(图3和图4),用于访问复本S1D1中的行。根据一个实施例,用于行的散列表条目指向该行的时间顺序条目链的尾部。
为了使用散列表来访问行的时间顺序条目链,引擎实例将散列函数应用于该行的主键以产生与散列表350内的散列桶(hash bucket)对应的散列值。在这个散列桶内存储有具有这个主键的行的条目(如果该行的版本已存储在切片中)。用于行的散列表条目包括指向该行的时间顺序条目链的尾部的指针。
如果所讨论的行没有增量日志条目,那么该行的散列表条目将指向该行的最新行堆条目。因此,如果行R2仅存储在行堆条目344中,并且行R2没有增量日志条目,那么行R2的散列表条目将直接指向行堆条目344,如图4中所示。
另一方面,如果行具有一个或多个增量日志条目,那么该行的散列表条目将指向该行的最新增量日志条目。因此,在图4中所示的示例中,行R1的散列表条目指向增量日志条目332(R1的时间顺序条目链的尾部)。
散列表350可以以多种方式中的任何一种方式实现,并且本文描述的技术不限于任何特定的散列表实施方式。根据一个实施例,将散列函数应用于主键以生成散列值。散列值的位的第一子集被用于识别该主键落入的散列桶,并且散列值的位的第二子集被用作该散列桶的偏移量。然后将该主键的散列条目存储在该指定的散列桶内从该指定的偏移量开始的位置处。如果两个行的主键“冲突”(产生相同的桶和偏移量),那么可以使用多种冲突解决技术中的任何一种。本文描述的技术不限于任何特定的冲突解决技术。
根据替代实施例,第一组位(例如,位0-7)被用于识别桶,并且第二组位(例如,位8-15)与存储在桶中的“散列标签数组”中的每个标签进行比较。散列标签数组可以是例如由与每个散列桶条目相关联的主键产生的散列值的位8-15。SIMD操作可以被用于在单个操作中将所讨论的主键的位8-15与散列标签数组中的每个8位条目进行比较。SIMD操作的结果将指示桶中哪些散列表条目具有与所讨论的主键相同的位8-15。由于这个比较基于比整个主键的位更少的位,因此比较的结果可能产生假阳性。例如,该比较可能指示有三个散列条目的散列值的位8-15与所讨论的主键的散列值“匹配”。这些匹配的散列条目中至少有两个必然是假阳性,因为对于任何给定的主键,表最多只能有一个行。
为了确保“匹配的”散列表条目实际上是针对所讨论的主键,可以跟随散列表条目中的指针直到与散列表条目相关联的行的时间顺序条目链的尾部处的条目。时间顺序条目链尾部,无论是增量日志条目还是行堆条目,都将包括该行的整个主键。然后可以将该行的该主键与所讨论的主键进行比较,以确定该行的该主键是否实际上与所讨论的主键匹配,或者该匹配是否是假阳性。
将新行插入复本
当托管切片的主复本的引擎实例接收到将新行插入该切片的请求时,引擎实例为此改变生成增量条目,并将增量条目存储在切片的主复本的增量日志内的日志记录中。引擎实例然后在散列表350的适当桶中存储该行的散列表条目。该散列表条目指向该新的增量日志条目。
除了存储新行的散列表条目和增量日志条目外,引擎实例还将该日志条目传播到具有插入行的该切片的次级复本的主机。在这些主机中的每个主机内,新行的日志条目被存储在相应次级复本的增量日志中,并创建散列表条目以指向这些新存储的增量日志条目。因此,在该切片的每个复本上,新插入的行都以单个条目的时间顺序条目链开始。
从现有行中读取数据
如上面所提到的,读取操作可以由如下任何引擎实例执行,即,该引擎实例能够访问包含期望数据的切片的任何复本。另外,可以截至任何指定的快照时间执行读取操作,只要快照时间不早于该行的时间顺序条目链中该行的最旧版本即可。读取操作通过以下操作执行:
·确定要从中读取数据的切片
·使用切片到引擎实例映射,选择能够访问该切片的复本(可以是主复本或次级复本)的主机
·在所选择的主机处,使适当的引擎实例对要从中读取数据的行的主键执行散列操作,
·使用所得的散列值在散列表内定位适当的散列桶,
·在这个桶内定位所讨论的行的散列表条目,
·使用来自该散列表条目的指针来定位该行的时间顺序条目链的尾部,以及
·从属于该行的条目链的条目中读取期望数据
在一些情况下,行的散列表条目指向的条目将不包含对行所请求的操作所需的所有数据。例如,该操作可能要求来自R1的列c1和c2的值,而增量日志条目332可能仅具有列c1的值。作为另一个示例,该操作可以要求截至特定的快照时间(例如,T50)的来自R1的c1的值。然而,增量日志条目322中包含的c1的值可能是与提交时间T100相关联的。因此,读取操作要求比增量日志322中所包含的版本更旧的c1版本。
每个条目中存储的提交时间指示条目中的数据所属的快照。如果尚未对条目执行清理,那么该条目将包含事务ID而不是提交时间。在这些情形下,执行读取的引擎实例可以使用事务ID在事务表中查找事务的状态。如果事务已被提交,那么事务表中指定的该事务的提交时间是包括该事务ID的条目的提交时间。如果事务仍处于活动状态,那么该条目被跳过,因为未提交的改变不能被提供给任何读取操作。如果事务未提交并且处于非活动状态,那么可以要求额外的工作来确定读取操作是否应当看到条目中的改变,这将在下文中更详细地描述。
当行的散列表条目指向的条目不具有指定的读取操作所需的行的所有数据时,引擎实例遍历该行的时间顺序条目链的条目之间的链接直到获得所有需要的数据。在R1的情况下,这可以要求从增量日志条目332到增量日志条目334,到行堆条目342,再到行堆条目346。
引擎实例并不需要总是跟随行的时间顺序条目链一直到时间顺序条目链的头部以获得读取操作所需的数据。例如,读取操作所需的数据可能在仅读取时间顺序条目链中条目的子集之后获得。因此,如果请求是要读取R1的c1的最新版本,那么可以直接从增量日志条目332中获得它,而无需遍历R1的时间顺序条目链中的任何附加链接。
根据一个实施例,所有读取操作都是在没有获得任何锁的情况下执行的。因此,读取不会阻塞写入操作或其它读取操作,并且写入操作也不会阻塞读取操作。只要复本(主复本或次级复本)中行的条目链具有截至读取操作的快照时间提交的数据,执行读取操作的引擎实例就可以在不获得锁的情况下并且在不阻塞对同一行的任何并发写入或读取的情况下从复本中行的条目链中的条目获得它所需的数据。
用于主键列的本地索引
如图3中所示,复本可以存储任何数量的本地索引306。在图3中所示的实施例中,复本S1D1包括本地索引320、322和324。本地索引306可以以多种方式实现。为了解释的目的,假设本地索引306是使用B树结构实现的。然而,本文描述的技术不限于使用任何特定索引结构来实现本地索引306。
本地索引可以建立在表的主键上。这种索引对于点查找(例如,基于行的主键查找单个行)一般而言是不必要的,因为这是散列表的目的。然而,建立在主键上的本地索引可以是有用的,例如,促进范围扫描。例如,如果请求是针对社会保险号在555-55-5555和555-55-9999范围内的人的姓名,那么可以遍历B树索引以找到与等于或大于“555-55-5555”的第一个主键相关联的索引条目。第一个匹配的主键可以从这个条目中获得。从这个索引条目开始,可以跟随叶节点到叶节点的链表,从每个被如此访问的索引条目中获得主键,直到遇到主键大于555-55-9999的索引条目。这样获得的主键可以被用来索引到散列表中,以从主键落在该指定范围内的行的时间顺序条目链中获得数据。
根据一个实施例,当在主键上建立本地索引以便促进范围扫描时,不是包括整个主键,而是叶节点索引条目可以简单地包括指向与行相关联的散列表条目的指针。在这种实施例中,引擎实例直接根据该索引条目中的指针定位散列表条目,而不是必须将散列函数应用于主键以获得散列值然后在与该散列值相关联的散列桶中查找散列表条目。
根据替代实施例,建立在主键上的索引的叶节点中的条目包括根据与该索引条目对应的行的主键产生的散列值。基于从索引条目获得的散列值,基于范围的扫描操作可以在散列表中定位合适的桶。然后可以检查这个桶中的散列表条目以识别具有落入为扫描指定的范围内的主键的任何散列表条目。这些条目中的指针(如果存在任何此类条目)指向行的时间顺序条目链的尾部,该行具有满足如下条件的主键:(a)散列到这个散列表桶并且(b)落入为扫描指定的范围。
删除时的推迟的索引维护
如上面所提到的,可以在主键上建立本地索引,以促进基于主键的范围扫描。在正常情形下,必须响应于影响切片所关联的索引中的行的DML操作来更新这种本地索引。例如,如果插入主键为PK7的新行,那么针对这个主键PK7的条目将必须(a)被添加到散列表,以及(b)被插入索引内的适当位置。类似地,如果删除具有主键PK9的行,那么(a)删除与主键PK9相关联的散列表条目,以及(b)删除与主键PK9相关联的索引条目。
根据一个实施例,为了提高删除行的DML操作的性能,对应的索引条目的删除被推迟。因此,删除与PK9相关联的行将导致删除PK9的散列表条目,但不会删除PK9的索引条目。
因为散列表条目被删除,所以系统将不会用已删除数据来对读取请求进行响应,即使针对已删除行的条目仍保留在索引中。例如,假设在删除与PK9相关联的行之后,系统接收从主键落在PK1-PK10范围内的行读取数据的请求。响应于该请求,系统可以使用建立在主键上的本地索引来确定范围PK1-PK10所映射到的切片具有与主键PK4、PK9和PK10相关联的行。
基于这个信息,扫描操作将使用散列表来为具有主键PK4、PK9和PK10的行查找时间顺序条目链。当扫描操作尝试查找PK9的散列表条目时,它将无法找到该散列表条目,因为PK9的散列表条目已被删除。基于缺少PK9的散列表条目,扫描操作将跳过PK9并且仅返回来自与PK4和PK10相关联的行的数据。
用于非主键列的本地索引
本地索引可以被用于基于主键列以外的列中的值来定位行。例如,对于表T,主键列可以是社会保险号,但查询可能询问所有名字(firstname)为“Amy”的人的年龄。为了找到满足涉及“名字”列的谓词的行,可以基于来自“名字”列的值来构建索引320。然后可以基于名字“Amy”遍历索引320以找到具有“Amy”的条目的叶节点。
根据一个实施例,不是包含指向具有名“Amy”的(一个或多个)行的(一个或多个)指针,而是索引320内针对“Amy”的索引条目包括具有名“Amy”的每个行的主键。在获得具有名字“Amy”的行的主键之后,引擎实例对主键进行散列以在散列表350中找到对应的条目,并跟随这些条目中的指针以从这些行的对应条目链中获得数据。
参考图7,它是图示建立在非主键列上的次级索引706可以如何基于值被遍历以找到在非主键列中具有该值的行的主键的框图。出于说明的目的,假设次级索引706建立在“名字”列上,请求是针对名字为“Amy”的行,并且行R1是包括名字“Amy”的行。
在这些情形下,基于键值“Amy”遍历次级索引706以定位与键值“Amy”相关联的索引条目708。该索引条目包括行R1的主键。然后使用行R1的该主键查找这个主键的散列表条目。该散列表条目指向行R1的时间顺序条目链的尾部。在图7中所示的示例中,行R1的时间顺序条目链仅包括一个条目,该条目是行堆702中的行堆条目。
与行R1的时间顺序条目链形成对比,图7中行R2的时间顺序条目链在增量日志714中包括一个增量日志条目并且在行堆702中包括一个行堆条目。因此,行R2的散列表条目指向行R2的增量日志条目,该增量日志条目继而指向行R2的行堆条目。
全局次级索引
当为非主列(诸如“名字”)维护本地索引时,必须为每个切片维护这种本地索引,并且该切片的本地索引必须位于该切片的每个复本上。这是因为不可能知道哪个或哪些切片具有名字为“Amy”的行。因此,对于每个切片,必须搜索其相应的本地“名字”索引以确定这个切片是否具有名字为“Amy”的任何行。
作为为非主列维护每切片(per-slice)本地索引的替代方案,可以为此类列维护单个“全局”索引。这种全局索引与本地索引相似,但全局索引将包含用于表中所有行的条目,而不管它们属于哪些切片。因此,在这种索引中与“Amy”相关联的索引条目将包括表中“名字”值为“Amy”的所有行的主键。然后可以结合范围到切片映射来使用这些主键来识别每个行检索请求应当指向的切片。然后可以将读取请求发送到管理这些切片的复本的主机。
在现有行上执行DML
对现有行(在复本中已经具有时间顺序条目链的行)执行DML操作的事务通过以下操作执行:
·创建新的日志条目,其包括对行的该改变,
·将新日志条目存储在包含该行的切片的主复本的增量日志中,
·将新的日志条目传播到具有该切片的次级复本的主机,
·使新的日志条目指向该行的时间顺序条目链的前一个尾部,
以及
·使该行的散列表条目指向新添加的条目(其是该行的时间顺序条目链的新尾部)
例如,假设行R1的时间顺序条目链包括四个条目,如图4中所示。响应于对行R1执行改变的DML操作,该DML操作所做的改变被存储在新的增量日志条目500中(图5中所示)。新的增量日志条目500指向增量日志条目332,增量日志条目332是行R1的时间顺序条目链的前一个尾部。然后更新行R1的散列表条目以指向新的增量日志条目500,如图5中所示。
将增量日志应用于行堆
如上面所提到的,当一行最初被添加到复本时,该行通常被添加为增量日志条目。然而,增量日志304充当的是行数据的临时存储,行数据最终应当被应用于行堆302。在一个实施例中,后台进程周期性地将增量日志条目应用于行堆302。
例如,假设增量日志304具有用于新插入的行R3的增量日志条目。此时,R3的时间顺序条目链仅包含该一个增量日志条目(R3的散列表条目指向该条目)。为了将R3的增量日志条目应用于行堆302,包含R3的该增量日志条目的内容的行堆条目被存储在行堆302中。R3的散列表条目被更新以指向该新的行堆条目,并且该增量日志条目可以被垃圾收集/重新使用。
当一行的时间顺序条目链包括一个或多个行堆条目时,该行的最旧的增量日志条目(或多个条目)必须在该行的任何较新的增量日志条目之前被应用。例如,参考图5,增量日志条目334必须在应用增量日志条目332和500之前被应用。在这些情形下,将增量日志条目应用于行堆涉及:
·创建新的行堆条目,其具有正被应用的增量日志条目的内容,
以及
·修补行的时间顺序条目链中的指针,以便:
○所应用的增量日志条目从时间顺序条目链中被移除,以及
○在与所应用的增量日志条目先前占据的相同位置处,新的行堆条目被插入到行的时间顺序条目链中
例如,参考图5,在行R1的时间顺序条目链中,增量日志条目334在增量日志条目332之后和行堆条目342之前。为了将增量日志条目334应用于行堆302,创建新的行堆条目(例如,行堆条目348)。行堆条目348至少填充有增量日志334的内容。这样做可以创建稀疏行堆条目(该行堆条目包括少于截至与行堆条目相关联的提交时间的行的所有值)。为了创建完全填充的行堆条目,可以通过合并行R1的所有值来进一步填充行堆条目348,因为这些值在创建增量日志条目334时存在。这可以通过从位于行R1的时间顺序条目链中更远的行堆条目(例如,行堆条目342和346)中获得缺失值来实现。
在创建和填充新的行堆条目348之后,R1的时间顺序条目链的指针被更新,使得新的行堆条目348替换R1的时间顺序条目链中被应用的增量日志条目304。在本示例中,更新指针包括使增量日志条目332指向新的行堆条目348,并使行堆条目348指向行堆条目342。在图6中说明了这些改变。在这些指针改变已经完成之后,增量日志条目334不再是行R1的时间顺序条目链的一部分,并且增量日志条目334占用的空间可以被释放/重新使用。
传播DML操作所做的改变
如前面所提到的,影响切片中的数据的所有DML操作都是针对切片的主复本进行的。然而,为了使次级复本可用于读取操作,必须将在主复本处所做的改变传播到次级复本。根据一个实施例,通过向正托管次级复本的主机发送包含关于这些改变的信息的日志记录,来将对切片的主复本所做的改变传播到次级复本。
例如,返回到图2,以切片S1中的数据为目标的DML操作将由引擎实例200B(其托管S1D1,S1的主复本)执行。在主复本(S1D1)中,可以通过以下操作来做出改变:(a)为该改变生成日志记录,以及(b)将该改变的该日志记录作为增量日志条目存储在主复本(S1D1)的增量日志中。然后该日志记录从主机200A传播到主机202A(其托管S1D2,S1的次级复本)。
对切片所做的改变被传播到该切片的所有次级复本。因此,对切片S3所做的改变将在主机202A上的主复本S3D1处进行,并传播到主机204A(其具有次级复本S3D3)和主机208A(其具有次级复本S3D2)。
日志记录的内容
根据一个实施例,被传播到切片的次级复本的日志记录的内容与存储在切片的主复本中的、用于该改变的增量日志记录的内容相似。具体而言,根据一个实施例,作为增量日志记录存储在切片的主复本处并传播到该切片的次级复本的日志记录的内容包括:
·执行了日志记录中所反映的改变的事务的事务ID
·受DML操作影响的行的主键
·该DML操作所做的改变(例如,更新后的(一个或多个)
列值)
·在事务内哪个语句指定了该DML操作的指示
·该DML操作的类型的指示(例如,插入、更新、删除等)
·日志记录是否是该语句的最后一个日志记录的指示(last-
log-of-statement标志)
对于在事务内哪个语句指定了DML操作的指示可以通过以下操作来做出:(a)为每个语句指派编号,以及(b)在执行语句时生成的每个日志记录中包括该语句的编号。例如,如果事务TX1具有三个语句ST1、ST2和ST3,那么可以为这三个语句指派相应的编号1、2和3。为语句ST1所做的改变生成的所有日志记录将包括语句编号1,而为语句ST2所做的改变生成的所有日志记录将包括语句编号2。在语句(诸如语句ST2)使得生成多个日志记录的情况下,最后一个日志记录将包含last-log-of-statement标志,以指示它是语句ST2的最后一个日志记录。如下文将更详细描述的那样,语句编号和last-log-of-statement标志被用于确保在事务提交或故障转移到次级复本的主机时次级复本已接收到该事务的所有日志记录。
日志记录中的事务ID可以被用于确定做出反映在日志记录中的改变的事务的状态。例如,参考图7,假设行R2的增量日志条目包括事务ID TX2。这个事务ID可以被用于在事务表710中查找事务TX2的事务表条目712。事务表条目712包含关于事务TX2的状态的信息。例如,事务可以指示事务TX2是否正在执行、准备、提交或已提交。如果已提交,那么事务表条目712将指示事务TX2的提交时间。
条目的清理
当事务提交时,与该事务所做的改变对应的增量日志条目和/或行堆条目可以被更新以包括该事务的提交时间。通过将提交时间放在条目本身当中,可以避免在事务表中查找该事务的需要。更新与已提交事务相关联的条目以反映事务的提交时间的过程被称为“清理(cleanout)”。例如,可以通过将条目中的事务ID替换为事务的提交时间来执行清理。
对于尚未被清理但与已提交的事务对应的条目,包含在该条目中的数据的版本通过在事务表710中查找该事务以确定事务的提交时间来确定。
一旦对条目执行了清理操作,存储在条目中的提交时间就用于指示相关联的条目所属的行的“版本”。因此可以确定已清理的条目的版本而不必使用事务表710来查找做出反映在条目中的改变的事务的状态。
由事务生成的日志的清理不需要在事务提交时执行。更确切地说,清理可以例如由后台进程周期性地执行。
日志记录的半同步传播
如上面所提到的,当DML操作对切片中的数据做出改变时,通过生成反映该改变的日志记录、将该日志记录存储在切片的主复本的增量日志中并将该日志记录传播到该切片的次级复本来做出此改变。然而,根据一个实施例,通过“半同步地(semi-synchronously)”执行日志记录到次级复本的传播来改进DML操作的性能。
将日志记录传播到次级复本是半同步的,这在于对针对改变的日志记录进行传播的引擎实例向请求了该改变的客户端报告该改变成功了,而无需等到接收到针对该改变的该日志记录已被成功传播到次级复本的确认。例如,假设客户端请求插入一行,其中该行的主键落在被映射到切片S3的范围内。在这些情形下,该插入请求由主机202A上的引擎实例202B执行,主机202A托管切片S3的主复本(S3D1)。在该请求的执行期间,引擎实例202B将增量日志条目插入到S3D1的增量日志中,并发起将该日志条目传播到引擎实例208B(其托管切片S3的次级复本S3D2)和引擎实例204B(其托管切片S3的次级复本S3D3)。在发起日志条目的传播之后,但在接收到次级复本接收到该日志条目的确认之前,引擎实例202B就向客户端报告做出该改变的语句已被成功执行。因为在接收到日志记录已在次级复本处被接收的确认之前就报告语句成功完成,所以主复本和次级复本处的改变并不是完全同步的。
根据一个实施例,客户端处的驱动程序跟踪事务的哪些语句已被报告为成功执行。如下文将更详细描述的,如果事务故障转移到不同的主机,那么客户端维护的“最后成功执行的语句”信息被用于恢复该事务(不必完全重新启动它)。引擎实例202B在通知客户端语句已执行之前不等待来自次级复本的确认这一事实可以导致显著的性能改进,因为DML操作的执行不会招致与确认相关的延迟。
根据一个实施例,在以下时刻,做出语句中指定的改变的引擎实例向客户端报告该语句已成功执行:
·改变的日志记录被存储在主复本的增量日志中,以及
·(一个或多个)日志记录已放置“在线上”以供传输到(一个或多个)次级复本
在这种上下文中,“在线上”是指日志记录已被传送到做出了改变的引擎实例的故障域(failure domain)以外的故障域的情境。因为引擎实例一直等到日志记录在线上,所以在主复本和次级复本处所做的改变也不是完全异步的。因此,术语“半同步”被用于指日志记录从主复本到次级复本的传播。
在本示例中,假设主机202A具有网络接口卡(NIC),该网络接口卡(NIC)将主机202A连接到主机204A和208A所连接到的网络。在这些条件下,引擎实例202B可以在NIC确认接收到与语句相关联的日志记录时报告该语句已针对切片S3成功执行。NIC可以在实际发送包含日志记录的分组之前发送此确认,只要日志记录存储在与NIC相关联的存储器(与引擎实例在其中运行的存储器相反)中即可。因此,在NIC确认时,包含日志记录的分组可能尚未被发送到次级复本的主机。在这个示例中,NIC构成了单独的故障域,因为在NIC已确认接收之后,即使引擎实例202B随后发生故障或挂起,日志记录从NIC到主机204A和208A的传播也会成功。
冗余连接的主机
如上面所解释的,NIC和引擎实例属于不同的故障域。因此,即使生成日志记录的引擎实例发生故障或挂起,日志记录也将由NIC成功传播到次级复本。然而,双重故障(主复本的引擎实例的故障,以及NIC/网络的故障)仍然有可能导致改变没有被传播到次级复本的情况,即使客户端已经被告知对应的语句成功了。
因此,为了降低次级复本将无法接收到改变的可能性,系统中的每个主机可以通过多个冗余的网络连接到每个其他主机。例如,如图2中所示,主机202A可以通过两个不同的网络(网络1、网络2)连接到主机204A,每个网络在主机202A中具有其相应的NIC(NIC1、NIC2)。在这些情形下,引擎实例202B可以并发地通过两个NIC/网络向主机204A发送对切片S3的改变的日志记录。因此,只有当两个NIC/网络都发生故障(这是极不可能的事件)时,日志记录才会无法到达主机204A。
虽然未在图2中示出,但是两个网络(网络1、网络2)中的每一个都可以将每个主机与每个其他主机连接。在这些情形下,主机之间的任何通信只有在两个网络都出现故障时才会失败。另外,可以根据需要而增加每个主机之间的网络的数量以确保通信的成功。例如,在一个实施例中,每个主机通过至少三个不同的网络连接到每个其他主机。
行堆条目的垃圾收集
如上面所解释的,随着对行执行DML操作,该行的时间顺序条目链增长,其中每个DML操作将新条目添加到行的时间顺序条目链的尾部。同样如上面所解释的,通过为该行创建新的行堆条目,可以将该行的最旧增量日志条目应用于行堆,从而允许回收增量日志条目占用的空间。然而,如果允许每行的时间顺序条目链无限增长,那么主机最终将耗尽持久存储空间。
因此,根据一个实施例,系统周期性地回收位于行的时间顺序条目链的头部的行堆条目所占用的空间。位于行的时间顺序条目链的头部的行堆条目在本文中被称为“头条目”。头条目包含行的最旧可用版本。例如,当与头条目相关联的时间戳比指定的阈值年龄更旧时,可以回收头条目所占用的空间。例如,假设系统的指定保留时间为三天。在这些情形下,系统能够处置与最多三天的快照时间相关联的读取请求。如果特定行的头条目的提交时间戳超过三天,那么系统可以解除该头条目的分配并重新使用其存储空间。
当解除行的头条目的分配时,可能必需重写该头条目之前的行堆条目。位于行的头条目之前的行堆条目被称为该行的“倒数第二个条目(penultimate entry)”。倒数第二个条目可能需要被重写,例如,当倒数第二个条目是稀疏条目时。
例如,假设行R1具有五个列c1、c2、c3、c4和c5。进一步假设行R1的头条目是全行版本,它具有截至时间T10的所有五个列的值。最后,假设行R1的倒数第二个条目是稀疏行堆条目,其仅具有截至时间T50的c1和c2的值。
在这些情形下,解除对R1的头条目的分配而不进行任何附加的改变将导致问题。具体而言,在这种解除分配之后,如果系统接收到读取截至时间T50的行R1的请求,那么截至时间T50的c3、c4和c5的值将不再可用。
根据一个实施例,当解除具有稀疏的倒数第二个条目的行的头条目的分配时,系统创建该行的新的全行版本,该新的全行版本反映倒数第二个条目的快照时间。例如,在行R1的倒数第二个条目是时间戳为T50的稀疏条目的情况下,系统为R1创建截至时间T50的全行版本。R1的此全行版本替换R1的该稀疏的倒数第二个版本。因此,R1的时间顺序条目链的指针被修订为:
·从行的时间顺序条目链中移除头条目和倒数第二个条目二者,
以及
·将该新的全行版本添加到行的时间顺序条目链的头部
在新的全行条目被添加到该行的时间顺序条目链的头部之后,旧的头条目和旧的倒数第二个条目所占用的空间可以被释放和重新使用。
协调器选择
再次参考图2,当客户端请求执行事务时,系统200选择用来协调该事务的引擎实例。根据一个实施例,系统基于事务所针对的切片来选择协调事务。在事务仅对来自单个切片的数据进行操作的简单情况下,这个切片被指定为针对该事务的“控制切片”,并且管理该切片的主复本的引擎实例被选为用于该事务的协调引擎实例。因此,在图2中所示的系统中,仅对来自切片S3的数据进行操作的事务将由管理切片S3的主复本S3D1的引擎实例202B来协调。
在事务对来自多于一个切片的数据进行操作的情况下,系统从该事务所操作的这些切片当中选择控制切片。例如,假设事务对来自切片S1的数据和来自切片S2的数据进行操作。在这种情况下,系统将选择切片S1或者S2作为控制切片。如果选择切片S1,那么管理切片S1的主复本S1D1的引擎实例200B被指定为该事务的协调器。如果选择切片S2,那么管理切片S2的主复本S2D1的引擎实例204B被指定为该事务的协调器。
当事务对来自多个切片的数据进行操作时,可以使用各种技术来选择控制切片。例如,如果事务对切片S1和S2进行操作,但在切片S1上比在切片S2上做更多的工作,那么切片S1可以被选为控制切片。在不可能从事务本身确定将要被改变的(一个或多个)切片的情况下,从客户端接收了请求的引擎实例可以简单地选择它为其管理主复本的任何切片作为控制切片,然后承担作为该事务的协调引擎实例的角色。因此,有可能出现事务的控制切片不是该事务所触及的切片之一的情况。
可替代地,当事务在多个切片上操作时,可以基于相应主机的当前工作负载来选择控制切片。例如,如果主机200A被大量使用而主机204A相对空闲,那么可以选择切片S2作为协调切片,使得事务可以由不太繁忙的主机204A上的引擎实例204B来协调。还有其它实施例在选择事务的控制切片时可以考虑多种因素,包括但不限于哪个主机从客户端接收请求、当前主机工作负载、以及事务在每个切片上必须执行的工作负载。
在一些实施例中,客户端包含用于选择向其发送事务的主机的逻辑。客户端可以基于上述因素(例如,事务对其操作的(一个或多个)主键以及哪些主机管理这些主键所映射到的切片的主复本)来做出主机选择。在这种实施例中,客户端可以维护拓扑高速缓存,该拓扑高速缓存指示主键与管理主键映射到的切片的主复本的主机之间的映射。在客户端选择主机的实施例中,在选择主机之后:
·客户端连接到该主机,
·其主复本驻留在该主机上的切片被选为控制切片(这基于事务中涉及的(一个或多个)主键),以及
·管理该主复本的引擎实例充当此事务的协调器。
在替代实施例中,用于选择控制切片的逻辑位于每个主机上。在这种实施例中,客户端向其发送事务的主机可以选择其主复本驻留在不同主机上的控制切片。在这种情况下,事务和协调该事务的责任可以被转发给该其它主机。可替代地,最初从客户端接收了事务的主机可以向客户端发回消息,该消息告诉客户端将该事务发送到不同主机(即,管理切片(该切片被接收到请求的主机选择作为控制切片)的主复本的主机)。
客户端辅助的故障转移
当正在协调事务的引擎实例因任何原因发生故障或停止工作时,该事务将成为“故障转移事务(failover transaction)”,并且选择新的协调器来恢复该故障转移事务。根据一个实施例,新的协调器是从管理控制切片的次级复本的引擎实例当中选择的。
除了选择新的协调器之外,所有其余的主机都将它们的逻辑时钟设置为max(当前时钟值,由发生故障的主机生成的最高时间戳)。下文将描述用于确定发生故障的主机所生成的最高时间戳的技术。
关于为故障转移事务选择新的协调器,如果切片S3是事务的控制切片,那么引擎实例202B最初将被指定为该事务的协调器(因为引擎实例202B管理切片S3的主复本(S3D1))。如果引擎实例202B停止运行,那么系统为事务选择新的协调器。在这种情况下,用于协调事务的候选者是引擎实例204B(其管理对控制切片S3的一个次级复本S3D3的访问)和引擎实例208B(其管理对控制切片S3的另一个次级复本S3D2的访问)。当控制切片有多个次级复本时,可以基于各种因素(诸如相应主机的繁忙程度以及哪个主机具有该事务的最多日志记录)选择新的协调器。
根据一个实施例,如果用于成为事务的新协调器的候选者对于该事务不具有相同数量的日志记录,那么选择具有最大数量的事务日志记录的候选者。例如,假设引擎实例208B比引擎实例204B具有针对该故障转移事务的更多日志记录。在这些情形下,引擎实例208B将被选为该故障转移事务的新协调器。
在新协调器处恢复执行事务之前,将其它候选者处缺失的任何事务日志记录从新协调器发送到这些其它候选者。在本示例中,引擎实例208B将来自故障转移事务的在由引擎实例204B管理的次级复本中缺失的任何事务记录发送到引擎实例204B。事务日志记录以及它们在故障转移期间如何被使用将在下文中更详细地描述。
一旦选择了新的协调引擎实例,由新的协调引擎管理的控制切片的次级复本就成为控制切片的新的主复本。例如,如果引擎实例208B被选为其控制切片是S3的事务的新协调进程,那么次级复本S3D2被指定为切片S3的新主复本。此外,客户端向引擎实例208B发送信息以允许引擎实例208B恢复由现在发生故障的引擎实例202B开始的事务。
为了使引擎实例208B能够恢复事务,客户端向主机208A发送关于事务的信息以及由先前协调器确认的最后改变的指示。例如,在发生故障之前,引擎实例202B已经向客户端发送了一系列与事务的状态相关的消息。每个消息可以确认语句已成功执行。因此,客户端将已经存储有在故障之前其执行被引擎实例202A确认的最高语句编号。
当引擎实例202B发生故障时,客户端向新的协调器(引擎实例208B)发送恢复事务的请求,连同已被先前协调器(引擎实例202B)确认执行了的最高语句编号。新协调器(引擎实例208B)然后在与从客户端接收到的语句编号相关联的语句之后的语句处恢复执行事务。
例如,假设事务TX1有十个语句(ST1至ST10),并且切片S3被选为该事务的控制切片。在这些情形下,引擎实例202B(管理切片S3的主复本)被选为事务的协调器。在执行事务时,引擎实例202B成功执行语句ST1至ST4,每次成功执行一语句时向客户端发送确认消息。在故障转移之后,次级复本S3D2被指定为主复本,并且引擎实例208B成为该事务的新协调器。客户端向引擎实例208B通知ST4是被成功执行的最后一个语句,因此新协调器(引擎实例208B)在语句ST5处恢复事务的执行。
使用日志记录的半同步传播的故障转移
如上面所提到的,改变可以被半同步地传播到次级复本。即,协调器可以在次级复本的主机确认接收到语句所做的改变之前向客户端指示该语句已经在切片的主复本上成功地执行。
在使用日志记录的半同步传播的实施例中,协调器可以在将改变推送到不同的故障域(诸如获得日志已被本地NIC接收的本地NIC的确认)之后向客户端发送确认。然而,即使在这些情形下次级复本不会接收到日志记录的可能性极小,但仍是有可能的。因此,在上面给出的示例中,事务的语句ST4所做的改变可能没有被传播到次级复本S3D2和S3D3。
因此,根据一个实施例,在故障转移之后,在新协调器恢复事务之前,新协调器确认其复本具有直到最后确认的语句并包括该语句的所有语句的日志记录。在本示例中,引擎实例208B在核实复本S3D2包括事务的所有日志记录直至并包括语句ST4的日志记录(包括包含用于ST4的语句结束(end-of-statement)标志的日志记录)之前不恢复语句ST5处的事务的执行。在缺失任何日志记录的情况下,新协调器将中止事务,该事务然后可以从头开始重新执行。在所有日志记录都存在的情况下,新协调器在下一语句(ST5)处恢复事务。
主机故障时调整时钟
如上面所提到的,当主机发生故障时,所有其余主机将其逻辑时钟设置为max(当前时钟值,由发生故障的主机生成的最高时间戳)。然而,确定由发生故障的主机生成的最高时间戳并不容易。因此,使用一种租赁技术(leasing technique),以便非故障节点始终可以知道至少与发生故障的主机生成的最高时间戳一样高的时间戳。
根据该租赁技术,“最大时钟值”被传送到系统中的所有主机。租约授予主机生成上至该最大时钟值的时间戳的许可。每当系统中任何主机的逻辑时钟达到最大时钟值时,该主机就必须请求附加的“租约”。在接收到新的租约请求后,选择新的最大时钟值,并通过传送该新的最大时钟值来授予该新的租约。
在使用这种租赁技术的系统中,保证了系统中的任何主机都不会看到比由租赁机制授予的当前最大时钟值更大的时间戳值。因此,当一主机停止运转(die)时,系统中的所有主机都可以将它们的时钟设置为当前最大时钟值,以保证它们的时钟至少与由发生故障的主机节点生成的任何时间戳一样高。当主机故障之后以这种方式调整时钟时,新的最大时钟值被选择,并且其余主机被授予租约以生成上至新的最大时钟值的时间戳。
确定性的响应时间
根据一个实施例,系统在指定的最大时间内响应所有命令。当事务的执行会超过指定的最大时间时,协调事务的引擎实例将事务的已经被执行的语句的结果连同恢复令牌返回给客户端。恢复令牌包含引擎实例恢复该事务所需的信息,诸如最后执行的语句的编号。
在接收到中间结果和恢复令牌后,客户端可以连同恢复令牌一起重新提交该事务。指派给重新提交的事务的协调引擎实例基于恢复令牌的内容在适当的语句处恢复事务的执行。以这种方式使用恢复令牌不仅允许有保证的响应时间,而且还允许主机在很大程度上忘记在恢复令牌发送到客户端的时间与客户端重新发送事务的时间之间的事务的状态(并因此释放资源)。
为了避免超过时间阈值,引擎实例有可能必须在语句中间(mid-statement)停止处理命令。例如,命令可以请求扫描整个表。在这些情形下,有可能在达到时间阈值时只部分地扫描了表。如果部分执行了的扫描是以基于主键的次序执行的,那么恢复令牌可以包括最后扫描的行的主键。因此,当操作恢复时,扫描可以针对下一行来恢复。类似地,如果扫描是按照存在次级索引的另一个列来排序的,那么恢复令牌可以指示来自被索引的该列的最后被扫描的值。当操作恢复时,该列上的次级索引可以被用于在包含来自被索引的该列的下一个值的行处恢复扫描。
多切片语句
单个语句可以涉及多个切片。例如,语句可以请求扫描表T,该表T被划分为五个切片S1-S5,这些切片的复本存储在图2中所示的系统中。如上面所提到的,当事务在多个切片上操作时,系统选择控制切片,并且管理该控制切片的主复本的引擎实例对事务进行协调。
在表扫描操作的情况下,对给定切片的扫描可以由管理该切片的任何复本的任何引擎实例执行。根据一个实施例,协调事务的引擎实例以最大化主机之间的并行化和工作负载平衡的方式在其它主机之间分配工作。例如,如果选择引擎实例202B来协调表T1的完整扫描,那么引擎实例202B可以扫描S1D2,并指派引擎实例200B扫描S2D2、指派引擎实例204B扫描S3D3、指派引擎实例208B扫描S4D1,并指派引擎实例206B扫描S5D1。这些扫描操作可以并行执行,结果被返回到协调引擎实例202B。协调引擎实例202B然后将结果发送回请求了该表扫描的客户端。
在引擎实例内对访问多个切片的语句的工作进行协调的逻辑在本文中被称为语句协调器。根据一个实施例,语句协调器将语句所需的工作分解成语句片段,其中每个语句片段指定要由不同引擎实例完成的工作。然后将这些语句片段发送到它们相应的引擎实例,以使这些引擎实例执行语句片段中指定的工作。因此,在本示例中,引擎实例202B的语句协调器为要求对表T进行完整扫描的语句创建五个语句片段,并将这些语句片段发送到适当的引擎实例以使得表扫描被并行执行。
事务
如上面所提到的,由系统200执行的数据库操作常常作为事务的一部分被执行。事务是必须以原子方式执行的工作的单元。因此,如果系统200已经执行了事务中指定的工作中的一些,但无法完成该工作的其余部分,那么系统200必须中止该事务并“回滚”已执行的工作。
每个事务可以具有多个语句。在每个事务内,语句是串行执行的。然而,一个事务的工作可以与其它事务的工作并发地被执行。此外,在任何给定语句内指定的工作都可以被划分并且并行地执行。如上面所提到的,在执行事务的语句时生成的日志记录包括语句的编号和事务ID两者。
当事务提交时,根据该事务的协调引擎实例在其中运行的主机的逻辑时钟来为该事务指派提交时间。如上面所提到的,被选择为协调事务的引擎实例是通过确定事务的控制切片、然后选择管理该控制切片的主复本的引擎实例作为该事务的协调器而选择的。
同样如上面所提到的,事务内的语句可能要求在多个切片上执行DML操作。在这些情形下,这些切片中的一些切片的主复本可能是由驻留在协调引擎实例所属的主机以外的主机上的引擎实例来管理的。例如,假设一事务对驻留在切片S1和S3两者中的数据进行更新。在这些情形下,可以选择切片S1作为控制切片。由于S1是控制切片,因此管理S1D1(切片D1的主复本)的引擎实例200B被选为协调引擎实例。
为了对切片S3执行DML操作,协调引擎实例200B向管理S3D1的引擎实例发送语句片段,S3D1是切片S3的主复本。在图2中所示的实施例中,管理S3D1的引擎实例是主机202A上的引擎实例202B。该语句片段指定必须在切片S3上完成的工作。引擎实例202B执行所请求的工作并将工作的完成传送回协调引擎实例200B。
提交事务的先决条件
事务的协调引擎实例在确认该事务所需的所有工作都已成功执行之前不能提交该事务。在每个切片可以具有一个或多个次级复本并且每个事务可以在多个切片上执行DML的系统中,事务的工作包括(a)对切片的主复本执行DML,以及(b)将日志记录传播到次级复本。
此外,在切片的主复本上执行DML可以涉及(a1)协调引擎实例在控制切片的主复本上执行工作,(a2)协调引擎实例在一个或多个非控制切片的主复本上执行工作,以及(a3)一个或多个非协调引擎实例在一个或多个其它非控制切片的主复本上执行工作。
因此,需要提交规程(commit protocol)来确保直到以下所有事件发生后才提交事务:
·协调引擎实例已经执行了针对控制切片的主复本所请求的所有工作
·协调引擎实例已经在该协调引擎实例为其管理主复本的任何非控制切片上执行了所有请求的工作
·非协调引擎实例已经在被该事务改变的任何其它切片的主复本上执行了所有请求的工作,以及
·该事务对主复本所做的所有改变的日志记录已被成功传播到对应的次级复本
如前面所提到的,协调引擎实例可以向客户端报告客户端所请求的DML操作已成功执行,而无需等待如下的(一个或多个)主机实际接收到与DML操作对应的日志记录的确认,这些主机包含有在该DML操作中被改变的切片的(一个或多个)次级复本。然而,在提交之前,协调引擎实例有必要获得这样的确认。例如,假设事务TX1中的语句ST1要求改变映射到切片S1的行。在这些情形下,引擎实例200B可以在更新主复本S1D1并将对应的日志记录发送到主机200A的NIC之后向客户端确认语句ST1已经被执行。然而,在提交事务TX1之前,引擎实例200B必须接收到日志记录已被主机202A(其托管切片S1的次级复本S1D2)成功接收的确认。
此外,在提交事务TX1之前,协调器引擎实例必须接收到作为事务TX1的一部分被执行的所有其它引擎实例已准备好提交的确认。例如,如果TX1的语句ST2指定对切片S3中的数据进行DML操作,那么协调引擎实例200B将向引擎实例202B(管理切片S3的主复本S3D1)发送对切片S3执行DML的请求。
在非控制切片的主复本上执行DML的非协调引擎实例无法向协调引擎实例报告它已准备好提交,直到它接收到它对非控制切片所做的改变的日志记录已成功传播到管理非控制切片的次级复本的引擎实例的确认。在本示例中,引擎实例200B向引擎实例202B发送语句片段以使引擎实例202B对S3D1中的数据执行针对切片S3所请求的DML操作。在这些情形下,直到引擎实例202B接收到与它对S3D1的改变对应的日志记录已经被成功传播到分别由引擎实例208B和204B管理的S3D2和S3D3的确认,引擎实例202B才能报告它准备好提交。
语句的执行期间的通信
在解释提交事务中所涉及的操作之前,应给出在执行事务内的语句期间发生的各种通信的解释。参考图9,它是根据实施例的系统900的框图,该系统900将被用于解释可以由基于切片的分布式数据库系统使用的事务提交规程(protocol)。系统900包括六个主机950、952、954、956、958和960。主机950、952、954、956、958和960分别执行引擎实例902、904、906、908、910和912。引擎实例902管理切片S1的主复本930,而引擎实例912管理切片S2的主复本932。
切片S1具有分别由引擎实例904和906管理的两个次级复本934和936。切片S2具有分别由引擎实例908和910管理的两个次级复本938和940。
为了解释提交规程,假设客户端990提交包括两个语句ST1和ST2的事务TX1,其中语句ST1对切片S1执行DML并且语句ST2对切片S2执行DML。还假设切片S1被选择为事务TX1的控制切片。因为引擎实例902管理控制切片S1的主复本,所以引擎实例902被指定为事务TX1的协调器。
协调器对语句的执行
在本示例中,引擎实例902对语句ST1的执行通过以下方式进行:
·对切片S1的主复本930进行改变
·半同步地将这些改变的日志记录发送到切片S1的次级复本934和936
·半同步地将语句S1的语句结束保存点消息发送到切片S1的次级复本934和936
·向客户端990发送语句S1的语句完成确认消息。
非协调器对语句的执行
因为语句S2涉及对如下切片(即,该切片的主复本是在控制引擎实例的主机以外的主机处被管理的)执行DML操作,所以要求附加的通信。执行语句ST2所需的通信在图9中示出。
参考图9,语句S2从客户端990到主机950的提交被图示为“(1)语句”以指示客户端对语句ST2的提交是图9中所示的第一个动作。根据一个实施例,引擎实例902包括语句协调逻辑和事务协调逻辑。如有必要,语句协调逻辑将从客户端990接收的语句ST2拆分为语句片段,其中每个片段对其主复本由不同主机管理的切片进行操作。语句片段然后被发送到管理这些切片的主复本的引擎实例。
在本示例中,语句S2只有一个片段F1,它指示要在切片S2上执行的DML。引擎实例902将片段F1发送到引擎实例912(其管理S2的主复本932)以供执行。片段F1到主机958的传输在图9中被示为“(2)DML片段”,以指示片段F1的传输是图9中所示的第二个动作。
主机950上的事务协调逻辑跟踪事务TX1的状态,并将指示事务TX1的事务状态的事务日志记录存储在控制切片的主复本中。在本示例中,引擎实例902的事务协调逻辑将事务TX1的事务日志记录存储在主复本930中。如下文将更详细描述的,在TX1被提交之前,这些事务日志记录(不同于包含增量日志条目的数据日志记录)被传播到切片S1的次级复本934和936。
因为事务日志记录被传播到事务的控制复本的次级复本,所以管理这些(一个或多个)次级复本的(一个或多个)引擎实例中的任何一个引擎实例都能够用作该事务的备份协调器。因此,如前所述,如果事务的协调引擎实例失败,那么这些备份协调器之一被选择来恢复该事务。
在引擎实例912接收到语句片段F1之后,引擎实例912执行该语句片段,以对切片S2的主复本932中的数据执行指定的DML操作。包含反映这些改变的增量日志条目的日志记录随后被传播到切片S2的次级复本938和940。该数据日志记录到主机956和960的传播被图示为“(3)数据日志记录”以指示数据日志记录的传播按时间顺序是图9中图示的第三个动作。如上面所提到的,日志记录的传播以半同步方式执行,其中引擎实例912等待本地NIC确认接收到用于传输的日志记录,但不等待来自主机956和960的接收到日志记录的确认。
在将日志记录半同步传输到切片S2的次级复本938和940之后,引擎实例912向协调引擎实例902报告片段执行完成。在“片段完成”消息中,引擎实例912包括如下信息,该信息识别为引擎实例912在片段执行期间所做的改变而生成的最后日志记录。例如,如果该片段与事务的语句ST2相关联,并且片段的执行产生了三个日志记录,那么片段完成消息可以包括(a)语句编号ST2,和(b)该语句的最后一个日志记录的日志记录序列号(即,3)。“切片完成”消息的传输被图示为“(4)片段完成+Last_LOGREC_ID”以指示“切片完成”消息的传输按时间顺序是图9中所示的第四个动作。
在接收到来自所有参与语句执行的引擎实例的它们的语句部分已完全执行的确认后,协调器将“语句结束保存点事务日志”存储到其事务日志中,并半同步地将语句结束保存点事务日志发送到备份协调器(控制切片的次级复本的主机)。根据一个实施例,语句结束保存点事务日志包括:
·语句所属的事务的事务ID
·语句编号
·重试次数(为执行语句所做的尝试的次数)
·对于该语句接触的每个切片,特定于该切片的记录,该记录包括切片ID和指示最后一个日志记录的序列号的LogRecID,
以及这个语句对指定切片所做的改变
在本示例中,在从引擎实例912接收到片段完成消息后,引擎实例902存储语句结束保存点事务日志并将语句结束保存点事务日志传输到分别管理控制切片S1的次级复本934和936的引擎实例904和904。语句结束保存点事务日志的半同步传输如图9中的“(5)语句结束保存点事务日志”所示,以指示这个传输按时间顺序是图9中描绘的第五个动作。
如前面所提到的,协调引擎实例向客户端传回语句已成功完成的确认,而无需等待与语句相关的半同步传输实际到达其目的地。因此,在向NIC提供语句结束保存点事务日志以供向引擎实例904和906传输后,引擎实例902向客户端990报告语句S1已成功完成。
协调引擎实例
在事务开始时,协调引擎实例(上面给出的示例中的引擎实例902)将事务的事务记录存储在控制切片的主复本中的事务表中。事务记录包括事务的事务ID和关于事务的状态信息(例如,事务是否活动、已提交、中止等)。此外,事务条目还可以包括:
·已执行的语句的重试信息,以及
·“参与切片”的列表及其相应的“最后LogRecID”
参与切片的列表是作为事务中DML操作的目标的非控制切片的列表。在上面给出的示例中,切片S1是控制切片,而切片S2是参与切片,因为在切片S1是控制切片的事务期间更新了S2。与参与切片相关联的最后LogRecID指示由协调引擎实例从在参与切片上执行了DML的引擎实例接收到的最后LogRecID。在图9中所示的示例中,与参与切片S2相关联的LogRecID是在引擎实例912完成语句ST2的执行之后由引擎实例912发送给主机950的LogRecID(即,动作(4))。
如下文将解释的,协调引擎实例使用此状态信息来跟踪语句完成并协调提交规程。在一个实施例中,状态信息被维护在事务的事务记录中,该事务记录可以在该事务的控制切片的主复本中。然而,在替代实施例中,状态信息可以存储在别处,只要它对协调器引擎实例是可访问的即可。下面将参考图10描述协调引擎实例如何使用事务状态信息。
分支协调器
当事务的协调引擎实例发送语句片段以使另一个引擎实例执行DML操作时,该另一个引擎实例负责对事务的“分支”进行协调。在图9中所示的示例中,引擎实例912是负责对由引擎实例902协调的事务TX1中的分支进行协调的“分支协调器”。
根据一个实施例,每个分支协调器在本地事务表中存储条目,该条目指示:
·本地事务ID到全局事务ID的映射
·事务的本地分支的状态(活动、已提交、中止等)
·时间戳信息
这些“分支事务条目”使用半同步传播被传播到在该分支的执行期间被更新的主复本的次级复本。例如,在引擎实例912执行分支期间,引擎实例912对切片S2的主复本932执行DML操作。因此,该分支的分支事务条目使用半同步传播被传播到切片S2的次级复本938和940。
事务可以看到自己的未提交的改变。然而,事务只能看到其它事务的已提交的改变。另外,只有在改变的提交时间等于或早于它们的快照时间的情况下,事务才能看到其它事务做出的这些改变。事务状态信息,与时间戳信息相结合,允许在次级复本上执行读取。例如,假设客户端向主机956发送请求以读取截至快照时间T10的来自切片S2的数据。引擎实例908检查事务状态信息以确定在事务分支期间对切片S2所做的改变是否已经提交。如果对切片S2所做的改变已提交,那么引擎实例908检查时间戳信息以确定在事务分支中所做的改变是否落在T10快照内。如果改变未提交或太新(即,分支的提交时间大于T10),那么引擎实例908跳过时间顺序条目链中与事务分支期间所做的这些改变相关联的条目,以定位包含确实落在T10快照内的数据的较旧条目。
更新逻辑时钟
更新同一数据项的两个事务的提交时间反映对这个数据项所做改变的次序是至关重要的。因此,如果TX1更新数据项并提交,TX2然后更新同一数据项并提交,那么必须为TX2指派比TX1晚的时间戳,即使TX2由与协调TX1的主机不同的主机进行协调。
为了确保没有事务会被赋予比接触同一数据项的后续事务更早的提交时间戳,主机在发送到其它主机的消息上搭载其逻辑时钟的当前值。例如,根据一个实施例,事务中的所有参与者发送回协调引擎实例的准备确认消息包括他们各自主机的逻辑时钟的当前值。
事务中涉及的所有节点必须向协调引擎实例报告它们的逻辑时钟值,以确保为事务指派的提交时间晚于参与节点参与到事务中时的逻辑时钟。具体而言,必须将其时钟值报告回协调器引擎实例的节点包括(a)事务触及的所有主复本的节点,以及(b)事务触及的主复本的所有次级复本的节点。如下文将更详细描述的,从备份协调器引擎实例904发送的准备确认消息将包括主机952的逻辑时钟的当前值。从备份协调器引擎实例906发送的准备确认消息将包括主机954的逻辑时钟。从分支协调器引擎实例912发送的准备确认消息将包括主机958的逻辑时钟的当前值。
如果任何准备确认消息包括大于协调引擎实例的主机(例如,主机950)上逻辑时钟的当前值的逻辑时间戳,那么协调引擎实例的主机的逻辑时钟被更新以反映大于它接收到的最高逻辑时钟值的时间。例如,假设主机950上的逻辑时钟的当前值为T500。在这种情况下,如果来自引擎实例904、906和912的准备确认消息分别包含时间戳T300、T400和T600,那么主机950上的逻辑时钟将更新为至少T601。这种时钟调整是在协调引擎实例使用主机950上的逻辑时钟从事务TX1获得候选提交时间之前执行的。
提交事务
参考图10,它图示了用于在已经执行图9中所示的动作之后提交事务TX1的规程。最初,在执行事务的语句时,事务的状态是活动的。事务的“活动”状态反映在由协调引擎实例(例如,引擎实例902)、备份协调器(例如,引擎实例904和906)和分支协调器(例如,引擎实例912)维护的事务日志记录中。
在事务中的所有语句执行完毕之后,客户端提交提交命令。在接收到提交命令时,协调引擎实例902已接收到已执行TX1的所有语句(ST1和ST2)的确认,协调引擎实例902已相应地更新TX1的事务记录,并且已经半同步地将事务记录发送到控制切片S1的次级复本934和936。引擎实例902还已向客户端报告语句S1和S2已完全执行(连同每个语句的最后LogRecID)。
响应于提交命令,协调引擎实例通过以下操作过渡到“准备”状态:
·更新TX1的事务记录中的状态信息,以及
·向参与了该事务的所有引擎实例发送准备请求消息,这些引擎实例包括备份协调器、分支协调器(其托管该事务所触及的主复本)和事务所触及的所有切片的所有次级复本的主机。
为了向事务中的参与者发送准备请求消息,协调引擎实例从事务的事务记录中读取参与者的列表。根据实施例,协调引擎实例还获得事务的“准备时间戳”。事务的准备时间戳可以是协调引擎实例所驻留的主机的逻辑时钟的当前值。
根据实施例,准备请求消息包括:
·正被准备的事务的全局事务ID
·准备时间戳
·事务所触及的每个切片的切片ID
·对于事务所触及的每个切片,与事务对这个切片所做的改变相关联的日志记录的最后LogRecID。
响应于接收到准备请求消息,事务的参与者:
·如果全局准备时间戳大于本地逻辑时钟的当前值,那么将其本地逻辑时钟更新为全局准备时间戳
·使用准备请求消息中的最后LogRecIDs来确认它们拥有协调引擎实例认为它们应当具有的所有日志记录
·从其本地逻辑时钟获得本地准备时间戳
关于检查是否所有需要的日志记录都存在,假设参与的引擎实例具有切片S1的复本。进一步假设事务对切片S1所做的改变反映在三个数据日志记录DL1、DL2和DL3中。在这个示例中,对于切片S1,发送到引擎实例912的准备请求消息包括,DL3的最后LogRecID。响应于从协调引擎实例902接收到准备请求消息,参与的引擎实例核实它具有针对切片S1的直到并包括日志记录DL3的日志记录。如何处置错误(例如,参与的引擎实例缺失日志记录)将在下文中更详细地描述。
在确认他们具有所需的日志记录后,事务参与者获得本地准备时间戳并更新他们相应事务记录中的状态信息以指示本地准备时间戳和事务TX1处于“准备好”状态。在更新其相应的事务记录后,事务参与者向协调引擎实例发送准备确认消息。根据一个实施例,每个准备确认消息包括本地准备时间戳。这个时间戳值表示事务的本地“准备时间”。如下文将更详细描述的,协调引擎实例使用这些本地准备时间来确保事务TX1的提交时间大于所有本地准备时间。
在从所有事务参与者接收到准备确认消息后,协调引擎实例:
·将其本地逻辑时钟更新为大于最高本地准备时间的值(如果任何本地准备时间大于协调引擎实例的逻辑时钟的当前时间的话)
·基于其本地逻辑时钟的当前值获得候选提交时间
·用候选提交时间并且用事务处于“准备好/正在提交”状态的指示来更新其事务记录,以及
·向每个备份协调器发送包含候选提交时间的消息。
根据一个实施例,由协调引擎实例向备份协调器发送的“候选提交时间”是通过递增协调引擎实例的逻辑时钟的值、然后将协调器的逻辑时钟的新值用作候选提交时间来获得的。换句话说,候选提交时间被设置为max(本地准备好时间,当前本地时钟)+1。
在本示例中,主机950上的逻辑时钟递增,然后它的值被发送到引擎实例904和906作为TX1的候选提交时间。因为这是在基于事务中涉及的所有主机处的本地准备时间而更新逻辑时钟之后发生的,所以保证候选提交时间高于事务中所有参与者的准备时间。
响应于包含候选提交时间的消息,备份协调器用候选提交时间和事务处于“准备好/正在提交”状态的指示来更新它们的事务日志。备份协调器然后将“确认提交时间”消息发送回协调引擎实例。
在从所有备份协调器接收到确认提交时间消息后,协调引擎实例:
·将事务的状态改变为“已提交”,
·告诉客户该事务已提交(并提供提交时间),
·将提交的事务记录发送到备份协调器
响应于接收到事务的已提交日志记录,备份协调器更新其事务的事务日志记录以反映该事务已提交。
在事务提交之后,提交确认消息被(异步地)发送给事务中的所有参与者。响应于提交确认消息,对与该事务对应的所有条目(增量日志记录和/或行堆条目)执行清理。在清理之后,事务的参与者将提交确认消息发送回协调引擎实例。
报告事务已提交
在上述提交规程中,直到协调引擎实例从备份协调器接收到确认提交时间消息,协调引擎实例才告诉客户端事务已提交。协调引擎实例之所以要等到接收到备份协调器的确认提交时间消息才报告事务的提交是因为,在某些情形下,事务的提交时间会从最初由协调引擎实例设置的候选提交时间发生改变。
例如,假设事务最初被指派了候选提交时间T121。进一步假设协调引擎实例(例如,引擎实例902)在从备份协调器(例如,引擎实例904和906)接收到提交时间确认之前截至时间T121将事务标记为“已提交”。此时带有快照时间T125的读取操作将看到该事务所做的改变。
然而,在协调引擎实例已经从备份协调器接收到提交时间确认之前,协调引擎实例可能在时间T130崩溃。在这些情形下,可以指派备份协调器(例如,引擎实例904)作为该事务的新协调引擎实例。
可能不知道T121的候选提交时间的新协调引擎实例:
·重新准备事务(确认所有参与者都准备好提交事务)以供提交,
·选择新的候选提交时间(例如,T135)
·将候选提交时间发送给备份协调器
·当接收到确认时,将新的提交时间传达给客户端。
因为事务现在具有大于T125的提交时间T135,所以在协调引擎实例崩溃之前执行的读取操作(其使用快照时间125)是不可重复的。具体而言,用相同的快照时间执行相同的读取操作将产生不包括该事务所做改变的结果(因为新的提交时间在该读取操作的快照时间之后)。
用于经恢复的事务的中断范围(blackout ranges)
根据一个实施例,提交规程被修改,使得协调事务在候选提交时间消息“在线上(on the wire)”时就向客户端报告事务已提交,而不等待来自备份协调器的接收提交时间消息的确认。为了避免在没有接收到原始候选提交时间的备份协调器恢复此类事务时造成的不可重复读取操作问题,此类进行恢复事务的备份协调器为该事务指派“中断范围”。
根据一个实施例,用于备份协调器所恢复的事务的中断范围是以下两者之间的时间段:(a)事务的最高准备时间和(b)由进行恢复的备份协调器指派给该事务的提交时间。在上面给出的示例中,假设由原始协调引擎实例902接收到的最高准备时间是T124。因此,协调引擎实例902选择T125的提交时间。协调引擎实例902(在从备份协调器904和906接收到提交时间的确认之前)报告事务TX1已提交,然后崩溃。
于是可以选择备份协调器引擎实例904来恢复事务TX1。作为新协调器的引擎实例904重新准备该事务。由引擎实例904接收到的最大准备时间将再次为T124。然而,引擎实例904处的内部逻辑时钟可能是T134。因此,引擎实例904可以为事务TX1指派T135的提交时间。在这个示例中,用于经恢复的事务TX1的“中断范围”是介于但不包括T124(最高准备时间)与T135(经恢复的事务的提交时间)之间的时间范围。
在将中断范围指派给已提交的经恢复的事务之后,如果带有处于该中断范围内的快照时间的读取操作尝试读取经恢复的事务所触及的数据项,那么系统将报告错误。例如,在事务TX1在提交时间T135提交之后,并且中断范围为T125-134,如果具有在T125-T134范围内的快照时间的任何读取操作尝试读取事务TX1所触及的行,那么将生成错误。响应于接收到这种错误,客户端可以重新提交具有落在中断范围之外的快照时间(例如,读取快照时间T157)的读取操作。
以原子方式改变状态和时间戳信息
通常有必要以原子方式做出多个改变(以便进程要么看到所有改变,要么看不到任何改变)。例如,在获得候选提交时间之后,协调引擎实例必须在事务记录内将事务的状态改变为“正在提交”,并将时间戳改变为候选提交时间。重要的是,任何进程都不能看到这些改变中的一个而看不到另一个。
根据实施例,如果硬件不支持以原子方式做出这两个改变,那么原子性可以通过以下方式来实现:(a)在事务记录中存储无效时间戳、(b)改变事务记录中的状态信息,以及(c)将候选提交时间存储在事务记录中的无效时间戳之上。使用这种技术,正在读取该事务记录的进程将看到:
·状态=准备好,时间戳=准备好时间戳
·状态=准备好,时间戳=无效时间戳
·状态=正在提交,时间戳=无效时间戳
·状态=正在提交,时间=候选提交时间戳
在该读取进程看到无效时间戳(例如,时间戳0)的情况下,读取进程知道该事务记录正在更新,因此读取进程不使用该信息。相反,读取过程一直等到它看到有效的时间戳,此时该过程将看到“候选提交时间戳”并且状态为“正在提交”。
通道和自动提交事务
在上面给出的示例中,提交规程在从客户端接收到提交命令时被发起。然而,在自动提交事务的情况下,提交命令可以是隐式的。根据一个实施例,客户端和主机之间的“通道(lane)”的配置参数被设置为“自动提交”。“通道”是将客户端连接到主机的逻辑实体,确保通过该通道提交的语句的排序。因此,通道可以被认为是客户端通过它向主机发送命令的“管道”。
如果通道的配置参数被设置为自动提交,那么通过该通道接收的每个语句都被视为单语句事务。因此,在接收到来自这个通道的语句中指定的操作已经完成的确认之后,即使没有接收到显式的提交命令,协调引擎实例也自动发起提交规程。
虽然通道是最初在客户端和主机之间建立的管道,但通道可以被认为是客户端侧实体,因为与通道相关联的客户端不会改变,但与通道相关联的主机可能改变。例如,当事务从一个主机故障转移到另一个主机时,客户端提交针对该事务的命令的通道连接到新主机,并且该客户端继续使用同一通道向新主机提交针对经恢复的事务的命令。
急切准备
根据一个实施例,对于自动提交事务,有可能将通常在事务的准备阶段期间发送的消息搭载在事务的活动阶段期间发送的消息上。例如,包含由事务做出的改变的数据日志记录的传输可以与准备请求消息的传输相结合。在这些情形下,“准备请求消息”可以简单地是数据日志记录中的标志。当设置该标志时,接收方知道要准备事务所做的改变,并在其针对接收到的数据日志记录的确认消息上搭载准备时间戳。
再次参考图9,假设自动提交事务指定对切片S1中的数据的改变。S1被选为控制切片,并且因此引擎实例902被选为协调引擎实例。在对S1的主复本930做出改变之后,引擎实例902将包含这些改变的数据日志记录发送到主机952和954,主机952和954分别存储切片S1的次级复本934和936。对于急切准备(eager prepare),包括此数据日志记录的消息附加地充当准备请求消息。因此,主机952和954将通过确定事务的准备时间并向引擎实例902发回确认来对该消息进行响应,该确认不仅指示数据日志记录已被接收到,而且还包括它们针对该事务的相应准备时间。基于这些准备时间,引擎实例902选择候选提交时间并继续进行用于提交该事务的步骤(如图10中所示)。因此,避免了对单独“准备”阶段的需要。如果自动提交事务改变两个切片(例如,S1和S2)中的数据,那么负责这些切片的主复本的引擎实例将做出他们相应的改变并将其相应的日志记录发送到适当的次级复本。所有次级复本都将该数据日志记录作为准备请求消息,并以事务的准备时间进行响应。
对于不是自动提交的事务,急切地准备事务可能是效率低下的。例如,如果事务包括20个语句,那么要求参与者在20个语句中的每一个语句之后进行“准备”是低效的。如果参与者指示事务在20个语句中的第一个语句之后准备好,那么从那时起,以该事务所触及的数据为目标的读取操作将不得不将该事务视为处于准备好状态,而不是处于活动状态。正如下面更详细解释的,针对处于准备好状态的数据的读取操作可能要求附加的步骤(当读取的快照时间大于准备好时间戳时)以增加该事务最终被指派大于该读取操作的快照时间的提交时间的可能性。
在非自动提交事务中的语句数量已知或可以准确估计的情况下,急切地准备该事务可能仍然是值得的。在此类情况下,将数据日志记录消息与准备请求消息组合将仅针对已知是或估计是事务中最后一个语句的最后日志记录的内容执行。例如,在具有20个语句的事务中,准备请求消息可以与第20个语句所做改变的最后一个日志记录的数据日志记录消息相组合。
在最后一个语句的工作将由非协调引擎实例执行的情况下,协调引擎实例将准备请求消息与发送到该非协调引擎实例的DML片段组合。例如,再次参考图9,假设引擎实例902正在协调其中最后一个语句对切片S2进行操作的事务。在这些情形下,从引擎实例902发送的DML片段与准备请求消息组合。在执行DML片段之后,引擎实例912将准备请求消息包括在发送到切片S2的次级复本938和940的数据日志记录中。在这个示例中,引擎实例908和910不仅确认接收到日志记录,而且还(a)确认它们准备好提交事务并且(b)在该确认中包括它们的本地准备时间戳。在接收到这些确认消息后,引擎实例912更新其本地逻辑时钟,获得其自己的针对该事务的准备时间,并向协调引擎实例902确认它已准备好提交。在这种上下文中,“更新本地逻辑时钟”涉及将其逻辑时钟设置为以下项中的较大者:(a)当前值,和(b)本地准备时间戳。在引擎实例912对引擎实例902的确认消息中,引擎实例912包括其准备时间戳。
根据一个实施例,当通常被异步发送的消息与准备请求组合时,该消息代替地被同步发送。例如,直到引擎实例912从次级复本938和940接收到确认和准备时间戳,引擎实例912才会向引擎实例902报告它已成功执行其DML片段。
如上面所解释的,在事务的准备阶段期间,必须向任何未曾接收到“急切准备”消息的事务参与者发送准备消息。另一方面,如果急切准备消息(搭载在其它消息(诸如日志记录)上的准备请求消息)被发送给所有参与者,那么就没有单独的准备阶段。在这些情形下,当接收到提交指令时,协调引擎实例将已经拥有所有参与者的准备时间。此时,协调引擎实例选择候选提交时间并前进到提交阶段,如上所述。
对触及两个切片的自动提交的急切准备
急切准备甚至可以用于触及多于一个切片中的数据的自动提交事务。例如,假设在图9中所示的系统中,自动提交事务触及切片S1和S2。进一步假设切片S1被选为控制切片。因为切片S1被选择为控制切片,所以引擎实例902被指定为协调引擎实例。引擎实例902执行该事务中接触切片S1的一部分,并且将DML片段发送到引擎实例912以使引擎实例912执行该事务中接触切片S2的一部分。引擎实例902在发送到引擎实例912的DML片段上搭载准备请求消息。
引擎实例902将一个或多个日志记录发送到次级复本934和936,因此这些次级复本将反映引擎实例902对S1的主复本930所做的改变。每个次级复本的这些日志记录中的最后一个日志记录是同步发送的,并包括准备请求。
类似地,引擎实例912将一个或多个日志记录发送到次级复本938和940,因此这些次级复本将反映引擎实例912对S2的主复本932所做的改变。每个次级复本的这些日志记录中的最后一个日志记录是同步发送的,并包括准备请求。
引擎实例904和906通过获得准备时间戳并将准备时间戳发送到引擎实例902来对来自引擎实例902的数据日志记录/准备请求进行响应。类似地,引擎实例908和910通过获得准备时间戳并将准备时间戳发送到引擎实例912来对来自引擎实例912的数据日志记录/准备请求进行响应。引擎实例912随后根据需要增加其时钟,并获得准备时间戳。引擎实例912在确认执行DML片段的消息上搭载其准备时间戳。
此时,协调引擎实例902已直接或间接地从事务中的所有参与者接收到准备时间戳。协调引擎实例902基于这些准备时间戳根据需要增加它的当前时钟,并确定候选提交时间。协调引擎实例902然后可以直接前进到事务的提交阶段。
从准备好状态降级
当使用急切准备时,事务被每个接收到搭载的准备请求消息的引擎实例视为“已准备好”。因为使用急切准备,所以准备请求消息与在整个事务准备好提交之前所发送的消息相组合,同时接收到的读取操作可能会以低效的方式被处置。即,它们不能安全地忽略未提交的改变(如果事务尚未处于准备好状态,它们本可以安全地这样做)。根据一个实施例,系统跟踪有多少读取操作尝试读取由已被急切准备的事务所触及的数据。如果读取操作的数量超过阈值,那么事务自动从急切准备过渡到非急切准备。响应于该过渡,已经被急切准备的事务中的参与者将该事务状态改变回“活动”。此外,协调引擎实例丢弃参与者已经提供的准备时间。
作为事务状态返回到“活动”的结果,新的读取操作可以访问事务所触及的数据项的较旧版本,这是基于该事务将被指派给大于它们的快照时间的提交时间的假设。因此,对于快照时间大于准备时间的情况,可以避免特殊处置。从急切准备过渡到非急切准备的任何事务必须在事务的最后一个语句被执行之后经历完整的准备阶段,如图10中所示。
读取尚未提交的事务所更新的数据项
数据项已被尚未提交的事务更新的事实不一定会停止以此数据项为目标的读取操作的进展。例如,假设切片S1中行R1的时间顺序条目链有十个条目,其中前五个条目与尚未提交的事务相关联。进一步假设客户端提交了截至时间T20读取行R1的请求。如上面所解释的,可以使用片段S1的任何复本来服务于该读取操作。读取操作如何进行取决于尚未提交的事务的状态。
如果该尚未提交的事务仍然是“活动的”,那么可以跳过前五个条目,并且可以从该行的较早的五个条目中的一个或多个获得与时间T20对应的R1的行版本。在这种情况下,假设读取操作不需要看到尚未提交的事务所做的任何改变是安全的,因为能保证为该事务指派的提交时间大于该读取操作的快照时间T20。
如果尚未提交的事务处于“准备好”阶段并且准备好时间戳大于T20,那么可以跳过前五个条目,并且可以从该行的较早的五个条目中的一个或多个获得与时间T20对应的行版本。在这种情况下,假设读取操作不需要看到尚未提交的事务所做的任何改变是安全的,因为能保证为该事务指派的提交时间大于准备时间,已知该准备时间大于快照时间T20。
另一方面,如果尚未提交的事务处于准备好阶段并且准备好时间戳小于T20,那么有可能为尚未提交的事务指派小于T20的提交时间。例如,假设读取操作是要从S2的次级复本938读取切片S2的一行。如果事务处于准备好状态并且准备好时间是T15,那么引擎实例908将已经向协调引擎实例902发送了带有准备时间T15的准备确认消息。因此,保证了事务的提交时间大于T15,但不保证大于T20。在这些情形下,读取操作可以被暂停,直到为事务指派了提交时间。在一些情况下,读取操作可以被暂停,直到清理了事务所生成的条目,这是因为读取操作的协调器将直到在执行该读取操作的主机上清理了为事务生成的条目之后才会知道事务的提交时间。
如果提交时间大于T20,那么读取操作可以通过跳过该事务生成的五个条目来继续。另一方面,如果提交时间小于T20,那么该事务所做的改变必须被读取操作看到,因此这前五个条目中的值将根据需要被使用以获得读取操作所需的数据。
处于“准备好/正在提交”状态的事务以类似于“准备好”事务的方式被处置。具体而言,如果读取操作具有低于提交时间戳的快照时间,那么可以通过跳过与提交事务相关联的行的时间顺序条目链中的条目来执行该读取操作,因为保证了提交事务具有至少与提交时间戳一样高的快照时间。另一方面,如果提交时间戳小于读取操作的快照时间,那么读取操作必须一直等到为事务指派了提交时间。
针对准备时间读取操作的优化
如上面所提到的,具有如下快照时间(即,该快照时间大于对读取操作必须正常读取的项进行了更新的事务的准备时间)的读取操作必须等待,直到该事务提交并被指派了提交时间。一旦事务提交并指派了提交时间,那么,如果提交时间大于读取操作的快照时间,则跳过该事务所做的改变。另一方面,如果提交时间小于读取操作的快照时间,那么读取操作会看到该事务所做的改变。
根据一个实施例,采用一种避免在对特定数据项执行DML的事务的准备好阶段期间使需要查看该特定数据项的特定版本的读取操作等待的技术。具体而言,当(读取快照时间>事务准备好时间)时,执行读取操作的引擎实例向正在执行协调引擎实例的主机发送增加时钟消息。该增加时钟消息可以立即发送,或者在短暂等待之后被发送。
增加时钟消息包括读取操作的快照时间。如果协调主机处的逻辑时钟尚未高于增加时钟消息中的快照时间,那么接收到增加时钟消息的主机通过将该主机的逻辑时钟的值增加到高于该消息中包含的快照时间的值来对增加时钟消息做出响应。在接收到事务的主机已增加其逻辑时钟的确认后,读取操作可以在事务所做的改变不属于该读取操作的快照(并且因此可以被读取操作安全地跳过)这一假设下继续进行。此时,复本的准备时间也可以被增加到读取操作的快照时间(因为现在协调引擎实例的时钟已经用读取操作的快照时间最大化,所以能保证事务被指派高于该快照时间的提交时间)。
例如,假设TX1更新了切片S2中的特定行,TX1在次级复本938处的状态是“准备中”,并且TX1在次级复本938处的准备时间是T10。进一步假设引擎实例908接收到截至时间T20读取这个特定行的请求。在这些情形下,不是等待TX1提交,而是引擎实例908可以向主机950发送带有时间戳T20(或更高)的增加时钟消息。作为响应,主机950将其本地逻辑时钟的值增加到比增加时钟消息中包括的时间戳更晚的时间。以这种方式增加主机950的时钟能确保主机950将向TX1指派比读取操作的快照时间T20更高的提交时间。主机950将确认增加时钟消息发送回主机956。在接收到对增加时钟消息的确认之后,准备时间可以增加到T20,并且读取操作可以继续进行,从而跳过与TX1相关联的条目,因为保证了TX1所做的改变不在与时间T20相关联的快照中。
根据一个实施例,增加时钟操作是使用一系列远程直接存储器访问(RDMA)调用来完成的。可以进行RDMA调用以读取协调引擎实例正在其上运行的主机上的相关的事务表条目。从该事务条目中,读取操作的协调器可以获得事务的全局准备时间。如果读取操作快照较小,那么可以安全地忽略该改变,因为提交时间只会增加。如果读取操作快照大于全局准备时间,那么可以使用RDMA写入操作将全局准备时间改变为读取操作的快照时间。以这种方式改变全局准备时间确保了事务的协调引擎实例最终将为事务指派比读取操作的快照时间更高的提交时间。
处置提交时读取操作(committing-time read operation)
如上面所解释的,在确保事务将被指派大于读取操作的快照时间的提交时间之后,在事务的准备阶段期间到达的读取操作可以读取事务所触及的数据项的较旧版本。遗憾的是,当所讨论的事务处于准备/提交状态时,无法对读取操作执行类似的优化。
当事务处于准备好/正在提交状态时,事务的协调器已经向备份协调器发送了候选提交时间。因此,此时基于读取操作的快照时间来增加协调引擎实例的主机的逻辑时钟可能不会对指派给事务的提交时间产生任何影响。类似地,改变全局事务表条目中事务的准备时间将改变协调引擎实例已经发送给备份协调器的候选提交时间。
根据一个实施例,当事务处于“准备好/正在提交”状态时,读取操作的协调器仍可以向协调引擎实例发送增加时钟消息。然而,协调引擎实例不是调整其时钟或改变全局准备时间,而是一直等到它接收到来自备份协调器的确认提交时间消息。此时,协调引擎实例不仅将事务状态改变为“已提交”,而且还会通过提供指派给事务的提交时间来对搁置的读取操作进行响应。
因为提交时间是直接发送到读取操作的协调器的,所以读取操作仅被搁置直到事务提交,而不是所讨论的数据日志条目的清理时间。通过将事务的提交时间与读取操作的快照时间进行比较,读取操作的协调器确定是从为事务生成的时间顺序条目链条目中获得数据,还是跳过这些条目。
根据一个实施例,当事务处于准备好/正在提交阶段并且读取操作被搁置时,协调引擎实例可以将事务的候选提交时间发送到被搁置的读取操作的协调器。可以在协调引擎实例不等待所有备份协调器确认提交时间的情况下发送这个候选提交时间。在这些情形下,如果候选提交时间小于读取操作的快照时间,那么读取操作必须继续等待(因为还不能保证事务一定会提交)。另一方面,如果候选提交时间大于读取操作的快照时间,那么读取操作可以在它看不到事务所做的改变这一假设下继续进行。这是可能的,因为如果事务确实提交,那么它的提交时间将至少与候选提交时间一样高。
乐观的准备时间
如上文所解释和图10中所示的,在从事务中的所有参与者接收到准备确认消息后,协调引擎实例选择高于以下各项的候选提交时间:(a)其当前逻辑时钟,和(b)从事务参与者接收到的最高准备时间。在上述实施例中,由每个事务参与者发送的准备时间是在参与者准备与事务相关联的改变时参与者的主机处的逻辑时钟的值。
例如,如果事务TX1对图9中所示的系统900中的切片S1和S2执行DML,那么系统900中的所有主机都将成为TX1中的参与者,因为每个主机都具有切片S1或者切片S2的复本。由于这些主机处的逻辑时钟彼此独立,因此在每个主机处为事务TX1建立的准备时间可能不同。
如上面所提到的,如果读取操作的快照时间大于TX1的准备时间,那么在TX1的准备阶段期间以TX1所触及的数据项为目标的读取操作必须在读取数据项之前执行附加的工作(例如,向控制引擎实例发送时钟增加消息)。然而,如果它们的快照时间小于TX1的准备时间,那么此附加的工作不是必要的。
根据一个实施例,为了增加稍后接收的读取操作的快照时间将小于正被准备的事务的准备时间的可能性,事务的参与者可以为事务指派高于其当前时钟的准备时间。例如,假设引擎实例910已经接收到针对TX1的准备请求。作为响应,引擎实例910核实S2的次级复本940具有TX1对切片S2所做的所有改变的日志记录。引擎实例910然后将其本地存储的TX1的状态改变为“准备好”,存储TX1的本地准备好时间,并在准备确认消息中返回该本地准备好时间。为了指派乐观的准备时间,引擎实例910选择显著高于主机960的逻辑时钟的当前值的准备时间。
例如,如果主机960的逻辑时钟的当前值是T1000,那么引擎实例910可以选择T10000的准备时间。通过以这种方式选择乐观的准备时间,引擎实例910增加了在TX1的准备状态期间接收到的以TX1所触及的数据项为目标的任何读取操作将具有小于TX1的本地准备时间的快照时间的可能性。因为这些读取操作的快照时间将低于TX1的本地准备时间,所以读取操作可以继续(查看数据项的TX1之前的版本),而无需执行任何附加的工作来确保TX1将被指派大于读取操作的快照时间的提交时间。
日志记录的逻辑回滚
在各种情形下,有必要“回滚(rollback)”或“撤销(undo)”对切片所做的改变。根据实施例,不是创建其中改变已被移除的数据的新版本,而是系统简单地存储如下数据,该数据指示哪些日志记录将被视为“撤销的(undone)”。
例如,假设语句ST3对其主复本分布在多个主机上的多个切片做出改变。在该语句的执行期间,语句ST3的日志记录由这些主机中的每一个生成。这些日志记录中的每一个都用用于语句ST3的标识符标记。如果协调引擎实例在语句ST3执行完成之前发生故障,那么事务将故障转移到另一个引擎实例,该引擎实例成为该事务的新协调引擎实例。为了撤销为语句ST3所做出了的改变,新的协调引擎实例生成“回滚日志记录”。回滚日志记录指示所有标记有事务的语句编号ST3的日志记录都将被视为“撤销的”。
在存储回滚日志记录之后,新的协调引擎实例重新提交该语句以供执行。然而,新的协调引擎不是重复使用相同的语句编号,而是为该语句指派新的语句编号(例如,ST4)。因为对于重新执行的语句使用新的语句编号,所以可以容易地将语句执行中止的日志记录与语句重新执行时所生成的日志记录区分开来。
当将增量日志条目应用于行堆时,跳过“撤销的”日志记录中的增量日志条目。因此,应用此类日志记录涉及从其相应的时间顺序条目链中移除增量日志条目,而不创建任何新的堆行条目。在撤销的增量日志条目从其时间顺序条目链中移除之后,分配给增量日志中的这些撤销的日志记录的空间可以被解除分配/重新使用。
从丢失的数据日志记录中恢复
在事务的执行期间,会发生许多不同类型的故障。这样的一个错误是次级复本未能接收到反映对主复本所做的改变的数据日志记录。何时发现该错误取决于多种因素,诸如包含该主复本的主机是否发生故障。
再次参考图9,假设在执行与事务TX1的语句ST2相关联的DML片段期间引擎实例912生成三个数据日志记录(DL1、DL2和DL3)。进一步假设S2的次级复本940和938的主机960和956没有接收到数据日志记录DL2。
如果主机960和956在没有接收到DL2的情况下接收到后续的数据日志记录(例如,DL3),那么主机960和956能够判断它们缺失了数据日志记录。在这些条件下,主机960和956可以从主机958请求缺失的日志记录(DL2)。
在一些情况下,可能直到稍后在事务执行中才发现故障。例如,假设主机956和960接收到日志记录DL1和DL2,但是没有接收到日志记录DL3,日志记录DL3是从主机958半同步发送的。进一步假设主机958向主机950确认了语句片段的完成,然后崩溃。从主机958发送到主机950的片段完成确认消息包括引擎实例912对切片S2的主复本932所做的改变的最后LogRecID。因此,在崩溃之后,协调引擎实例902将具有在崩溃之前由引擎实例912生成的日志记录DL3的LogRecID。
遗憾的是,随着主机958的崩溃,实际日志记录DL3将会丢失。在崩溃之后,次级复本938可以被指定为S2的新主复本。在这些情形下,与日志记录DL3相关联的改变将不会被反映在S2的新主复本938中。在事务TX1的提交规程的准备阶段期间,控制引擎实例902将向事务TX1中的所有参与者发送准备消息。在本示例中,控制引擎实例902将询问主机956它是否已经准备好对切片S2的所有改变直到数据日志记录DL3中反映的改变。因为引擎实例908只有直到DL2的数据日志记录,所以引擎实例908将在TX1的准备阶段期间报告错误。在这些情形下,整个事务TX1可能需要回滚并重新执行。
引擎集群
术语“引擎集群”在本文中被用来统指如下一组实体,这些实体一起工作,服务于来自客户端的数据库命令。例如,在图2中所示的系统200中,引擎集群包括引擎实例200B-208B。引擎集群的成员资格可以动态改变。例如,如果引擎实例202B发生故障,那么引擎实例202B不再是引擎集群的成员。相反,为了增加引擎集群的容量,可以向引擎集群添加新的主机和引擎实例。
当引擎集群的成员资格发生改变时,需要重新指派复本托管责任。例如,因为发生故障的主机上的引擎实例所管理的复本无法再被访问,所以对于发生故障的主机处的每个主复本,位于不同主机处的次级复本将被提升为主状态。如上所述,次级复本的这种提升可以作为事务故障转移操作的一部分来执行。类似地,当新主机被添加到引擎集群时,需要将这些新主机处的引擎实例指派给主机复本,以便将系统的一些工作负载分配给新主机。
控件集群
根据实施例,除了引擎集群之外,分布式数据库系统还包括控件集群。控件集群包括一组控件实例。控件集群中的控件实例的数量常常是奇数,但也可以使用偶数个控件实例。参考图12,它图示了包括六个主机1200、1210、1220、1230、1240和1250的分布式数据库系统。两个引擎集群和一个控件集群在这些主机上执行。具体而言,控件集群包括分别在主机1200、1220、1230和1240上执行的控件实例1202、1222、1232和1242。分别在主机1200、1210、1220、1230和1250上执行的引擎实例1204、1214、1224、1234和1254形成一个引擎实例集群(EC1)。分别在主机1200、1210、1230、1240和1250上执行的引擎实例1206、1216、1236、1246和1256形成另一个引擎实例集群(EC2)。
控件集群的责任是跟踪每个引擎集群的当前状态和成员资格。具体而言,控件集群对哪些主机当前作为分布式数据库系统的一部分操作以及主机之间的邻居监视关系进行跟踪。下面将更详细地描述邻居监视。
根据一个实施例,控件实例作为高可用性元数据基础设施(HAMI)总体(ensemble)操作。在一个实施例中,HAMI仅使用本地存储装置在足够多的机器上提供分层键-值存储以实现高可用性。支持写入的总体通常有3-9个有投票权的成员(voting member)。也可以有无投票权的观察者(可以处置客户端写入请求)以用于附加的读取扩展(readingscaling)。在一个实施例中,HAMI通过将读取操作引导到复本和无投票权的观察者来提高可扩展性。HAMI总体是被称为成员的HAMI引擎的各个实例的集合。总体被配置有一定数量的成员,并且在简单的情况下,这些经配置的成员当中的法定数量(quorum)必须启动并运行以提供服务。在一些实施例中,还可以存在经配置的数量的共享(非本地)存储位置。当存在共享存储时,总体可以提供法定数量的经配置的成员,或者能够达到法定数量的共享存储位置的、少于法定数量的成员。这允许一个经配置的成员在它能够达到足够多的共享存储时提供服务,即使经配置的成员中的大多数是不可用的。经配置的成员具有固定的网络位置和端口。该配置被保存在所有成员可见的经复制的对象存储库中,并且除了名称解析外不需要任何其它东西。
在跟踪引擎集群的状态和成员资格时,控件集群必须能够响应于影响成员资格的改变而非常快速地做出关于引擎集群成员资格的决定。另外,控件集群本身应当是容错的,因此需要改变引擎集群的成员资格的故障不会同时导致控件集群发生故障。
控件集群对主机集群的视角被认为是调查故障的“真相”。如下文将详细描述的,调查是必要的,因为仅因为另一个主机已报告一主机发生故障就假设该主机发生故障是不安全的。例如,如果主机1200报告主机1210发生故障,那么主机1210可能确实发生了故障。然而,替代地,主机1200可能正遭遇网络问题(因此无法读取主机1210的健康计数器)而主机1210正在正常操作。下文将更详细地描述使用健康计数器来检测故障。
健康计数器
参考图13,它更详细地图示了图12的主机1200。根据一个实施例,每个主机维护一组健康计数器1330。健康计数器1330是主机1200的易失性存储器中的、由主机1200内的组件周期性更新的值。当计数器停止更新超过一阈值时间段时,很可能是负责递增该计数器的组件发生故障。因此,根据一个实施例,健康状况检查器通过周期性地检查与组件相关联的计数器来监视它们各自组件的健康状况,以确保计数器按预期递增。
健康状况检查器和监视树
根据一个实施例,使用各种“健康状况检查器”来监视分布式数据库系统的各种组件的健康状况。健康状况检查器是如下实体,该实体的角色是检测组件何时发生故障。根据一个实施例,健康状况检查器被布置在层次结构中,其中较高级别的健康状况检查器监视一个或多个较低级别的健康状况检查器的健康状况。主机内的健康状况检查器的层次结构构成了“监视树”,监视树的“根”是负责监视主机自身健康状况的健康状况检查器。
在图13中所示的实施例中,引擎实例1204和1206分别包括实例检查器1312和1314。在一个实施例中,实例检查器是监视树中最低级别的健康状况检查器。实例检查器监视特定于调度器组(scheduler-group-specific)的健康状况计数器,这些计数器由在其相应引擎实例内执行的调度器组递增。当特定于调度器组的健康状况计数器指示相应的调度器组正在正确执行时,实例检查器会增加它们自己的特定于引擎的健康状况计数器。
除了实例检查器1312和1314之外,主机1200还包括主机检查器1310和邻居检查器1340。主机检查器1310基于由实例检查器1312和1314设置的特定于引擎的健康状况计数器来监视主机1200的健康状况。除了监视特定于引擎的健康状况计数器之外,主机检查器1312还可以从主机管理器1350获得信息。主机管理器可以执行与主机1200的健康状况相关的各种检查,包括但不限于:
·检查主机1200上运行的操作系统的健康状况(例如,检查内核存储器碎片)
·检查寄存器以检测主机控制器适配器(例如,连接到主机1200的一个或多个NIC)的任何问题
·检查主机1200本地的任何SSD和NVRAM的健康状况
·检查主机服务组件的健康状况当主机管理器1350和特定于引擎的健康状况计数器指示引擎实例正在恰当地操作时,主机检查器1310可以递增特定于主机的健康状况计数器。
邻居检查器1340通过周期性地读取相邻主机的特定于主机的健康状况计数器的值来监视相邻主机的健康状况,这将在下文中更详细地描述。除了监视相邻主机的特定于主机的健康状况计数器之外,邻居检查器1340还可以周期性地读取在相邻主机上执行的邻居检查器的健康状况计数器。因此,邻居检查器1340能够检测其邻居主机何时未正常运行以及其邻居主机何时未正确监视其相应的邻居主机。
根据一个实施例,邻居检查器1340通过使用RDMA操作从邻居主机的存储器中读取健康状况计数器来确定邻居主机是否正常操作。例如,邻居检查器1340可以使用RDMA操作来读取主机1210的易失性存储器中的健康状况计数器(参见图12)以确定主机1210是否正常操作。
最后,在控件实例1202内是用于使用HAMI心跳来检测其它控件实例的健康状况的逻辑。下文将更详细地描述如何监视控件集群的健康状况。
主机监视环
如上面所提到的,每个主机内的邻居检查器使用RDMA读取相邻主机的特定于主机的健康状况计数器以确定相邻主机是否正常操作。根据一个实施例,控件集群进行邻居监视指派以确保每个主机的健康状况都被另一个主机监视。可以进行此类邻居监视指派,使得邻居监视关系形成包括所有主机的环。
再次参考图12,它图示了形成包括所有主机1200-1230的环的邻居-监视关系1270。在所示实施例中,主机1200监视主机1210的健康状况。主机1210监视主机1220的健康状况。主机1220监视主机1250的健康状况。主机1250监视主机1240的健康状况。主机1240监视主机1230的健康状况。主机1230监视主机1200的健康状况。
网络拓扑
参考图16,它图示了支持图12中所示实体之间通信的网络拓扑。在图16中,八个主机中的每个主机都在执行主机监视器。主机监视器是主机监视环的一部分,其中每个主机监视相邻主机的健康状况。此外,主机中的一些主机正在执行控件实例。
将主机相连接的网络的拓扑使得每个主机可以通过两个不同的网络连接到每个其他主机。例如,最左边的主机可以通过包含交换机1、2和3的一个网络或通过包括交换机4、5和6的第二网络来与最右边的主机通信。
对引擎实例故障进行响应
当引擎实例发生故障时,故障将由与发生故障的引擎实例在同一主机上运行的主机检查器检测到。例如,如果引擎实例1204发生故障,那么实例检查器1312将检测到该故障并停止增加引擎实例1204的健康状况计数器。主机检查器1310将看到引擎实例1204的健康状况计数器没有改变,并且知道引擎实例1204已经发生故障。
在主机检查器检测到其主机上的引擎实例已经停止运转之后,主机检查器向引擎集群中幸存的引擎实例发送消息,向它们通知兄弟引擎实例已经停止运转。例如,如果有100个主机并且引擎集群中有10个引擎实例并且一个引擎实例停止运转,那么主机检查器将发送9个消息。引擎逐出消息告诉其它引擎实例从引擎实例集群中逐出发生故障的引擎实例。根据一个实施例,使用RDMA(快速路径)来发送引擎逐出消息,并且发送引擎逐出消息的主机检查器不会等待该消息被确认。这些对等体到对等体(peer-to-peer)逐出消息因而是“不可靠的”。
除了向幸存的引擎实例发送引擎逐出消息之外,在发生故障的引擎实例的主机上运行的主机检查器还向控件集群发送消息。然而,与发送到幸存引擎实例的引擎逐出消息不同,在将引擎逐出消息发送到控件集群之后,主机检查器等待来自控件集群的已接收到该消息的确认。
在接收到引擎实例逐出消息后,控件集群在控件目录中记录引擎实例逐出,并向引擎实例集群的所有幸存成员广播逐出通知。与对等体到对等体逐出消息形成对比,来自控件集群(慢速路径)的逐出消息是可靠的。因此,如果所有的主机间连接都正常运行,那么每个幸存的引擎实例将两次被通知引擎实例逐出:一次是通过来自发生故障的引擎实例的主机的RDMA,另一次是通过来自控件集群的逐出广播。
在被通知引擎实例将被逐出后,幸存的引擎实例更新它们的引擎实例集群配置信息以逐出该指定的引擎实例,调整切片托管指派以考虑发生故障的引擎实例的移除等。
对主机故障进行响应
当主机发生故障时,被指派来对这个发生故障的主机进行邻居监视的主机将通过注意到发生故障的主机上的健康状况计数器没有增加而检测到该故障。例如,假设主机监视环如图12中所示建立。如果主机1210发生故障,那么主机1200(该主机当前被指派给对主机1210进行邻居监视)上的邻居检查器将检测到该故障。
在检测到主机的故障后,检测到故障的主机向控件集群发送消息以报告主机故障。在向控件集群报告主机故障之后,检测到故障的主机将开始对发生故障的主机曾对其进行邻居监视的主机进行邻居监视。因此,在报告主机1210发生故障后,主机1200将开始对主机1220(先前被发生故障的主机1210监视的主机)进行邻居监视。
在接收到发生故障的主机的通知后,控件集群发起调查。根据一个实施例,调查以分级方式进行。
参考图14,图示了包括四个主机1401、1402、1403和1404的分布式数据库系统。为了说明的目的,假设主机1403上的邻居检查器检测到主机1404的问题。该问题可以是主机1404的主机健康状况计数器已停止递增,或者主机1403无法与主机1404通信。主机1403尝试读取主机1404的健康状况计数器如(1)中所示,指示它按时间顺序是图14中所示的第一个动作。
在检测到主机1404的问题后,主机1403上的邻居检查器确定谁是控件集群1450中的当前领导者。在一个实施例中,这可以使用任何控件实例的RDMA来实现。在图示的示例中,对跟随者控件实例(CI-F)的RDMA被示为(2)。
一旦识别出控件集群的领导者,主机1403的邻居检查器就向控件实例领导者(CI-L)发送主机逐出警报。主机逐出警报的传输如(3)所示。
响应于接收到主机逐出警报,控件实例领导者:
·确定逐出列表(4)
·向每个幸存的主机发送怀疑通知(5)
·在控制目录中记录逐出列表
·更新与被逐出的主机对应的状态信息
·向每个幸存的主机发送逐出通知(6)
确定逐出列表
如上面参考图14所解释的,当一个或多个主机发生故障时,控件集群的领导者确定哪些主机将从主机集群中被逐出。作为一般规则,领导者尝试在主机集群中保留可以彼此通信的最大主机集合。该集合在本文中被称为“最大完全连接的主机集合”。最大完全连接的主机集合是基于主机之间的连接性来确定的,如现在将参考图15描述的那样。
参考图15,它是根据一个实施例的用于确定最大完全连接的主机集合的流程图。在步骤1502,确定“本地调查”是否成功。本地调查是指当一个引擎实例检测到与之通信的另一个引擎实例出现问题时所采取的故障排除步骤。本地调查的最终结果是以下三种替代方案之一:
·问题的解决(例如,重新启动挂起的线程)
·实例的逐出(作为调度组逐出的代理,因为我们没有后者)
·如果怀疑连接性是根本原因,那么请求扩大调查范围。在这种情况下,我们将模式切换为重点调查(focusedinvestigation)。
例如,本地调查可以涉及尝试重新启动一个或多个组件。如果本地调查成功,那么控制传递到步骤1550,在该步骤中问题被认为已解决并且可以继续进行正常操作。如果本地调查失败,那么控制传递到步骤1504。
在步骤1504处,开始“重点调查”。重点调查是确定需要从主机集群中逐出哪些引擎实例。根据一个实施例,不属于最大完全连接的引擎实例集合的引擎实例被逐出。
为了说明的目的,假设重点调查是由主机A无法与主机B通信的情况触发的。在这个场景中,在步骤1508处,主机A确定它是否可以到达控件集群的当前领导者。如果主机A无法到达控件集群的当前领导者,那么主机A知道它将被逐出。因此,在步骤1552处,主机A自我逐出。在自我逐出之后,主机A停止处理客户端的数据请求,直到执行恢复以将主机A重新添加到主机集群中。
如果主机A可以到达控件集群的当前领导者,那么主机A通知当前领导者它无法到达主机B。在步骤1510处,控件集群的领导者尝试联系主机B。如果领导者无法与主机B通信,那么在步骤1554处将主机B添加到逐出列表。
如果领导者可以到达主机B,那么在步骤1512处,领导者确定主机A和B是否能够访问同一网络。如果A和B不能访问同一网络,那么控制传递到步骤1518并且使用打破平局的试探法来确定A和B中的哪一个将被逐出。在步骤1556处,输家被添加到逐出列表。
如果主机A和B能访问同一网络,那么控制传递到步骤1514,在该步骤中使用控件集群的一个或多个其它成员来探测到主机A和B的连接。作为由控件集群的一个或多个其它成员执行的探测的结果,控件集群确定主机A和B的连接性分数。根据一个实施例,主机A的连接性分数反映控件集群中有多少成员可以与主机A通信,而主机B的连接性分数反映控件集群中有多少成员可以与主机B通信。
在步骤1516处,确定主机A与B的连接性分数是否相等。如果连接性分数不相等,那么具有较低连接性分数的主机被认为是“输家”,并在步骤1556处被添加到逐出列表中。如果连接性分数相等,那么在步骤1518处使用打破平局的试探法来确定在步骤1556被放入逐出列表的输家。
步骤1552、1554和1556之后是步骤1558,其中逐出列表准备就绪。一旦准备就绪,就在步骤1560中将逐出列表提交给控制目录,并且在1562处发起逐出规程。
处理逐出对于幸存的实例来说是一项繁重的任务。另外,处理逐出必须在短时间内完成。例如,幸存者必须重新配置受逐出影响的切片。幸存者可能需要构建附加的复本来补偿失去的复本。
如上所述,重点调查是成对进行的。在多个故障的情况下,基于成对调查的逐出可能导致不必要的重新配置工作。此外,在多重故障场景下,成对调查会导致显著次优的全局配置。
为了避免在多重故障场景中的成对调查会导致的问题,如果在重点调查期间(或在重点调查之后的很短时间内)警报到达控件集群,那么采用“广泛调查(wideinvestigation)”技术。在重点调查期间接收到这种警报可以指示存在多重故障场景。
在“广泛调查”期间,控件集群充当调查者和仲裁者,并且集群的所有主机都在调查的范围内。在广泛调查期间,检查控件集群和主机之间的连接,而不是检查主机之间的对等连接的全集。广泛调查所导致的逐出在单个逐出列表中被成批处理。
在广泛调查中,对控件集群领导者可用的网络连接进行分类。例如,假设控件集群领导者连接到两个网络(网络1和网络2)。控件集群领导者通过网络1和网络2两者可以访问的主机可以被归类为“完全连接的主机”。控件集群领导者通过单个网络间接访问的主机可以被归类为“边缘主机”。控件集群领导无法直接或间接访问的主机被归类为“无法到达”。在归类之后,无法到达的主机被逐出。
一个网络的边缘主机一般不能与另一个网络的边缘主机通信。在这些情形下,控件集群领导者决定要逐出哪个网络的边缘主机。例如,控件集群领导者可以决定保留网络1中的边缘主机,而逐出网络2中的边缘主机。根据一个实施例,在选择要保留哪个网络的边缘主机时,相对于不包括控件实例的主机,控件集群领导者偏爱保留包括控件实例的主机。如果广泛调查最初是由一个主机发出的关于另一个主机的警报触发的,那么控件集群实例确保这两个主机中至少有一个主机被包括在建议的逐出列表中。
对其它类型的故障进行响应
主机和引擎实例故障并不是分布式数据库系统中可能发生的唯一类型的故障。例如,诸如主机服务(例如,主机检查器1310)和实例服务(例如,引擎实例1204或控件实例1202)之类的软件组件可能发生故障。当软件组件发生故障时,系统自动尝试重新启动发生故障的组件。
如果引擎实例停止运转(发生故障并且不能重新启动),那么在与该引擎实例相同的主机上执行的用于该引擎实例的主机检查器检测故障并将故障报告给控件集群。例如,如果引擎实例1204停止运转,那么主机检查器1310向控件集群报告引擎实例1204已停止运转。以这种方式报告已停止运转的引擎实例被称为“单方面报告”,因为它不涉及除发生故障的引擎实例正在其上执行的主机以外的任何主机上的组件。响应于被通知引擎实例已发生故障,控件集群以逐出发生故障的引擎实例的方式来重新配置引擎集群。
引擎实例逐出
出于各种原因,可能需要将引擎实例从引擎集群中逐出。例如,如上面所解释的,引擎实例可能需要被逐出,因为实例检查器已经检测到引擎实例已经停止做有用的工作。如果引擎实例正在其上执行的主机发生故障(这可以通过邻居监视检测到),那么也将需要逐出该引擎实例。最后,如果引擎实例正在其上执行的主机失去与主机集群中其它主机的连接(例如,由于链路或交换机故障),那么将需要逐出该引擎实例。
逐出引擎实例涉及以排除该引擎实例的方式重新配置引擎集群。重新配置引擎集群可以涉及:
·确定由被逐出的引擎实例管理的主复本
·将这些主复本的次级复本指定为新的主复本
·创建新的次级复本以取代这些已变成主复本的次级复本
·更新切片到引擎实例映射以反映改变
控件实例健康状况监视
如上所述,通过在主机监视环中监视相邻主机,有可能检测主机何时发生故障。在一个实施例中,使用单独的健康状况监视机制来检测控件实例的故障。具体而言,根据实施例,控件集群使用RAFT规程来检测其成员当中的故障。RAFT规程在斯坦福大学的DiegoOngaro和John Ousterhout的“In Search of an Understandable Consensus Algorithm”中被详细描述,该论文可以在www.usenix.org/conference/atc14/technical-sessions/presentation/ongaro找到,其内容通过引用并入本文。
根据RAFT规程,在任何给定时间都存在被指定为“领导者实例”的控件实例。然而,领导者实例的指定是临时的,并且随着时间改变。在一个实施例中,领导权时间具有固定的持续时间。一旦一位领导者的领导权持续时间结束,领导权指定就自动传递给另一位领导者。根据实施例,领导权指定的序列形成环,该环包括控件集群中的所有控件实例。因此,每个控件实例在成为指定的领导者实例方面都具有相同的“轮流机会”。在替代实施例中,领导权不会随时间自动改变。而是,一旦被选为领导者,控件实例就将一直保持领导权直到它发生故障,在它发生故障时,可以选举跟随者作为新的领导者。在一个实施例中,当选择新的领导者时,每个控件实例具有相同的被选为新领导者的机会。
在一个实施例中,为了检测控件实例故障,领导者实例向所有其它控件实例发送心跳消息,并且所有其它控件实例将心跳消息发送回领导者实例。未能在阈值时间段内接收到心跳消息指示未从其接收到心跳的控件实例没有正确操作。因此,领导者实例能够检测到任何其它控件实例(“跟随者实例”)何时发生故障,并且所有跟随者实例都能够检测到领导者实例何时发生故障。
在替代实施例中,控件集群可以使用健康状况计数器和RDMA以类似于主机集群的方式来检测故障。具体而言,不是领导者实例向所有跟随者实例发送心跳消息,而是领导者实例可以递增健康状况计数器并且跟随者实例可以使用RDMA来检查领导者实例的健康状况计数器。类似地,不是跟随者实例向领导者实例发送心跳消息,而是跟随者实例可以更新本地健康状况计数器并且领导者实例可以使用RDMA来检查跟随者实例的相应健康状况计数器是否正在增加。
根据一个实施例,每个控件实例具有监视该控件实例的健康状况的实例检查器。主机检查器读取由控件实例的检查器更新的健康状况计数器。如果控件实例检查器检测到控件实例内的故障,或者如果控件实例终止,那么健康状况计数器不会更新。这被主机检查器检测到,主机检查器向控件集群的其余成员发送警报以指示控件集群的成员之一已停止运转。如果停止运转的成员已知是上一个领导者,那么剩余的成员可以发起选举。这确保快速启动领导权选举。
处置控件实例故障
如果控件实例没有收到来自领导者实例的心跳,那么发起HAMI选举以确定新的领导者。相比之下,当HAMI跟随者停止对HAMI领导者的请求做出响应时,该HAMI跟随者继续被视为HAMI总体的一部分。
当HAMI领导者收到更新请求时,以下事件发生:
·领导者尝试将请求持久化到法定数量的成员(包括他自己)
·一旦达到法定数量,更新请求就提交,即使跟随者没有做出响应
·领导者将继续向任何未响应的跟随者异步地发送日志记录
发送到未响应的跟随者的异步请求将不会对更新请求的时延产生任何影响,只要可以达到法定数量即可。
每当从总体中移除的跟随者能够再次加入总体时(在重启或网络分区修复等之后),该跟随者将开始接收日志记录(或日志记录的快照)以便赶上。此外,可以通过管理操作来将控件实例添加到控件集群或从控件集群中移除。
硬件概述
根据一个实施例,本文描述的技术由一个或多个专用计算设备来实现。专用计算设备可以是硬连线的以执行本技术,或者可以包括被永久性地编程以执行本技术的数字电子设备,诸如一个或多个专用集成电路(ASIC)或现场可编程门阵列(FPGA),或者可以包括被编程为根据固件、存储器、其它存储装置或组合中的程序指令执行本技术的一个或多个通用硬件处理器。这种专用计算设备还可以将定制的硬连线逻辑、ASIC或FPGA与定制的编程组合来实现本技术。专用计算设备可以是台式计算机系统、便携式计算机系统、手持式设备、联网设备或结合硬连线和/或程序逻辑来实现技术的任何其它设备。
例如,图11是图示可以在其上实现本发明的实施例的计算机系统1100的框图。计算机系统1100包括总线1102或用于传送信息的其它通信机制以及与总线1102耦合用于处理信息的硬件处理器1104。硬件处理器1104可以是例如通用微处理器。
计算机系统1100还包括耦合到总线1102用于存储信息和要由处理器1104执行的指令的主存储器1106,诸如随机存取存储器(RAM)或其它动态存储设备。主存储器1106也可以用于存储在要由处理器1104执行的指令的执行期间的临时变量或其它中间信息。当这种指令被存储在处理器1104可访问的非暂态存储介质中时,这种指令使计算机系统1100成为被定制用于执行指令中指定的操作的专用机器。
计算机系统1100还包括耦合到总线1102用于存储静态信息和处理器1104的指令的只读存储器(ROM)1108或其它静态存储设备。诸如磁盘或光盘之类的存储设备1110被提供并且被耦合到总线1102,以用于存储信息和指令。
计算机系统1100可以经由总线1102耦合到用于向计算机用户显示信息的显示器1112,诸如阴极射线管(CRT)。包括字母数字键和其它键的输入设备1114耦合到总线1102,用于将信息和命令选择传送到处理器1104。另一种类型的用户输入设备是光标控件1116,诸如鼠标、轨迹球或光标方向键,用于向处理器1104传送方向信息和命令选择并且用于控制显示器1112上的光标移动。这种输入设备通常具有两个轴(第一轴(例如,x)和第二轴(例如,y))上的两个自由度,以允许设备在平面中指定位置。
计算机系统1100可以使用定制的硬连线逻辑、一个或多个ASIC或FPGA、固件和/或程序逻辑来实现本文描述的技术,所述定制的硬连线逻辑、一个或多个ASIC或FPGA、固件和/或程序逻辑与计算机系统结合使计算机系统1100成为专用机器或将计算机系统1100编程为专用机器。根据一个实施例,本文的技术由计算机系统1100响应于处理器1104执行主存储器1106中包含的一条或多条指令的一个或多个序列而执行。这些指令可以从另一个存储介质(诸如存储设备1110)读取到主存储器1106中。在主存储器1106中包含的指令序列的执行使处理器1104执行本文描述的处理步骤。在替代实施例中,可以使用硬连线电路系统代替软件指令或与软件指令组合使用。
如本文使用的术语“存储介质”是指存储有使机器以特定方式操作的数据和/或指令的任何非暂态介质。这种存储介质可以包括非易失性介质和/或易失性介质。非易失性介质包括例如光盘或磁盘,或固态驱动器,诸如存储设备1110。易失性介质包括动态存储器,诸如主存储器1106。存储介质的常见形式包括例如软盘、柔性盘、硬盘、固态驱动器、磁带或任何其它磁性数据存储介质、CD-ROM、任何其它光学数据存储介质、具有孔模式的任何物理介质、RAM、PROM和EPROM、FLASH-EPROM、NVRAM、任何其它存储器芯片或盒式磁带。
存储介质与传输介质不同但可以与传输介质结合使用。传输介质参与在存储介质之间传递信息。例如,传输介质包括同轴电缆、铜线和光纤,包括包含有总线1102的电线。传输介质还可以采取声波或光波的形式,诸如在无线电波和红外线数据通信期间生成的这些。
各种形式的介质可以涉及将一条或多条指令的一个或多个序列携带到处理器1104以供执行。例如,指令最初可以在远程计算机的磁盘或固态驱动器上携带。远程计算机可以将指令加载到其动态存储器中,并使用调制解调器通过电话线发送指令。计算机系统1100本地的调制解调器可以在电话线上接收数据并使用红外线发射器将数据转换为红外线信号。红外线检测器可以接收红外线信号中携带的数据,并且适当的电路系统可以将数据放置在总线1102上。总线1102将数据携带到主存储器1106,处理器1104从主存储器1106中检索并执行指令。由主存储器1106接收的指令可以可选地在由处理器1104执行之前或之后存储在存储设备1110上。
计算机系统1100还包括耦合到总线1102的通信接口1118。通信接口1118提供耦合到网络链路1120的双向数据通信,其中网络链路1120连接到本地网络1122。例如,通信接口1118可以是综合业务数字网络(ISDN)卡、电缆调制解调器、卫星调制解调器、或向对应类型的电话线提供数据通信连接的调制解调器。作为另一个示例,通信接口1118可以是提供到兼容的局域网(LAN)的数据通信连接的LAN卡。也可以实现无线链路。在任何这种实现中,通信接口1118发送和接收携带表示各种类型信息的数字数据流的电信号、电磁信号或光信号。
网络链路1120通常通过一个或多个网络向其它数据设备提供数据通信。例如,网络链路1120可以通过本地网络1122提供到主计算机1124或到由互联网服务提供商(ISP)1126操作的数据设备的连接。ISP 1126又通过现在通常称为“互联网”1128的全球分组数据通信网络提供数据通信服务。本地网络1122和互联网1128都使用携带数字数据流的电信号、电磁信号或光信号。通过各种网络的信号以及在网络链路1120上并且通过通信接口1118的信号是传输介质的示例形式,这些信号将数字数据携带到计算机系统1100或携带来自计算机系统1100的数字数据。
计算机系统1100可以通过(一个或多个)网络、网络链路1120和通信接口1118发送消息和接收数据,包括程序代码。在互联网示例中,服务器1130可以通过互联网1128、ISP1126、本地网络1122和通信接口1118传输对于应用程序的所请求代码。
接收到的代码可以在它被接收时由处理器1104执行,和/或存储在存储设备1110或其它非易失性存储装置中以供以后执行。
云计算
术语“云计算”在本文中一般用于描述一种计算模型,该模型使得能够按需访问计算资源(诸如计算机网络、服务器、软件应用和服务)的共享池,并且允许以最少的管理工作或服务提供商交互来快速供应和释放资源。
云计算环境(有时称为云环境或云)可以以各种不同方式实现,以最好地满足不同的要求。例如,在公共云环境中,底层计算基础设施由组织拥有,该组织使其云服务可供其它组织或公众使用。相比之下,私有云环境一般仅供单个组织使用或在单个组织内使用。社区云旨在由社区内的几个组织共享;而混合云包括两种或更多种类型的云(例如,私有云、社区云或公共云),它们通过数据和应用可移植性绑定在一起。
一般而言,云计算模型使一些以前可以由组织自己的信息技术部门提供的职责能够在云环境中作为服务层交付,供消费者使用(根据云的公共/私有性质,或者在组织内部或者外部)。取决于特定的实施方式,由每个云服务层提供的或在其内部提供的组件或功能的精确定义可以有所不同,但常见的示例包括:软件即服务(SaaS),其中消费者使用在云基础设施上运行的软件应用,而SaaS提供者管理或控制底层云基础设施和应用。平台即服务(PaaS),其中消费者可以使用PaaS提供者支持的软件编程语言和开发工具来开发、部署和以其它方式控制他们自己的应用,而PaaS提供者管理或控制云环境的其它方面(即,运行时执行环境以下的所有内容)。基础设施即服务(IaaS),其中消费者可以在其中部署和运行任意软件应用,和/或供应处理、存储、网络和其它基本计算资源,而IaaS提供者管理或控制底层物理云基础设施(即,操作系统层以下的所有内容)。数据库即服务(DBaaS),其中消费者使用在云基础设施上运行的数据库服务器或数据库管理系统,而DbaaS提供者管理或控制底层云基础设施、应用和服务器,包括一个或多个数据库服务器。
在前面的说明书中,已经参考众多具体细节描述了本发明的实施例,这些细节可以在实施方式之间不同。因此,说明书和附图应被视为说明性而非限制性的。本发明范围的唯一和排他性指示,以及申请人意图作为本发明范围的内容,是以发布这种权利要求的具体形式从本申请发布的权利要求集合的字面和等同范围,包括任何后续更正。

Claims (16)

1.一种方法,包括:
在多个主机中的每个主机上,执行多个引擎实例中的一个或多个引擎实例;
其中所述多个主机中的每个主机是计算设备;
由所述多个引擎实例中的每个引擎实例管理对存储在持久存储装置上的数据的访问,该持久存储装置对于该引擎实例在其上执行的主机是本地的;
在所述多个主机之间建立邻居关系,其中所述邻居关系形成有向图,所述有向图初始地包括所述多个主机中的所有主机;
其中,在所述有向图内,每个主机具有一个或多个指定的邻居主机;
由每个主机执行监视该主机的所述一个或多个指定的邻居主机的健康状况的邻居监视器;以及
其中每个邻居监视器通过监视由所述一个或多个指定的邻居主机维护的计数器来监视所述一个或多个指定的邻居主机的健康状况;
其中特定邻居监视器在所述多个主机中的特定主机上执行;
其中每个主机上的所述一个或多个引擎实例负责改变该主机上的计数器。
2.如权利要求1所述的方法,还包括:
响应于所述特定邻居监视器确定特定邻居主机不健康:
所述特定邻居监视器将所述特定邻居主机的邻居主机建立作为所述特定邻居监视器的新邻居主机,以及
所述特定邻居监视器发起对所述新邻居主机的监视。
3.如权利要求1所述的方法,其中,监视所述计数器包括确定所述计数器是否正在改变。
4.如权利要求1所述的方法,其中,所述多个主机中的每个主机通过至少两个不同的网络连接到所述多个主机中的每个其他主机。
5.如权利要求1所述的方法,还包括:
在所述多个主机中的第一组主机上执行多个控制实例;
其中每个控制实例在所述第一组主机中的不同主机上执行;
其中所述多个控制实例维护指示所述多个主机之间的邻居关系的数据;
响应于所述特定邻居监视器确定所述特定主机的所述一个或多个指定的邻居主机当中的特定邻居主机不健康:
所述特定邻居监视器向所述多个控制实例中的控制实例传达所述特定邻居主机不健康。
6.如权利要求5所述的方法,其中:
所述多个控制实例包括:
被指定为领导者控制实例的特定控制实例,以及
一个或多个跟随者控制实例;
所述方法还包括:
所述领导者控制实例监视所述多个控制实例中的所有跟随者控制实例的健康状况;以及
所有跟随者控制实例监视所述领导者控制实例的健康状况。
7.如权利要求6所述的方法,还包括:
所述多个控制实例中的特定跟随者控制实例确定所述领导者控制实例不健康,以及
响应于确定所述领导者控制实例不健康,所述特定跟随者控制实例发起从跟随者控制实例当中选举新的领导者控制实例。
8.如权利要求6所述的方法,其中,在所述多个控制实例内,控制实例通过与其它控制实例交换心跳来监视其它控制实例的健康状况。
9.如权利要求6所述的方法,其中:
所述特定控制实例被指定为领导者持续达预定时间量;以及
在所述预定时间量之后,领导权自动传递到所述多个控制实例中的下一个控制实例。
10.如权利要求1所述的方法,其中,每个邻居监视器通过使用RDMA读取操作读取其一个或多个指定的邻居主机的计数器来确定由其一个或多个指定的邻居主机维护的计数器是否正在递增。
11.如权利要求1所述的方法,还包括:
在所述多个主机中的每个主机上执行主机监视器,该主机监视器监视在该主机上执行的引擎实例的健康状况;以及
响应于检测到其主机上的引擎实例的软件故障,所述主机监视器自动重新启动所述引擎实例。
12.如权利要求5所述的方法,其中:
所述多个引擎实例构成引擎实例集群;
所述多个控制实例维护指定所述引擎实例集群的配置的配置数据;
所述方法还包括:
在所述多个主机中的每个主机上执行主机监视器,该主机监视器监视在该主机上执行的引擎实例的健康状况;
其中特定主机监视器正在所述多个主机中的特定主机上执行;
响应于检测到其主机上的特定引擎实例不健康,所述特定主机监视器通知所述多个控制实例中的控制实例所述特定引擎实例不健康;以及
响应于被通知所述特定引擎实例不健康,所述控制实例更新所述配置数据以重新配置所述引擎实例集群以排除所述特定引擎实例。
13.如权利要求12所述的方法,其中,响应于被通知所述特定引擎实例不健康,所述控制实例向所有幸存的引擎实例发送通知以向所有幸存的引擎实例通知所述特定引擎实例从所述引擎实例集群被排除。
14.如权利要求5所述的方法,其中:
所述多个主机构成主机集群;
所述方法还包括,响应于所述特定邻居监视器向控制实例传达其指定的邻居主机不健康,所述控制实例发起调查以确定所述多个主机中的哪些主机不健康并且应当从所述主机集群被排除。
15.一种或多种存储指令的非暂态计算机可读介质,所述指令在由一个或多个计算设备执行时,使得执行如权利要求1-14中的任一项所述的方法。
16.一种系统,包括:
多个计算设备,每个计算设备具有一个或多个处理器;
所述多个计算设备能够访问一个或多个存储指令的非暂态计算机可读介质,所述指令在由所述多个计算设备执行时,使得执行如权利要求1-14中的任一项所述的方法。
CN202180070442.1A 2020-10-14 2021-10-06 在无共享分布式数据库中快速检测和修复故障的系统和方法 Active CN116529724B (zh)

Applications Claiming Priority (4)

Application Number Priority Date Filing Date Title
US17/070,277 2020-10-14
US17/123,405 US11392616B2 (en) 2020-10-14 2020-12-16 System and method for rapid fault detection and repair in a shared nothing distributed database
US17/123,405 2020-12-16
PCT/US2021/053820 WO2022081395A1 (en) 2020-10-14 2021-10-06 System and method for rapid fault detection and repair in a shared nothing distributed database

Publications (2)

Publication Number Publication Date
CN116529724A true CN116529724A (zh) 2023-08-01
CN116529724B CN116529724B (zh) 2024-04-12

Family

ID=87398047

Family Applications (1)

Application Number Title Priority Date Filing Date
CN202180070442.1A Active CN116529724B (zh) 2020-10-14 2021-10-06 在无共享分布式数据库中快速检测和修复故障的系统和方法

Country Status (1)

Country Link
CN (1) CN116529724B (zh)

Citations (4)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
CN102667761A (zh) * 2009-06-19 2012-09-12 布雷克公司 可扩展的集群数据库
CN104769555A (zh) * 2012-06-18 2015-07-08 艾克特菲欧有限公司 增强型数据管理虚拟化系统
US20190236485A1 (en) * 2018-01-26 2019-08-01 Cisco Technology, Inc. Orchestration system for distributed machine learning engines
US20200012534A1 (en) * 2018-07-04 2020-01-09 Graphcore Limited Streaming engine

Patent Citations (4)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
CN102667761A (zh) * 2009-06-19 2012-09-12 布雷克公司 可扩展的集群数据库
CN104769555A (zh) * 2012-06-18 2015-07-08 艾克特菲欧有限公司 增强型数据管理虚拟化系统
US20190236485A1 (en) * 2018-01-26 2019-08-01 Cisco Technology, Inc. Orchestration system for distributed machine learning engines
US20200012534A1 (en) * 2018-07-04 2020-01-09 Graphcore Limited Streaming engine

Non-Patent Citations (1)

* Cited by examiner, † Cited by third party
Title
ORACLE: "Oracle Database Using Oracle Sharding 18c", ORACLE, pages 1 - 230 *

Also Published As

Publication number Publication date
CN116529724B (zh) 2024-04-12

Similar Documents

Publication Publication Date Title
US11514029B2 (en) System and method for high performance multi-statement interactive transactions with snapshot isolation in a scale-out database
Baker et al. Megastore: Providing scalable, highly available storage for interactive services.
US11550771B2 (en) System and method for an ultra highly available, high performance, persistent memory optimized, scale-out database
EP2673711B1 (en) Method and system for reducing write latency for database logging utilizing multiple storage devices
US11392616B2 (en) System and method for rapid fault detection and repair in a shared nothing distributed database
US8868504B2 (en) Database system with active standby and nodes
CA2550003C (en) Geographically distributed clusters
US11599421B2 (en) System and method for transaction continuity across failures in a scale-out database
CA2550614C (en) Cluster database with remote data mirroring
JP2014532919A (ja) オンライントランザクション処理
US20160292049A1 (en) Data recovery for a relational database management system instance in a heterogeneous database system
US9703634B2 (en) Data recovery for a compute node in a heterogeneous database system
CN116529724B (zh) 在无共享分布式数据库中快速检测和修复故障的系统和方法
US20230281190A1 (en) System and method for transaction continuity across failures in a scale-out database
Sridhar Active Replication in AsterixDB
Manchale Sridhar Active Replication in AsterixDB

Legal Events

Date Code Title Description
PB01 Publication
PB01 Publication
SE01 Entry into force of request for substantive examination
SE01 Entry into force of request for substantive examination
GR01 Patent grant