分布式锁定义
分布式环境下,锁定全局唯一资源
交易订单锁定
- 防止重复下单
- 解决业务层幂等问题
- 防止重复下单
MQ消息消费幂等性
强一致性
- 服务高可用,系统稳健
- 锁必须是可重入的(避免死锁)
- 锁字段续约及其自动释放
- 可视化管理后台,监控及管理
应用场景
- 保证数据库可靠性(转账)
- 分布式缓存更新问题
- 分布式中任务领取问题
分布式锁方案比较
基于Redis分布式锁方案
- 唯一线程串行处理
实现方式
锁的获取使用set命令实现,需要使用一条命令实现生成和设置过期时间来保证原子性。
private static final String SET_IF_NOT_EXIST = "NX";
private static final String SET_WITH_EXPIRE_TIME = "PX";
//@param jedis Redis客户端
//@param lockKey 锁
//@param requestId 请求标识
//@param expireTime 超期时间
jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
锁的释放:需要一条命令完成保证原子性,但是需要先判断是否是当前线程持有的锁,然后才能执行删除。
- 使用lua脚本来完成
//lua脚本
String script="if redis.call('get', KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
Object result=jedis.eval(script, Collections.singletonList(lockKey),
Collections.singletonList(requestId));
- 存在问题:
- 锁时间不可控
- 无法续租期
- 无法续租期
- 单点问题
- 单实例存在进程一旦死掉,会彻底阻塞业务流程
- 主从方式,主从数据异步,会存在同步数据时候锁失效的问题
- 单实例存在进程一旦死掉,会彻底阻塞业务流程
- 官方建议
- Redis本身建议使用Redlock算法来保证,但是问题是需要至少三个Redis主从实例来完成,维护成本相对较高。Redlock等同于自己实现简单的一致性协议,细节繁琐,容易出错
- Redis本身建议使用Redlock算法来保证,但是问题是需要至少三个Redis主从实例来完成,维护成本相对较高。Redlock等同于自己实现简单的一致性协议,细节繁琐,容易出错
- 锁时间不可控
基于ETCD分布式锁方案
为什么选择ETCD:
- 简单kv强一致性
- 高可用,无单点
- 数据高可靠
- 持久化
- 持久化