介绍
- 在雅虎,我们开发了一个高性能高可靠的分布式协调服务,叫做zookeeper,它允许大规模应用执行协调任务,比如:leader推举、状态传播以及约会机制(rendezvous,在交互的过程中,被协调的各方不需要事先彼此了解,甚至不必同时存在 )。这个服务实现了一个数据节点的层次空间,被称之为znodes,客户端使用它们来实现协调任务。我们发现这个服务在灵活性和性能上都非常符合雅虎公司web-scale,关键应用的产品需求。zookeeper放弃(foregoes)了锁,转而实现了零等待的共享数据对象,并且在这些数据对象上实现了操作顺序的强保证。Client库可以利用这些保证来实现它们自己的协调任务。一般来说,Zookeeper一个最主要的使用场景是应用对更新顺序比其它协调技术更重要(比如:阻塞blocking)。【这句翻译不通。。。】
- 嵌入到Zookeeper中的协议是ZAB,它是一个有序广播协议。当需要实现客户端保证的时候,有序广播非常关键。在每一个Zookeeper的server上维护一个zookeeper状态的副本也是很有必要的。这些副本使用我们的全序广播协议来保持一致,比如:使用复制状态机。本文集中在zookeeper如何使用这个广播协议来满足需求的,并对实现进行概述。
- 一个zookeeper服务通常包括3~7台机器;我们的实现可以支持更多的机器,但是3~7台就可以提供很好的性能和可恢复能力。client连接到任何一台机器来提供服务,并拥有zookeeper状态的一致性视图。这个服务能够在2f+1台机器的情况下,允许最多f台机器挂掉。
- 应用广泛地使用zookeeper,它允许有几十到几千台机器同时访问,所以需要很高的吞吐量。我们已经设计zookeeper可以很好的在读写比在2:1之上的负载下进行工作;不过,我们也发现zookeeper的高写吞吐量也让它适合用于写多的应用当中。zookeeper通过在本地的zookeeper状态副本来提供高的读吞吐量。因此,容错和都吞吐量都会随着服务器的加入而得到水平扩展。写吞吐量不会随着服务器的加入而得到水平扩展,它的吞吐量受限于广播协议的吞吐量,因此我们需要一个高吞吐量的广播协议。(下图为zookeeper的逻辑组件)
- 上图显示了zookeeper的逻辑组件;读请求在包含zookeeper状态的本地数据库进行处理;写请求被zookeeper从一般请求转换为幂等事务,并在生成response之前,通过zab协议进行发送。许多zookeeper的写请求都是有条件的:比如,znode只有在没有任何孩子的时候才能被删除;能够使用一个名字和紧跟它之后的序列号来创建znode;只有znode的版本是给定值的时候,才能对它进行修改;甚至无条件的写请求也会使用非幂等方式来修改元数据(比如:版本)。
- 通过单个服务端(被称之为leader)来发送所有更新,我们可以把非幂等请求转换为幂等事务。在这篇文章中,我们使用事务这个术语来代表请求的幂等版本。leader可以执行这个转换,因为它拥有数据库副本的未来状态视图,并能够计算新记录的状态。幂等事务就是这个新状态的记录。zookeeper在很多方面都充分利用了幂等事务的优势。由于我们事务的天然幂等性,使得zookeeper在recovery的时候,可以放松对广播协议的顺序需求。
需求
- 我们假定有一个进程集合,它们实现了原子广播协议并使用这个协议。为了保证能对zookeeper的请求正确转换为幂等请求,确保在同一时刻只有一个leader是有必要的;因此我们就保证通过协议来实现这一点:同一时刻只有一个leader。
- zookeeper在广播协议上有以下需求:
- 可靠投递:如果一个消息m,被一个server投递了;那么它最终也会被所有其它server正确投递。
- 全序:如果一个消息a在消息b之前被一个serve