etcd高级应用
1 分布式锁
1.1 Redis分布式锁
➢ Set实现分布式锁:
⚫ SET key value [EX seconds] [NX|XX],获取不到 锁的线程只能轮询去尝试获取锁(可用性)
⚫ NX参数实现互斥,一次性只能一个(互斥性)
⚫ EX保证拿到锁的服务器挂掉了,能自动释放锁(活 性)
⚫ SETNX无法原子性设置过期时间,所以并不常用
➢ 优点
⚫ 快、简单,在允许偶发锁失效的场景下推荐使用
➢ 缺点
⚫ 通过轮询抢占锁的机制不是很可靠,当某线程占用锁时间较长时可能导致其他线程抢占锁失 败
⚫ 如果master和slave结构,如果存在脑裂或者数据丢失情况,导致锁的数据没有同步,就导致 了分布式锁的失效
⚫ 解锁时,为了保证原子性(查询锁,判断值并删除),需要在redis服务端用脚本来实现查询 并删除
1.2 Zookeeper分布式锁
1.2.1 基于唯一节点实现
⚫ 唯一节点保证互斥性 ⚫ Zap协议保证一致性 ⚫ 临时节点保证活性 ⚫ Watch机制保证可用性

缺点:会发生惊群效应,当释放锁时所有竞争都将被唤醒
1.2.2 基于有序节点实现

流程:
1.3 Etcd实现分布式锁
Etcd是具备事务特性的,所以天然能保证原子性操作 ;可以根据key的create_revision来保证互斥性; Etcd集群通过Raft保证了数据的强一致性 ; Etcd通过Lease来保证活性 ;Etcd通过Watch来保证可用性

流程:
准备:
客户端连接Etcd,以/lock为前缀创建全局唯一的key;客户端分别为自己的key创建租约 Lease,租约的过期时间默认60s;每个客户端创建的具体key为/lock/leaseId
创建定时任务作为租约的“心跳”:
当一个客户端持有锁期间,其它客户端只能等待,为了避免等待期间租约失效,客户端会调 用keepalive进行自动续约。此外,如果持有锁期间客户端崩溃,心跳停止,key 将因租约 到期而被删除,从而锁释放,避免死锁。
客户端将自己全局唯一的 key 写入 Etcd
进行 put 操作,将步骤 1 中创建的 key 绑定租约写入 Etcd,根据 Etcd 的 Revision 机 制,假设两个客户端 put 操作返回的 Revision 分别为 1、2,客户端需记录 Revision 用 以接下来判断自己是否获得锁。
客户端判断是否获得锁
客户端以前缀 /lock/ 读取 keyValue 列表(keyValue 中带有 key 对应的 Revision), 判断自己 key 的 Revision 是否为当前列表中最小的,如果是则认为获得锁;否则监听列 表中前一个 Revision 比自己小的 key 的删除事件,一旦监听到删除事件或者因租约失效 而删除的事件,则自己获得锁。
执行业务
释放锁