租约(Lease) 机制是分布式系统中一种至关重要的协调工具,广泛应用于节点状态判定、领导者选举、分布式锁、资源管理等场景。其核心思想是通过一个带有时间限制的授权(Time-bounded Promise) 来确保在不确定环境下的行为一致性和系统可靠性。
Lease机制的运行逻辑主要包括以下要点。
1)Lease的本质:Lease是由授权者(Issuer,例如一个中心协调服务或当前Leader)授予接收方(Holder/Receiver,例如一个工作节点或候选Leader)的一种承诺。该承诺规定接收方在Lease的有效期内拥有特定的权限(如作为Leader的权利、访问某资源的权利)。
2)授权者的责任:一旦授权者发出了一个Lease,只要该Lease尚未过期,授权者就必须严格遵守其承诺。例如,如果授予了一个Leader Lease,那么在它过期前,授权者不能再授予给其他节点相同的Leader Lease。
3)接收方的权利与义务:接收方在Lease有效期内可以行使其被授予的权限。一旦Lease过期,接收方必须主动放弃该权限,并通常需要重新向授权者申请新的Lease才能继续。
4)Lease的失效机制:Lease可通过版本号号(Version)更新、时间周期(Time Period)到期或到达固定时间点(Fixed Timestamp)等方式失效,确保生命周期可控。
基于 Lease 机制确定节点状态
在分布式系统中确定一个节点是否处于正常工作状态是一个困难的问题,由于可能存在网络分化,节点的状态是无法通过网络通信来确定的。
最直观的办法是在Leader与Follower之间维持一个心跳(Heartbeat)。比如节点Q作为一个中心节点, A、B、C作为副本节点,A作为Leader,B、C作为Follower, 同一时刻只能有一个Leader节点。节点Q通过与 A、B、C的心跳来判断节点状态,从而判断Leader节点是否需要切换,但如果只通过心跳判断,是有问题的。
节点A、B、C周期性地向Q发送心跳信息,假如超过一段时间,节点Q收不到节点A的心跳,除了节点A本身甚至是节点Q的异常外,也有可能是因为节点Q与节点A之间的网络异常导致的(比如网络拥塞导致的"瞬断")。
假设节点A本身工作正常,节点A与节点B、C之间的网络正常。但此时节点Q认为节点A异常,重新选择节点B作为新的Leader,并通知节点A、B、C新的 Leader是节点B。由于节点Q的通知消息到达节点 A、B、C的顺序无法确定,假如先到达节点B,则在这一时刻,系统中同时存在两个工作中的Leader,一个是节点A、另一个是节点B。假如此时节点A、B 都接收外部请求并与节点C同步数据,会产生严重的数据错误。上述即所谓"双主"问题。
上面的例子中,如果要保证系统的正确性,依赖于对节点状态认知的全局一致性,即一旦节点Q认为节点A异常,则节点A也必须认为自己异常,从而节点A停止作为Leader,避免出现"双主"的问题。下面讨论利用Lease机制确定节点状态:
1)节点A、B、C周期性地发送心跳报告自身状态,节点 Q收到心跳后发送一个Lease,表示节点Q确认了节点A、B、C的状态,并允许节点在Lease有效期内正常工作。
2)节点Q可以给节点A一个特殊的Lease,表示节点A可以作为Leader工作。一旦节点Q希望切换新的 Leader,则只需等前一个Leader的Lease过期,则可以安全的颁发新的Lease给新的Leader节点,而不会出现"双主"问题。
Lease的容错
1)Leader节点宕机/网络分区: Lease机制天然容忍这种情况。Leader无法续约,Lease过期后其权限自动失效。系统不可用的最长时间(在等待Lease过期期间)受Lease有效期限制。
2)授权者(中心节点)异常: 若颁发Lease的单点授权者Q宕机,所有节点都无法获取或续约Lease,系统可能整体不可用。解决方案是使用一个高可用的小集群作为Lease的授权者。
3)时钟同步问题:授权者和接收者之间的时钟如果存在较大偏差,可能导致Lease的实际有效期与预期不符。授权者在计算Lease的到期时间时,需要考虑一个安全窗口(Guard Band或Clock Drift Bound)来容纳潜在的时钟误差。
按照工程经验,Lease的时间差一般取1-10s。太短,则太容易回收承诺,抖动频繁。太长,则太不容易回收承诺,可能导致可用性问题。
ETCD Lease机制
直接在应用中完整实现一套可靠的Lease机制相当复杂。幸运的是,像ETCD、ZooKeeper这类成熟的分布式协调服务已经内置了高可用的Lease功能,应用开发者可以直接使用。
如上图所示,创建了一个10秒的Lease。 如果在创建Lease后不进行任何操作,则该租约将在10秒后自动过期。 将key1和key2绑定到前Lease,以便在Lease到期时ETCD自动清除key1和key2。
如果希望保留Lease,则需要定期调用KeyAlive方法来刷新它。 例如,要检查分布式系统中的某个节点是否处于活动状态,可以在该节点中创建一个Lease,并定期调用该节点中的KeepAlive方法。 如果进程正常,则保留该节点的Lease。 如果节点崩溃,Lease将自动到期。
但是,如果大量的Key需要支持类似的Lease机制,并且必须为每个Key独立刷新Lease,这将给ETCD带来很大的压力。 因此,ETCD允许将多个Key(例如,具有相似过期时间的Key)绑定到同一个Lease,这可以大大减少Lease刷新的开销并提高ETCD性能。
未完待续
很高兴与你相遇!如果你喜欢本文内容,记得关注哦!!!