Skip to content

简介 ​

Simba 是一个用于 leader 选举和分布式锁 的 JVM 库。每个进程在你已经运维的后端(MySQL 或 PostgreSQL、Redis 或 Zookeeper)上打开一个 会话,并在其上竞争具名的 租约。赢得租约的节点获得一个 任期:这个对象携带一个 fencing token, 并且知道自己还剩多长有效时间。Simba 没有服务端:库运行在你的应用内部。

典型用法:让定时任务只在一个节点上运行,把分区工作分散到存活的节点上,让一个进程驱动一个工作流,或者在绝不能同时执行两次的步骤外面持有一把锁。

Simba 保证什么 ​

  1. 在本地时钟所能判断的范围内,每个租约名称至多有一个有效任期。 任期在会话的本地截止时刻之前有效,而这个时刻总是早于后端把租约交给另一个会话的时刻 (只要时钟速率之差小于配置的 drift)。有效性在每次读取时根据单调时钟计算,因此一个从长时间暂停中醒来的进程在第一次读取时就会看到自己的任期已失效。
  2. Fencing token。 每个任期都携带一个大于零的 token,在所有后端上,同一名称的 token 随任期严格递增。
  3. 成对的回调。 每个 onElected(term) 之后恰好跟随一个 onRevoked(term, reason),同一选举的回调按顺序逐个执行, 并且 stop() 完成之后不会再有回调到达。
  4. 有序的交接。 stop() 和 stepDown() 会中断绑定在任期上的任务,等待其退出(最多等待任期的剩余时间),然后才释放租约。
  5. 活性。 关闭客户端的节点会立即释放其租约;当节点崩溃或与后端失联时,其会话在 leaseDuration 之后过期,其他节点接管它的租约。

Simba 不保证什么 ​

任期是后端状态的一个 弱一致视图。被 GC、磁盘卡顿或网络分区暂停的进程,可能在会话过期之后恢复,并仍然完成一次已经开始的写入,而此时另一个节点持有更新的任期。 任何基于租约的锁都无法单独阻止这种情况;Simba 从不承诺“没有脑裂”。

如果重叠执行有害,被保护的资源必须拒绝过期的持有者:在每次写入时携带 term.token,并让资源拒绝低于其已接受的最大值的 token。如果重复执行只是浪费(例如报表生成了两次),仅靠任期就足够了。

Simba 也不会在后端不可达时继续工作:一旦会话的本地截止时刻已过,该节点的每个任期都会被撤销。

选择 API ​

所有 API 都挂在一个 Simba 客户端上(每个进程一个,对应一个后端会话)。

你想要……使用页面
在获得和失去领导权时做出响应simba.election(name).start(listener)快速开始
每个任期运行一次代码块,任期结束时中断election.runWhileLeader { term -> }Leader 任务
只在 leader 上周期性地运行一个方法election.schedule(...) 或 @SimbaScheduledLeader 任务
把 N 个分区分散到存活的节点上,每个分区只在一个节点上simba.group(name, n) 或 @SimbaPartitionedLeader 任务
在某个步骤外持有一把锁,然后释放simba.lock(name).acquire(timeout)锁
查看本节点的会话和每个选举simba.snapshot()、Actuator simba可观测性

选择后端 ​

JDBC (MySQL 8, PostgreSQL 14+)Redis 7Zookeeper
会话simba_session 中的一行带 PX 的哈希 simba:session:{sid}一个 Zookeeper 会话
租约simba_lease 中的一行,永不删除哈希 simba:lease:{name},永不过期临时节点 /simba/leases/{name}
Fencing token行内计数器,每个任期 +1哈希内计数器,每个任期 +1节点的 czxid
时钟数据库时间Redis TIMEZookeeper 会话超时
正常停止后的故障转移候选者的下一次尝试立即(释放广播)立即(节点 watch)
Token 持久性事务性主从切换后可能回退Zookeeper 法定人数(quorum)

崩溃后的故障转移大约需要 leaseDuration(Zookeeper:协商后的会话超时)再加上候选者的下一次尝试。选择你已经在运行的那个; 阅读 后端 了解部署与运维说明,尤其是 Redis 主从切换的边界。

下一步 ​

基于 Apache License 2.0 发布。