使用 etcd 的分布式锁进行选主的尝试

最近做项目在使用 etcd, 由于项目里很多定时任务,在实现高可用的时候需要进行选主,即只执行一次定时任务。之前的项目用的是 zookeeper 进行选主。大概思路是抢一个key,没抢到的就不执行了,抢到的就执行,类似于 redis 的 setnx 。因为项目本身用了 etcd,所以再引入 zookeeper 是不太合适的,同时 zookeeper 选主一旦定时任务如果执行失败,无法重试。

etcd 的分布式锁

  • 本文使用的分布式锁是 etcd 的 v3lock,附上官网文档
  • etcd 在创建分布式锁的时候必须绑定租约(Lease)。
  • 在获取分布式锁的时候,如果锁已经被创建,线程会阻塞,直到锁被释放。假设 A、B、C 三个线程租约都是 50 秒,同时去抢锁,然后假设 A 线程抢到了,B、C 就都在阻塞了,必须等租约 50 秒到期,或者 A 释放锁。
  • 如果 A 在执行很顺利,那么执行成功之后,A 需要把自己的租约 ID 写到 SuccessLease 这个 key 里面。这样 B、C 在获取锁之后,可以去查看 SuccessLease ,如果里面对应的租约没有到期,则说明 A 是执行成功了的,即无需再执行一次;如果租约到期了(上一次定时任务写入的),或者这个 key 不存在,则说明之前的执行是失败的,或者无效,那么当前线程可以进行临界区操作。
  • 如果 A 执行失败,比如报错了,或者线程挂了。那么 B、C 只能等租约到期,再获取锁,请注意:这时候 B 和 C 会同时获取锁,所以必须 B、C 必须看一下自己的租约到期了没有,如果到期了,说明获取锁是无效的,要新建一个租约,重新获取锁。

分布式锁选主流程设计

获取成功
到期
没到期
获取成功
过期
获取失败
没过期
Start
创建租约 LeaseA
获取分布式锁 LockB
判断 LeaseA 是否到期
进入临界区
获取 SuccessLease
判断 SuccessLease 是否过期
进行操作
释放 LockB 并退出临界区
将 LeaseA 写入 SuccessLease
结束

结束语

  • 第一次画流程图,有点长,路漫漫其修远兮,加油加油!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章