基础知识

image.png

## 分布式锁
### 可以用来实现分布式锁的中间件
- 关键点:支持排他性操作
- 例子:Redis、Nacos、ZooKeeper、关系型数据库
### 利用 Redis 实现一个分布式锁
#### 分布式锁方案
- 思路一
  - 步骤:1. 执行本地事务 2. 加分布式锁 3. 删除缓存 4. 释放分布式锁
  - 问题:1和2之间,分布式锁有可能被别人拿走;数据可能不一致
- 思路二
  - 步骤:1. 开启本地事务 2. 执行事务 3. 获取分布式锁 4. 删除缓存 5. 提交本地事务 6. 释放分布式锁
  - 异常
    - 删除缓存失败,事务会回滚
    - 删除缓存成功,但是提交事务失败,不影响
  - 缺点:事务超时
    - 问题:获取不到分布式锁;网络不通,删除超时
	- 变种
	  - 步骤:1. 获取分布式锁 2. 开启本地事务 3. 执行事务 4. 删除缓存 5. 提交本地事务 6. 释放分布式锁
#### 锁的本质
- 一个普通的键值对/加锁 SETNX/释放 DEL
#### 加锁
- SETNX 命令
  - 设置了键值对——加锁成功
  - 没有设置键值对——别人持有锁
- 确定等待时间:业务正常执行完毕的时间;可以考虑 99 线或 999 线
- 实现等待:睡眠;监听锁释放(DEL 事件)
- 超时重试(用 lua 脚本来执行)
  - 关键点:检测上一次有没有加锁成功
  - 场景
    - Redis 中没有 key1:直接加锁
    - Redis 中有 key1,值为 value1:
	    - 上一次加锁成功;
	    - 重置过期时间
    - Redis 中有 key1,值为 value2:
	    - 上一次没有加锁成功;
		  - 别人持有锁
#### 过期时间
- 确定过期时间
  - 标准:业务完成时间
  - 保守策略:设置更长时间,依赖于主动释放锁
- 续约机制
  - 要提前续约
  - 确保提前的时间能进行重试,并且成功
  - 续约失败:保守 | 中断业务;激进 | 继续执行
#### 中断业务
- 纯靠人在代码里检测
- 循环检测 + 主要步骤之间检测
#### 释放锁
- 要检测锁是不是自己加的
#### 其他亮点
- Redlock:多数原则
- 优化分布式锁:singleflight:减少全局竞争;锁本地转交
- 去分布式锁:数据库乐观锁;一致性哈希负载均衡

文章

分布式锁介绍

深入理解

误删除

Redisson

etcd等实现

分布式锁设计