YoloKokura

原论文:The Chubby lock service for loosely-coupled distributed systems

为什么需要第三方的锁服务?

Chubby的目的,或者说分布式锁的目的,是同步集群中不同成员的行为,并使他们对某些事件或集群状态达成一致。 但随之而来的问题就是,为什么一定要依赖于第三方的锁服务,而不是直接在集群中使用Paxos或者Raft这样的一致性协议呢?

  1. 首先,第三方锁服务对原系统的侵入改造要求更少。许多系统在设计之初并未考虑引入一致性协议,如果使用 外部的第三方锁,就不会破坏太多现有的项目结构。
  2. 另外,Chubby可以支持小文件的读写,使之能够将选主或数据分片的结果推广到整个集群。
  3. 开发者基本上熟悉了锁的概念,分布式锁对他们来说更容易接受。
  4. 一致性协议使用quorum进行决策,这意味着在客户端需要多台设备来保证高可用;但对于第三方锁,客户只需要获取一个分布式锁就可以了,一个客户即可做到。(这一点其实是站在client侧考虑的,其实有点牵强:Chubby要保证HA,同样也需要多个冗余成员,只是这种冗余和client的设计无关)

系统设计

Chubby大体分成client library和server两个组件,前者是应用和服务侧交互的中介,后者是Chubby的核心代码实现。

服务侧的若干服务器组成的集群称为Chubby cell,它们使用一种一致性协议来选主。读操作由master独立完成,写操作则需要同步到超过半数的成员上。如果master宕机,则其他成员通过一致性协议重新选主;如果普通成员宕机,且未及时恢复,则系统将从一个资源池中选择一个新的机器并启动Chubby进程。这台机器将更新DNS表,替换掉旧机器的IP地址。master将通过一致性协议与之同步状态。

命名机制

Chubby的命名示例如下:

/ls/foo/wombat/pouch

其中ls代表lock service,是一个必要的前缀。foo是Chubby cell的标识名,用于DNS查找。本地Chubby cell可以使用local指代。剩下的部分即可按照Unix文件系统的规范去解析。

缓存机制和Chubby Session

client在本地维持一份文件数据和节点元数据的write-through缓存,由master来决定是否更新。

master记录每个client应该缓存的内容,一旦这些内容将要发生变化,master首先向相应client发送指令标记缓存失效, client在自己的KeepAlive消息中附加ack返回给master,此时master方才修改这部分内容。

client和Chubby cell之间的连接被称为Chubby Session,由周期性的KeepAlive消息维持。 每一个Session都有一个租约期(lease),由master在回复KeepAlive时更新。 同时,client自身也持续估算来自master的lease,其中考虑了master的时钟以及网络通信的时间开销。 当client估计的lease过期,它将不确定master是否终止了Session,client认为Session进入一段称为jeopardy的状态。 这个时候它清空本地缓存,继续等待一段grace period。期间如果收到KeepAlive的回复,则重新恢复缓存,否则认为Session过期。 Chubby会通知应用层目前的状态,进入grace period时发送jeopardy事件,恢复通信发送safe事件,反之发送expired事件。这种事件通知确保应用层可以根据Session状态调整运行逻辑,不必出现问题就无脑重启,造成不必要的开销。

Tags: