基本概念
- 什么是分布式锁
+ 如果需要控制分布式系统,不能是某个客户端本地的锁
+ 锁是保存在一个共享存储系统中的,可以被多个客户端共享访问和获取\
- 为什么选择redis
+ 可以被多个客户端共享访问,正好就是一个共享存储系统\
+ 读写性能高,可以应对高并发的锁操作场景
单机上的锁和分布式锁的联系与区别
- 对于单机锁
+ 变量为0,表示线程未获取到锁
+ 变量为1,表示已经有线程获取到锁
+ 获取锁则把变量置为1
+ 释放锁则把变量置为0
- 分布式锁
+ 也是通过判断锁的变量值,多个客户端存储数据
+ 新的要求
- 分布式锁的加锁和释放锁的过程,涉及多个操作(需要保证原子性)\
- 怎么保证分布式锁的稳定性和可靠性
基于单个 Redis 节点实现高可靠的分布式锁
- 设置设计分布式锁
+ key锁的名称 value锁的状态
- 怎么保证读取锁,判断锁和设置锁操作的原子性
+ 使用redis原子命令
- SETNX 如果存在就设置,如果不存在就不设置+DEL删除释放锁\
+ 使用Lua脚本
- 使用SETNX的潜在风险
+ DEL操作异常,导致锁一直不释放 通过设置过期时间避免死锁
+ 不是申请的锁的客户端执行DEL会误删除锁 可以将value设为客户端唯一值
+ SET 命令的 NX 和 EX/PX 选项\
- DEL删除释放锁\
+ 最好使用lua脚本,保证指令的原子性
+ 读取数据,删除释放数据
\
基于多个 Redis 节点实现高可靠的分布式锁
- Redis 的开发者 Antirez 提出了分布式锁算法 Redlock\
- 如果客户端能够和半数以上的实例成功地完成加锁操作\
+ 获取锁成功
+ 否则获取锁失败
- 具体实现步骤
+ 客户端获取当前时间
+ 客户端按顺序依次向 N 个 Redis 实例执行加锁操作(使用指令SETNX value是客户端标识) 顺序加锁\
+ 完成加锁,计算总耗时 判断是否成功
- 超过半数加锁成功
- 总耗时未超过过期时间
- 可以通过redlock保证可靠性
总结
- 加锁注意点
+ 加锁包括了读取锁变量、检查锁变量值和设置锁变量值三个操作 使用SETNX指令\
+ 锁变量需要设置过期时间,避免死锁\
+ 锁变量的值需要能区分来自不同客户端的加锁操作,以免在释放锁时,出现误释放操作\
- 释放锁注意点
+ 释放锁也包含了读取锁变量值、判断锁变量值和删除锁变量三个操作\
+ 没有指令能够完成
+ 一般使用lua脚本实现操作的原子性
- 保证稳定性
+ 可以使用Redlock算法,实现基于多个实例的分布式锁
本文转载自: 掘金