最近做项目在使用 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 必须看一下自己的租约到期了没有,如果到期了,说明获取锁是无效的,要新建一个租约,重新获取锁。
分布式锁选主流程设计
结束语
- 第一次画流程图,有点长,路漫漫其修远兮,加油加油!