可序列化的分布式事务为设计分布式系统(如对象存储和联机事务处理(OLTP)系统)提供了强大的编程抽象。尽管这个领域的早期工作为了提高性能而牺牲了强大的事务语义,但是最近的系统已经表明事务可以在数据中心中快速执行。这其中关键的推动者是高速网络和轻量级网络栈(即绕过内核)。此外,这些系统利用了远程直接内存访问(RDMA)的低延迟和CPU效率。这些系统中的一个共同的线程是,它们广泛使用了绕过远程CPU的单边RDMA操作。这个决定背后的意图是利用单边RDMA的能力来节省远程CPU周期。
在本文中,我们探讨了单边RDMA是否不是设计事务处理系统的最佳选择。首先,单边RDMA操作与对远程数据存储的有效事务访问所需的功能之间存在差距。单边RDMA只提供远程读、写和原子操作,而访问数据存储通常涉及遍历数据结构,如哈希表和b树。通常,这些结构包括用于快速查找的索引和实际数据,需要两次或多次RDMA读取才能访问数据。这将导致更低的吞吐量和更高的延迟,并减少来自远程CPU旁路的净CPU节省。克服这种差距的关键技术是使数据结构扁平化,方法是忽略索引,将数据与索引合并,或者在所有服务器上缓存索引。这些变体在通用性和系统性能方面都有相关的成本。第二,当前单边RDMA实现的面向连接的特性通常要求CPU核心共享本地NIC队列对以实现可伸缩性,这是降低本地每核RDMA吞吐量以及远程CPU旁路净效益的若干因素。
我们展示了一个更好的事务原语:基于双边不可靠数据报消息的远程过程调用(RPCs)。RPCs涉及到消息处理中的远程CPU,并且比单侧RDMA更灵活,允许在一次往返中访问数据。然而,以前通过RDMA实现的RPC要么性能很差(例如,比FaRM中使用的单边RDMA差4倍),要么是专用的(例如,HERD的RPCs为一对一通信提供高性能,其中一台服务器处理来自许多客户端的RPCs)。这项工作的一个关键贡献是FaSST RPCs:一个快速、可伸缩和高效CPU的all-to-all RPC系统。这是通过使用RDMA的数据报传输实现的,它提供可伸缩性,并允许“Doorbell batching”,通过减少CPU发起的PCIe总线事务来节省CPU周期。我们表明,FaSST RPCs提供(1)比FaRM‘s RPCs高8倍的吞吐量,和13.9倍的 CPU效率(4.5节),(2)与单边READs相比,CPU效率提高1.7-2.15倍,或吞吐量更高,具体取决于READs是否扩展到具有超过几十个节点的集群(3.3节)。
使用不可靠的传输层需要处理数据包丢失。然而,在InfiniBand等RDMA网络中,数据包丢失极其罕见,因为其底层链路层提供了可靠性。在我们的实验中,我们没有观察到任何丢失的数据包,实验在一个实际的InfiniBand集群上传输了超过50PB的网络数据,该集群最多有69个节点。然而,数据包丢失可能发生在硬件故障期间,以及链路层可靠性协议的极端情况下。我们使用RPC请求程序触发的粗粒度超时检测这些损失,并描述如何以类似于传统机器故障的方式处理这些损失。
FaSST是一种基于FaSST RPCs的新型事务处理系统。它使用乐观并发控制、两阶段提交和主备份复制。我们当前的实现支持基于MICA的无序键值存储上的事务,并将8字节的键映射到不透明的对象。我们使用三个工作负载来评估FaSST:一个事务对象存储、一个以读取为主的OLTP基准测试,称为TATP,和一个写密集型OLTP基准测试,称为Small-Bank。FaSST与已公布的per-machine吞吐量进行了比较。在TATP上,当使用接近一半的硬件(NIC和CPU)资源时,FaSST的性能比FaRM高出1.87倍。在SmallBank上,使用类似的硬件,FaSST的性能在无需假设数据位置的情况下比DrTM+R高出1.68倍。
本节概述了我们使用FaSST所针对的环境。FaSST的目标是在一个数据中心内提供分布式事务,其中这个系统实例可以扩展到几百个节点。系统中的每个节点负责基于主键对数据进行分区,节点在对称模型中运行,每个节点同时充当客户机和服务器。对于具有良好数据局部性的工作负载(例如,只访问一个分区中的数据的事务),对称模型可以通过将事务与它们访问的数据放在一起来实现更高的性能。
FaSST的目标是高速、低延迟的键值事务处理,在普通OLTP基准测试上(短事务最多只有几十个键)实现吞吐量为每秒几百万个事务,平均延迟约为100微秒。要达到这种性能,需要内存中的事务处理和快速的用户空间网络I/O(即轮询),内核网络堆栈或中断的开销是不可接受的。我们假设商用网络设备:每个端口的带宽为10-100 Gbps,端到端延迟约为2µs。
要使数据跨机器故障持久,需要将事务记录到持久存储中,并且快速恢复需要维护数据存储的多个副本。在事务的关键路径上保持磁盘或ssd等持久性存储会限制性能。与最近的工作类似,FaSST假设事务处理节点配备了电池支持的DRAM,尽管未来的NVRAM技术,如果足够快,也可以工作。
最后,FaSST使用主备份复制来实现容错。我们假设故障将使用一个独立的容错配置管理器来处理,该配置管理器位于关键路径(Vertical Paxos模型)之外,类似于最近基于RDMA的分布式事务的工作。我们目前还没有实现这样的配置管理器。
RDMA是一个网络概念,有几种实现。虚拟接口体系结构(VIA)是用户级零拷贝网络的流行模型,并构成了当前常见的RDMA实现的基础,如InfiniBand、RoCE(通过聚合以太网的RDMA)和iWARP (internet Wide Area RDMA Protocol)。VIA NICs为用户进程提供网络虚拟接口。VIA基本上是面向连接的:必须在允许通信之前在一对虚拟接口之间建立连接。VIA架构师做出这个设计决策是为了简化VIA实现并减少延迟。本文的讨论以及我们的一些贡献是针对基于VIA的RDMA实现的;我们将在7.1节中讨论其他非商业RDMA实现。
在基于via的RDMA实现中,虚拟接口称为队列对(QPs),每个队列由一个发送队列和一个接收队列组成。进程通过将verbs发布到这些队列来访问QPs。双向verbs——SEND和RECV需要发送方和接收方的CPU参与:SEND生成一条消息,该消息的数据被写入到由接收方在预发布的RECV中指定的buer中。单向verbs(读、写和原子操作)绕过远程CPU直接操作远程内存。
RDMA传输可以是连接的,也可以是无连接的。面向连接的传输在两个队列对之间提供一对一的通信:要与N台远程机器通信,线程必须创建N个QPs。这些传输提供单边RDMA操作和端到端可靠性,但没有很好地扩展到大型集群。这是因为NICs用于缓存QP状态的内存有限,如果使用过多的QPs超过了这个内存大小,就会导致缓存抖动。无连接(数据报)传输是面向连接的VIA的扩展,支持的特性比面向连接传输少:它们不提供单边RDMA操作或端到端可靠性。但是,它们允许单个QP与多个其他QP通信,并且比面向连接传输具有更好的可伸缩性,因为每个线程只需要一个QP。
RDMA传输可以是可靠的,也可以是不可靠的,尽管当前的普通NICs不提供可靠的数据报传输。可靠的传输提供消息的有序传递,并在发生故障时返回错误。不可靠的传输通过避免确认包来实现更高的性能,但不提供可靠性保证或在网络故障时返回错误。现代高速网络,包括Mellanox的InfiniBand和英特尔的OmniPath,也提供传输层以下的可靠性。他们的链路层使用流量控制来防止基于拥塞的损失,并使用重新传输来防止基于比特错误的损失。InfiniBand的物理层使用正向纠错来修复大多数位错误,而这些位错误本身并不常见。例如,用于我们集群的InfiniBand电缆的比特误码率小于10-15。因此,即使是缺乏端到端可靠性的不可靠传输,也很少丢失包:使用不可靠数据传输50PB左右,我们没有丢失任何包(第3.4节)。请注意,这些网络中的链路层流控制可能会在极少数情况下导致拥塞崩溃,导致低吞吐量,但不会导致数据包丢失。
目前的RDMA实现提供了三种主要传输方式:可靠连接(RC)、不可靠连接(UC)和不可靠数据报(UD)。表1显示了每个传输的实现所支持的verbs子集。并非所有传输层都提供所有类型的verbs,因此选择一个verb意味着接受可用传输的限制。注意,只有连接的传输提供单向verbs,这限制了使用这些verbs的设计的可伸缩性。
现在,我们将描述使用双边数据报verbs构建RPC层的决定背后的基本原理。我们证明RPC是:
最近关于在支持RDMA的网络上设计分布式数据存储的工作主要集中于如何使用单边RDMA verbs。在这些设计中,客户机使用一个或多个READs操作访问服务器内存中的远程数据结构,类似于访问本地内存中的数据。各种优化有助于减少所需的读取次数;我们将在下面讨论这两种优化及其局限性。
Value-in-index: FaRM使用一个专门的索引来存储与其索引条目相邻的数据,从而允许使用这些索引来读取数据,从而平均在一次READ中提供哈希表访问。然而,这样做会将READ的大小放大6 - 8倍,从而降低吞吐量。这个结果强调了比较网络原语的应用程序级功能的重要性:尽管微基准测试表明READs操作可以优于类似大小的RPCs,但是由于它们的单侧性质,READs操作需要额外的网络流量和/或往返,从而将天平向另一个方向倾斜。
Caching the index: DrTM在集群中的所有服务器上缓存其哈希表的索引,允许单边READ GETs; FaRM 对其B树采用了类似的方法。虽然这种方法在工作负载具有较高的局部性或倾斜度时工作得很好,但它通常不工作,因为索引可能很大:有报告指出在单节点事务处理系统中,索引占流行OLTP基准测试内存的35%以上;在我们实现分布式事务处理基准测试时,这个百分比与此类似。在这种情况下,即使缓存10%的索引,也需要每台机器为索引贡献3.5%的集群总内存容量,如果集群包含100个节点,100/3.5=29个节点,这是不可能的。Cell B-Tree将B-Tree节点缓存在叶子节点之上4层,以节省内存和减少搅动,但是当客户机使用READs访问b树时,需要多次往返(大约4次)。
RPC允许使用两条消息访问分区数据存储:请求和回复。它们不需要将消息大小放大、多次往返或缓存。基于RPC的编程的简单性降低了利用现代快速网络进行事务处理所需的软件复杂性:要实现分区的分布式数据存储,用户只需为单节点数据存储编写简短的RPC处理程序。这种方法消除了基于单向RDMA方法所需的软件复杂性。例如,在本文中,我们使用MICA的哈希表设计来实现无序键值存储。为了支持分布式事务,我们只对MICA代码库做了很小的修改。在未来,我们计划使用Masstree作为有序存储。
数据报传输允许每个CPU核心创建一个可以与所有远程核心通信的数据报QP。由于QPs的数量相对较少(与内核的数量相同),因此可以在不溢出NIC缓存的情况下为每个内核提供对QPs的独占访问。但是,通过面向连接传输提供对QPs的独占访问是不可伸缩的:在有N台机器和每台机器T个线程的集群中,这样做需要在每台机器上有N*T个QPs,这可能不适合NIC的队列对缓存。线程可以共享QPs来减少QP内存占用。共享QPs会降低CPU效率,因为线程争用锁,而QP缓冲区的高速缓存线在它们的CPU内核之间来回跳转。
其效果可能非常显著:在我们的实验中,QP共享将单边READ的每核吞吐量减少了5.4倍(第3.3.2节)。类似地,使用单边WRITE和QP共享的FaRM的RPC在每台机器每秒500万个请求(Mrps)时CPU会成为瓶颈。但是,我们基于数据报的RPC不需要QP共享,并且可以达到40.9 Mrps / machine,即使这样,它们也只会受到NIC的限制,而不是CPU(第3.3.1节)。
与面向连接传输相比,数据报传输除了可扩展性之外还具有第二个重要优势:Doorbell batching,减少CPU使用。我们在这里以简化形式描述此功能;我们早期的论文中提供了详细的讨论。 用户通过PCIe总线将post操作写入NIC上的per-QP Doorbell寄存器,并指定该QP上的新操作数量,从而处理到NIC上的post操作。对于CPU来说,这种写操作开销相对比较大,因为它需要刷新写缓冲区,并使用内存屏障进行排序。然而,在事务系统中,应用程序可以通过一次发出多个RDMA工作请求来分摊此成本。例如,读取或验证多密钥事务的多个密钥,或向密钥的副本发送更新消息。对于数据报QP,该流程只需要按一次门铃,而不管该批处理中的各个消息目的地。然而,对于已连接的QPs,该过程必须按多个门铃——与批次中出现的目的地数量相同。注意,门铃批处理不会在RDMA层合并包(即,它不会将多个应用程序级请求放在一个RDMA包中);门铃批量处理也不会增加延迟,因为我们是投机取巧地这么做的(我们不会等待一批消息累积)。
最近的两个项目研究了RPC和单边RDMA的相对性能。在多个客户机向一台服务器发送请求的非对称设置中,HERD显示RPCs的执行与READs类似。在HERD中,客户机通过UC上的WRITEs向服务器发送请求;服务器通过UD的SENDs发送响应。这种方法可以很好地适应客户机数量,因为服务器上的活跃队列对数量很少。服务器的UC QPs是被动的,因为服务器的CPU不访问它们;这些被动QPs消耗很少NIC中的内存。活跃的UD QPs数量很少。
不幸的是,正如Dragojevic等人指出的,在分布式事务所需的对称设置中(每个机器都发出请求和响应),HERD的RPC设计伸缩性不好。这个场景需要每个节点上有许多活约的UC QPs来发送请求。在FaRM的实验中,在对称设置下的READs性能比其RPCs高出4倍。
我们现在给出的实验结果表明,对于分布式事务,FaSST的RPCs是比单边RDMA更好的选择。第四章详细讨论了我们RPC系统的设计与实现;在这里,我们使用它来实现基本的RPCs,其中请求和响应都是固定大小的buffer。我们首先在小集群上比较RPCs和单边READs的原始吞吐量,其中READs不要求QP共享。接下来,我们将比较它们在更现实的中型集群上的性能。
Clusters used: 为了表明我们的结果适用于一系列RDMA硬件,我们使用了两个具有不同NICs和CPU处理能力的集群(表2)。集群以其NIC的首字母命名。CX3是一个共有192个节点的共享Emulab集群;根据节点的可用性,我们的实验使用了多达69个节点。CX3节点具有ConnectX-3 NIC和具有8个内核的Intel SandyBridge CPU。CIB是一个拥有11个节点的私有集群。CIB节点有一个更强大的Connect-IB NIC,它提供的带宽比ConnectX-3 NIC多2倍,消息速率大约高4倍。他们也有一个更强大的,14核Intel Haswell CPU。
Experiment setup: 我们使用一组对称设置的机器,即,每台机器向其他每台机器发出请求(RPC请求或READs)。对于没有QP共享的READs操作,每个线程创建的RC QPs数量与机器数量相同,并向随机选择的机器发出读操作。我们对两个请求批处理大小(1和11)的RPC性能进行了评估,以显示按Doorbell batching请求的效果。我们通过将每批请求发送到不同的机器来防止RPC请求合并(第4节);这将我们在CIB上的最大批大小限制为11。
我们比较不同响应大小的RPC和READ性能;对于RPCs,请求大小固定为32字节,这对于从FaSST的数据存储中读取数据很有帮助。我们报告每台机器每秒数百万个请求(Mrps/machine)。注意,对于RPCs,每台机器的CPU还为来自其他机器的请求提供响应,因此一台机器发送的消息数量大约是我们报告的请求率的两倍。结果表明:
不可靠的传输不提供可靠的包交付,这可能会引入编程复杂性和/或有性能影响(例如,增加CPU使用),因为可靠性机制(如超时和重传)必须在软件RPC层或应用程序中实现。
为了理解FaSST处理潜在包丢失的方法,我们进行了两个观察。首先,我们注意到事务处理系统通常包含处理节点故障的重新配置机制。重新配置包括选择性地暂停正在进行的事务、通知节点新的集群成员关系、重放事务日志和重新复制丢失的数据。在FaSST中,我们假设了一个标准的重构机制;我们还没有实现这样的机制,因为本文的贡献不在这方面。我们希望,与DrTM+R类似,FaRM的恢复协议可以适用于FaSST。
第二个观察结果是,在正常运行下,现代RDMA支持的网络中丢包的情况极为罕见:在我们的实验中(下面讨论),我们观察到传输的数据超过50PB时,丢包率为零。在网络硬件故障和链路/物理层可靠性协议的极端情况下,数据包可能会丢失。FaSST的RPC层使用RPC请求者维护的粗粒度超时来检测这些损失(第4.3节)。
根据这两个的观察,我们认为在FaSST中可以接受的一个解决处理包丢失的方案就是简单地重新启动受丢失的RPC包影响的两个FaSST进程中的一个,允许重新配置机制为受影响的事务做出提交决策。我们将在5.1节中更详细地讨论这一点。
FaSST的RPCs是为使用小型(100字节)对象和几十个键的事务工作负载而设计的。这一层抽象了RDMA的细节,并被更高层的系统使用,比如我们的事务处理系统。FaSST RPCs的关键特性包括与协作程序集成以隐藏特定的网络延迟,以及优化,如Doorbell batching和消息合并。
RDMA网络延迟在负载下约为10µs,这是远远高于我们的应用程序所花费的计算和本地数据存储访问的时间。在等待RPC响应时,不要阻塞线程,这一点非常重要。与Grappa类似,FaSST使用协程(协作多任务处理)来隐藏网络延迟:协程在初始化网络I/O之后产生,允许其他协程在RPC运行时执行有用的工作。我们的实验表明,每个线程有少量(~ 20)的协程可以有效地隐藏延迟,因此FaSST使用Boost c++库中的标准协程,而不是针对有数千个协程的用例进行优化的Grappa的协程。我们测量了在协程之间切换的CPU开销为13 - 20ns。
在FaSST中,每个线程创建一个RPC端点,该端点由线程生成的协程共享。一个协同程序作为master;剩下的是worker。worker只运行应用程序逻辑,并向远程计算机发出RPC请求,在远程计算机上,处理请求的线程的master处理这些请求。Master轮询网络,以识别任何新到达的请求或响应包。Master计算并发送请求包的响应。它缓冲每个worker收到的响应包,直到所有需要的响应都可用为止,然后调用worker。
Worker根据应用程序逻辑允许的内容,对批量请求(>=1)进行操作。Worker首先创建新请求,而不执行网络I/O。对于每个请求,它指定请求类型(例如,访问特定的数据库表、事务日志记录等)和目标机器的ID。创建一批请求之后,worker调用RPC函数来发送请求消息。注意,RPC请求指定目标机,而不是目标线程;FaSST chooses the destination thread as the local thread’s ID–based peer on the destination machine. Restricting RPC communication to between thread peers improves FaSST’s scalability by reducing the number of coroutines that can send requests to a thread (Section 4.4)。(FaSST选择目标线程作为目标机器上基于ID的本地线程对等点。通过减少可以向线程发送请求的协程的数量(第4.4节),将RPC通信限制在线程之间可以提高FaSST的可伸缩性。)
每个线程上的master检测由其worker发出的RPCs的数据包丢失。Master通过计算收到的响应数来跟踪每个worker的进度。当且仅当worker的RPC包(请求或响应)中的一个丢失时,worker的进度计数器将停止工作:如果一个包丢失,master将永远不会接收到worker的所有响应;它再也不会调用worker,从而阻止它发出新的请求并接收更多的响应。如果没有包丢失,那么master最终将接收worker的所有响应。Worker被调用并发出新的请求——我们不允许worker在不发出RPCs请求的情况下让步于master。
如果一个worker的计数器在超时秒内没有更改,则master假定worker遭受了包丢失。一旦怀疑有损失,主进程就会杀死机器上的FaSST进程(第5.1节)。注意,在检测到包丢失之前,包丢失只影响一个worker的进程,即,其他worker可以成功提交事务,直到检测到丢失为止。这允许我们在不影响FaSST可用性的情况下使用较大的超时值。
我们当前将超时设置为1秒。在我们对50多个节点的实验中,我们没有观察到这个超时值的假阳性(false positive)。我们观察到,在超时值(如100 ms)明显更小的情况下,出现了误报。例如,如果处理RPCs响应的线程被抢占了,就会发生这种情况。
尽管FaSST的目标是提供通用的RPCs,,但我们目前不支持要求消息大于网络MTU (InfiniBand网络上的4 KB)的工作负载。这些工作负载可能会受到网络带宽的限制,不论是基本RPC还是单向RDMA设计的,从而达到类似的性能。如果需要,可以用几种性能中立的方法来解决这个限制。
FaSST还将每个协同程序限制为每批每台目标机的一个消息;然而,消息可以包含多个合并的请求。为了使RECV队列保持较小,以便它们可以被NIC缓存,需要这个限制。考虑一个有N个节点的集群,每个节点有T个线程,每个线程有c个协程。对于给定的线程,有N个对等线程和N*c协程可以向其发送请求。在任何时候,每个线程都必须在其RECV队列中提供与可以发送给它的请求数量相同的RECVs。允许每个目标机器上的每个协程m个消息需要维护每个RECV队列的(N cm)个RECVs 。在N = 100、c = 20和T = 14的相当大的集群中,每台机器上需要14个大小为2000m的RECV队列。对于我们的工作负载,m = 1就足够了,并且在我们的实验中运行得很好,但是m值的显著增大会导致NIC缓存抖动,从而降低RPC性能。
支持更大的集群可能需要减少RECV队列大小。这可以通过将允许从本地线程到特定远程机器的请求数量从c减少到更小的数量来实现;如果远程机器的线程预算暂时耗尽,协程将产生让步。在没有高歪斜的情况下,这对于大型集群和工作负载非常有效,在这种情况下,多个协程向同一台远程机器发送请求的概率很小。
我们在3.3节中指出,FaSST RPCs提供了良好的per-NIC吞吐量。现在,我们展示了它们还提供了良好的单核吞吐量。为了测量每个核心的吞吐量,我们在每台机器上运行一个线程,每个线程运行20个协程,并使用32字节的RPCs.。我们使用CIB上所有可用的11台机器;我们在CX3上使用11台机器进行比较。我们使用多个请求批大小来评估RPC性能。为了防止RPC层合并请求,我们为批处理中的每个请求选择不同的机器。
对于RPC基线,我们使用一个请求批处理大小,并禁用响应批处理。然后,我们依次启用请求批处理、廉价的RECV发布和响应批处理优化。
即使没有任何优化,FaSST RPCs比共享QP的READs具有更好的CPU效率:我们的基线达到2.6Mrps,而READs在3个或更过线程共享QP的情况下实现2Mrps(图3)。当请求批大小为3并启用所有的优化,FaSST RPCs实现4 Mrps-高于READs2倍。每批一个请求的RPC吞吐量峰值为3.4 Mrps(未显示)。
每批11个请求,FaSST RPCs实现4.3 Mrps。按照这个请求速率,每个CPU核心平均每秒发出1720万个verbs:430万个SENDS用于请求和响应,860万个用于RECVs。相对于单边READs(实现每秒200万个verbs),这种巨大的优势来自FaSST使用的数据报传输,它允许独占访问QPs和门铃批处理。
FaSST在分区的分布式数据存储上为事务提供了序列化和持久性。FaSST的数据存储将8字节的键映射到不透明的应用程序级对象。每个键都与一个8字节的头相关联,头由一个锁位和一个63位的版本号组成。头部用于并发控制和在恢复期间对提交日志记录进行排序。几个键可以映射到同一个标题。
我们实现了基于MICA的无序键值存储的事务。键值存储使用由关联桶(图5)和多个(7-15)插槽组成的哈希表来存储键值项。每个键映射到一个主桶。如果映射到主桶的键数超过了桶的容量,则主桶将动态链接到溢出桶链。存储在主存储桶中的所有键的头部及其链接的溢出存储桶都保留在主存储桶中。
在FaSST中,worker运行事务逻辑并充当事务协调器。FaSST的事务协议受到FaRM的启发,为了简单起见做了一些修改。FaSST使用乐观并发控制和两阶段提交来实现分布式原子提交,并使用主备份复制来支持高可用性。为了简单起见,我们使用了两阶段提交的Coordinator Log的变体。图6总结了FaSST的事务协议。我们将在下面详细讨论协议的各个阶段。所有消息都使用FaSST RPCs发送。我们分别用R(读集)和W(写集)表示事务读取和写入密钥集。我们假设事务首先读取它写的键。
目前,FaSST实现提供了序列化和持久性,但没有提供高可用性。与以前的单节点事务系统类似,我们实现了正常情况下的数据路径(日志记录和复制),使快速恢复成为可能,但是我们没有实现从机器故障中恢复的实际逻辑。我们假设FaRM用于检测和从机器故障中恢复的机制(如租约、集群成员重新配置、日志重播和丢失数据的重新复制)可以适用于FaSST;我们将在下面讨论如何处理包丢失。注意,我们的实现对包重排序不敏感,因为每个RPC消息都小于网络的MTU。
通过杀死检测到丢失RPC包的机器上的FaSST进程,我们将包丢失转换为机器故障(第4.3节)。受丢失包影响的事务在检测到终止的FaSST进程之前不会取得进展(例如,通过租约);然后事务的提交/中止决策将由恢复机制处理。这个基本方案可以改进(例如,可以重用受害节点以避免数据重复,因为它不需要重新引导),但这不是我们工作的重点。
在第3.4节中,我们测量了我们的网络在小于50PB数据的情况下的丢包率。由于我们实际上没有丢失包,所以实际的损失率可能要低得多,但是我们使用这个上限率进行大致的可用性计算。、
在一个100个节点的集群中,每个节点配备2x56 Gbps InfiniBand,在全双工带宽下传输数据,大约5小时内传输50PB。因此,包丢失将转化为每天少于5个机器故障。假设每个故障导致的停机时间为50ms,就像在FaRM中一样,FaSST将实现five-nines可用性。
我们现在讨论FaSST事务实现的细节。目前,FaSST提供8字节密钥和不透明对象上的事务,这些事务的大小最多为4060字节。值大小受网络的MTU(4096字节)和提交记录头开销(36字节)的限制。为了扩展分布式事务的单节点数据存储,FaSST用户为预定义的键值请求(例如,get、lock、put和delete)编写RPC请求处理程序。这可能需要更改单节点数据存储,比如支持版本号。用户通过为每个表分配唯一的RPC请求类型,向RPC层注册数据库表及其各自的处理程序;RPC子系统在接收具有表类型的请求时调用表的处理程序。
数据存储必须支持来自节点中的所有线程的并发本地读写访问。另一种设计是为每个线程创建独占数据存储分区,而不是像FaSST中那样为每台机器创建分区。正如前面的工作所示,这种替代设计对于本地数据存储访问更快,因为线程不需要使用本地并发控制(例如,本地锁)来访问它们的独占分区。然而,当用于分布式事务时,它需要RPC子系统支持线程之间的all-to-all通信,这通过放大所需的RECV队列大小完成,降低了可伸缩性(第4.4节)。我们选择牺牲小集群上更高的CPU效率来满足更迫切的需求:集群级的可伸缩性。
用户使用以下API在工作协同程序中编写应用程序级事务逻辑。
**AddToReadSet(K, *V)和AddToWriteSet(K, *V, mode)**分别为读写获取密钥K。对于写集键,写模式是插入、更新或删除。当协程从Execute(见下面)返回key K的值后,key K的值在buffer V中可用。此时,应用程序的事务逻辑可以修改V,将写集键修改为它希望提交的值。
**Execute()**发送事务协议的执行阶段RPCs。调用Execute将挂起worker协程,直到所有响应都可用为止。注意,上面的AddToReadSet和AddToWriteSet函数不会立即生成网络消息:请求将被缓冲,直到调用Execute。这允许RPC层通过一个门铃发送所有请求,并合并发送到同一台远程机器的请求。在添加更多键之后,应用程序可以在一个事务中多次调用Execute。这允许事务根据以前获取的密钥选择新的密钥。
如果读或写集键被锁定,则执行失败。在这种情况下,事务层将失败返回给应用程序,然后应用程序必须调用Abort。
**Commit()**运行提交协议,包括验证、日志记录和复制,并返回提交状态。**Abort()**为写集键发送解锁消息。
略。
略。
FaSST是一个高性能、可伸缩的分布式内存事务处理系统,它提供了序列化和持久性。FaSST使用FaSST RPC实现其性能,FaSST RPC是一种新的RPC设计,专门针对现代RDMA硬件的特性,使用了双边verbs和数据报传输。它拒绝了RDMA-CPU旁路的一个最吸引人的特性,即保持低通信开销和简单快速的系统设计。这一组合使得FaSST能够以更少的资源和更少的工作负载假设,将最近基于RDMA的事务系统的性能提高1.68x-1.87x。最后,我们首次大规模研究了无限带宽网络的可靠性,证明了这种网络中数据包丢失的罕见性。
FaSST: Fast, Scalable and Simple Distributed Transactions with Two-Sided (RDMA) Datagram RPCs