分布式系统 Zookeeper
背景
- 大规模的分布式应用需要各种各样的协调服务。比如配置参数、组成员、leader选举、锁。
- 有一种方法是为每一种需求开发一个专门的服务,比如Amazon Simple Queue Service专门用在排队。还有其他专门的服务用来做配置、leader选举。
- 另一种方法是类似Chubby。它本身是一个锁服务。然后可以基于它来实现更高层的服务,比如leader选举、group membership等等。(Zookeeper是在这条路上走更远)
作者想达到什么目的?
- 设计一套比较通用的API。让别人可以在此API基础上,实现一些常见的协调原语(coordination primitives),比如配置管理、Rendezvous、Group Membership、简单锁、取号排队锁、读写锁、Double Barrier。
- 要求高性能,尤其是对于读操作比写操作多很多的应用。
作者发明了什么技术方法?
- 以树状结构组织的znodes。分3种
- 常驻的(regular)
- 暂存的(ephemeral)
- 还可以带序列号的。
- sequential可以用来确定次序。
- session和watch很有特色
- pipeline。客户可以发出很多通知,不用等前一个执行完再发下一个。请求是异步执行,但是不会打乱原来顺序。
API的特色
- watches, sessions, atomic znode creation
- watch可以避免一直poll,等通知就行。
- session可以避免显式地写timeout。用来处理断线、宕机、机器慢等情况。所有者没反应了,节点就自动失效,关注方能收到通知。
例子
- 课程笔记举例多个master节点如何决定哪个为primary。
- 如果用Lab 3的KVserver不好实现。
- 用zookeeper容易得多。
- atomic znode creation,保证只有1个节点能抢到。从而决定了它成为primary。
- watches,能通知关心的节点。避免不停地poll。
- sessions能在primary节点挂掉以后自动失效,别人就可以观察到。可以来重新抢当primary。不用搞timestamp之类的东西。简化了实现。
ZooKeeper guarantees
- 写操作是可线性化的。
- 客户端的请求是FIFO的。不会乱序执行。
- 对于“通知”也保证顺寻。
- 保证:如果客户希望在ready被改变时,收到通知。那么客户会先收到通知,才读到ready改变后的值。不会倒过来,先读到新值,再收到通知。
实现概览 (与Lab 3做类比)
- ZooKeeper服务(kv服务)
- ZAB 层 (Raft 层)
- Start()把操作插入到ZAB(Raft)层。
- 命令执行是按照abdeliver() 回调的顺序,类似Lab 3里的apply()
举例
课程Notes(见最下面链接)里面举了3个例子,都是论文中的例子。
- ready
- 简单锁(simple lock)
- 排队取号锁(ticket lock)
都用伪代码写。比原论文写得更清楚明白。大家可以自己看课程笔记。
还可以回顾一下前一课的spinnaker如何用ZooKeeper做leader election,也是用创建znode。然后比较谁的log更新。赢的人创建一个新的/leader Z节点。
作者完成得如何?
- 非常高性能。Zookeeper performs 21,000 msg/sec(这个数值取自论文Table 1的右下角,0% read,都是写操作,3台服务器。)
- API支持非常多种类的用例。
- Zookeeper简化了分布式应用的打造。
- Widely-used(被世界各地的人们广泛地采用)
课前问题
Lecture 8
One use of Zookeeper is a fault-tolerant lock service (see the section “Simple locks” on page 6). Why isn’t possible that two clients can acquire the same lock? In particular, how does Zookeeper decide if a client has failed and it can give the lock to some other client?
- 答:simple lock是用创建一个ephemeral类型的znode实现。要创建成功,这条create命令必须被过半的zookeeper server接受。如果2个client同时调用create,只有1个会成功创建(create出现在log位置更前的那个成功)。这保证了不会有2个client同时得到锁。
- 锁是ephemeral的,就是每个session时间段内,持有锁的client至少要发送一条命令到zookeeper并被过半的ZooKeeper servers接受。(即使没有真命令要发,也要发一条空指令做为心跳)这样是为了防止裂脑——保证过半的ZooKeeper servers都认可,这个sessions内我收到了client的消息,它依然持有锁。这样,其他client要请求create(),就会被拒绝。
- 如果Zookeeper服务器在session时间内没有收到客户发来的心跳,它会删除这个znode。别人可以抢锁。
疑问(求解答)
- 课程笔记上说require session heartbeats to be replicated to majority是什么意思?
- client 2 acquires lock, but client 1 still believes it has it
- can be avoided by setting timeouts correctly
- need to disconnect client 1 session before ephemeral nodes go away
- requires session heartbeats to be replicated to majority
N.B.: paper doesn’t discuss this。(NB不是牛逼的缩写,是"敲黑板"的意思。)
- 似乎是说在timeout时间内,client 1如果不能和半数以上的zookeeper server保持心跳通信(不是直接通信是通过ZAB层)。就不能确定自己还持有锁。可能多数zookeeper servers已经认为你掉线了,把锁给别人(client 2)了。