ZooKeeper: Wait-free coordination for Internet-scale systems

ZooKeeper: Wait-free coordination for Internet-scale systems

本文描述了一种分布式应用程序进程协调服务——ZooKeeper。由于ZooKeeper是关键基础设施的一部分,ZooKeeper的目标是提供一个简单的高性能内核,用于在客户端构建更复杂的协调原语。它将来自组消息传递、共享寄存器和分布式锁服务的元素合并到一个复制的集中服务中。ZooKeeper公开的接口具有共享寄存器的免等待特性,并具有类似于分布式文件系统缓存失效的事件驱动机制,从而提供了一个简单而强大的协调服务。

ZooKeeper接口可以实现高性能的服务实现。除了无等待属性外,ZooKeeper还为每个客户端提供了请求FIFO执行的保证,以及所有改变ZooKeeper状态的请求的线性化。这些设计决策允许实现一个高性能处理管道,本地服务器可以满足读请求。我们展示了在2:1到100:1的读写比例下,ZooKeeper每秒可以处理数万到数十万的事务。这种性能允许ZooKeeper被客户端应用程序广泛使用。

1 Introduction

大规模分布式应用程序需要不同形式的协调。构型是最基本的协调形式之一。在其最简单的形式中,配置只是系统过程的操作参数列表,而更复杂的系统具有动态配置参数。在分布式系统中,组成员和leader选举也很常见:流程通常需要知道其他哪些流程是活的,以及这些流程负责什么。锁构成了一个强大的协调原语实现对关键资源的互斥访问。

协调的一种方法是为每一种不同的协调需要开发服务。例如,Amazon简单队列服务[3]特别关注排队。其他服务还专门为领导人选举[25]和配置[27]开发。实现更强大原语的服务可以用来实现不那么强大的原语。例如,Chubby[6]是一个具有强同步保证的锁定服务。锁可以用来实现领袖选举、组成员等。

在设计协调服务时,我们不再在服务器端实现特定的原语,而是选择公开一个API,使应用程序开发人员能够实现他们自己的原语。这样的选择导致了一个协调内核的实现,该内核支持新的原语,而不需要更改服务核心。这种方法支持适应应用程序需求的多种形式的协调,而不是将开发人员限制在一组固定的原语中。

在设计ZooKeeper的API时,我们放弃了阻塞原语,比如锁。阻塞协调服务的原语可能会导致慢速或故障的客户端,从而对更快的客户端性能产生负面影响。如果处理请求依赖于其他客户机的响应和故障检测,服务本身的实现就会变得更加复杂。因此,我们的系统Zookeeper实现了一个API,该API操作简单的waitfree数据对象,这些对象按照文件系统中的层次结构组织。事实上,ZooKeeper的API类似于任何其他文件系统的API,如果只看API签名,ZooKeeper看起来就像Chubby,没有锁方法open和close。然而,实现无等待的数据对象,使ZooKeeper与基于锁等阻塞原语的系统有很大区别

我们还必须为运营提供秩序保障。特别是,我们已经发现,保证所有操作的FIFO客户端顺序和线性化的写操作都可以实现服务的高效实现,这就足以实现我们的应用程序感兴趣的协调原语。事实上,我们可以用我们的API实现任何数量的进程的共识,并且根据Herlihy的层次结构,ZooKeeper实现了一个通用对象[14]。

ZooKeeper服务由一组使用复制实现高可用性和性能的服务器组成。它的高性能使包含大量进程的应用程序能够使用这种协调内核来管理协调的所有方面。我们能够使用一个简单的流水线架构来实现ZooKeeper,它允许我们在保持低延迟的同时拥有成百上千个未完成的请求。这样的管道自然支持以FIFO顺序从单个客户机执行操作。保证FIFO客户端顺序使客户端能够异步提交操作。使用异步操作,客户端可以同时有多个未完成的操作。例如,当一个新客户机成为leader时,它必须操作元数据并相应地更新它时,这个特性是可取的。如果没有多个未完成操作的可能性,初始化时间可以以秒为顺序,而不是亚秒。

为了保证更新操作满足线性化,我们实现了一个基于leader的原子广播协议[23],称为Zab[24]。然而,ZooKeeper应用程序的典型工作负载是由读操作控制的,因此需要扩大读吞吐量。在ZooKeeper中,服务器在本地处理读操作,我们不使用Zab来完全排序它们。

在客户端缓存数据是提高读取性能的一项重要技术。例如,进程缓存当前leader的标识符,而不是每次需要知道leader的时候都探测ZooKeeper。ZooKeeper使用了watch机制,使得客户端可以缓存数据,而无需直接管理客户端缓存。使用这种机制,客户端可以监视给定数据对象的更新,并在更新时接收通知。Chubby直接管理客户端缓存。它阻止更新以使缓存被更改数据的所有客户端的缓存失效。在这种设计下,如果这些客户机中的任何一个运行缓慢或出现故障,更新就会延迟。Chubby使用租约来防止有故障的客户端无限期地阻塞系统。然而,租赁只限制了慢或错误的客户端的影响,而ZooKeeper手表完全避免了这个问题。

在本文中,我们讨论了系统的设计和实现使用ZooKeeper,我们可以实现应用程序需要的所有协调原语,即使只有写操作是线性的。为了验证我们的方法,我们展示了如何用ZooKeeper实现一些协调原语。

协调内核:我们提出了一个在分布式系统中使用的具有宽松一致性保证的无等待协调服务。特别地,我们描述了我们的协调内核的设计和实现,我们已经在许多关键应用程序中使用它来实现各种协调技术

协调方法:我们将展示如何使用ZooKeeper来构建更高层次的协调原语,甚至是分布式应用中经常使用的阻塞和强一致性原语、

2 The ZooKeeper service

客户端使用ZooKeeper客户端库,通过客户端API向ZooKeeper提交请求。除了通过客户端API公开ZooKeeper服务接口外,客户端库还负责管理客户端和ZooKeeper服务器之间的网络连接。

ZooKeeper为其客户端提供了一组数据节点(znode)的抽象,这些节点是根据一个分层的名称空间组织起来的。这个层次结构中的znode是客户端通过ZooKeeper API操作的数据对象。分级名称空间通常用于文件系统。这是一种组织数据对象的理想方式,因为用户习惯了这种抽象,而且它可以更好地组织应用程序元数据。

ZooKeeper Implementation 

ZooKeeper通过将ZooKeeper的数据复制到组成服务的每一台服务器上,提供高可用性。我们假设服务器因崩溃而故障,这些故障服务器稍后可能会恢复。图4显示了ZooKeeper服务的高级组件。在接收到请求后,服务器就为它的执行做准备(请求处理器)。如果这样的请求需要服务器之间的协调(写请求),那么它们使用协议协议(原子广播的实现),最后服务器将更改提交到ZooKeeper数据库中,在整个集群的所有服务器中完全复制。对于读请求,服务器只读取本地数据库的状态,并生成对请求的响应。

4.2 Atomic Broadcast

所有更新ZooKeeper状态的请求都转发给leader。leader执行请求,并通过Zab[24](一种原子广播协议)将变更广播到ZooKeeper状态。接收客户端请求的服务器在客户端发送相应的状态更改时响应客户端。Zab默认使用简单多数仲裁来决定一个提议,因此Zab和ZooKeeper只能在大多数服务器是正确的情况下工作(例如,2f + 1服务器我们可以容忍f个故障)。

为了达到高吞吐量,ZooKeeper尝试保持请求处理管道的满。在处理管道的不同部分可能有数千个请求。因为状态更改依赖于先前状态更改的应用程序,所以Zab提供了比常规原子广播更强的顺序保证。更具体地说,Zab保证由leader广播的更改会按照发送的顺序进行传递,并且所有来自前一个leader的更改都会在广播自己的更改之前传递给一个已建立的leader。

有一些实现细节简化了我们的实现,并为我们提供了出色的性能。我们使用TCP进行传输,因此消息顺序由网络维护,这使我们能够简化实现。我们使用Zab选择的leader作为ZooKeeper的leader,这样创建事务的进程也会提出它们。我们使用日志作为预写日志来跟踪提案

Evaluation

我们将下面的讨论分为两个部分:吞吐量和请求延迟。

5.1 Throughput

为了评估我们的系统,我们对系统饱和时的吞吐量以及各种注入失败时吞吐量的变化进行了基准测试。我们改变了组成ZooKeeper服务的服务器数量,但始终保持客户端数量不变。为了模拟大量的客户机,我们使用了35台机器来模拟250个并发客户机。

ZooKeeper能够通过在组成服务的服务器上分配负载来实现如此高的吞吐量。我们可以分配负载,因为我们放松的一致性保证。胖乎乎的客户则把所有的请求都直接交给领导。图6显示了如果我们不利用这种放松,并强迫客户端只连接到leader,会发生什么。正如预期的那样,对于读为主的工作负载,吞吐量要低得多,但是即使对于写为主的工作负载,吞吐量也更低。服务客户端带来的额外CPU和网络负载会影响leader协调proposal广播的能力,从而影响写性能。

5.2 Latency of requests

     为了评估请求的延迟,我们以Chubby基准测试[6]为模型创建了一个基准测试。我们创建一个工作进程,它发送一个创建,等待它完成,发送一个新节点的异步删除,然后开始下一个创建。我们相应地改变worker的数量,每次运行时,我们让每个worker创建50,000个节点。我们通过将完成的创建请求数除以所有工作人员完成的总时间来计算吞吐量

即使在这些较大的请求下,ZooKeeper的吞吐量也比Chubby发布的吞吐量高出3倍以上

7 Conclusions

ZooKeeper通过向客户端公开无等待的对象,解决了分布式系统中协调进程的问题。我们已经发现ZooKeeper是有用的几个应用内部和外部雅虎!对于读为主的工作负载,ZooKeeper通过使用带表的快速读取来实现每秒数十万次操作的吞吐量值,这两个操作都由本地副本提供。虽然我们的一致性保证读取和手表似乎弱,我们已经展示了我们的用例,这种组合使我们能够实现高效的和复杂的协调协议在客户即使读不是precedence-ordered并无等待数据对象的实现。无等待特性已被证明对高性能至关重要。

虽然我们只描述了几个应用程序,但还有许多其他应用程序使用ZooKeeper。我们相信这样的成功是由于它简单的接口和人们可以通过这个接口实现的强大的抽象。此外,由于ZooKeeper的高吞吐量,应用程序可以广泛使用它,而不仅仅是粗粒度锁定。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值