download:Taro@3.3.3 最新版本开发企业级出行我的项目网盘分享
为什么需要分布式锁
用户下单
锁住 uid,防止重复下单。
库存扣减
锁住库存,防止超卖。
余额扣减
锁住账户,防止并发操作。
分布式零碎中共享同一个资源时经常需要分布式锁来保障变更资源一致性。
分布式锁需要具备个性
排他性
锁的基本个性,并且只能被第一个持有者持有。
防死锁
高并发场景下临界资源一旦发生死锁非常难以排查,通常可能通过设置超时工夫到期主动开释锁来规避。
可重入
锁持有者反对可重入,防止锁持有者再次重入时锁被超时开释。
高性能高可用
锁是代码运行的要害前置节点,一旦不可用则业务间接就报故障了。高并发场景下,高性能高可用是基本申请。
实现 Redis 锁应先管制哪些学识点
set 命令
SET key value [EX seconds] [PX milliseconds] [NX|XX]
EX second:设置键的过期工夫为 second 秒。SET key value EX second 成果同等于 SETEX key second value。
PX millisecond:设置键的过期工夫为 millisecond 毫秒。SET key value PX millisecond 成果同等于 PSETEX key millisecond value。
NX:只在键不存在时,才对键进行设置操作。SET key value NX 成果同等于 SETNX key value。
XX:只在键已经存在时,才对键进行设置操作。
Redis.lua 脚本
使用 redis lua 脚本能将一系列命令操作封装成 pipline 实现整体操作的原子性。
go-zero 分布式锁 RedisLock 源码分析
core/stores/redis/redislock.go
加锁流程
<button type=”button” class=”btn btn-dark far fa-copy rounded-0 sflex-center copyCode” data-toggle=”tooltip” data-placement=”top” data-clipboard-text=”– KEYS[1]: 锁 key — ARGV[1]: 锁 value, 随机字符串 — ARGV[2]: 过期工夫 — 判断锁 key 持有的 value 是否等于传入的 value — 如果相等说明是再次获取锁并更新获取工夫,防止重入时过期 — 这里说明是“可重入锁”if redis.call(“GET”, KEYS[1]) == ARGV[1] then — 设置 redis.call(“SET”, KEYS[1], ARGV[1], “PX”, ARGV[2]) return “OK” else — 锁 key.value 不等于传入的 value 则说明是第一次获取锁 — SET key value NX PX timeout : 当 key 不存在时才设置 key 的值 — 设置胜利会主动返回“OK”,设置失败返回“NULL Bulk Reply”— 为什么这里要加“NX”呢,因为需要防止把别人的锁给覆盖了 return redis.call(“SET”, KEYS[1], ARGV[1], “NX”, “PX”, ARGV[2]) end” data-bs-original-title=” 复制 ” aria-label=” 复制 ”>
— KEYS[1]: 锁 key
— ARGV[1]: 锁 value, 随机字符串
— ARGV[2]: 过期工夫
— 判断锁 key 持有的 value 是否等于传入的 value
— 如果相等说明是再次获取锁并更新获取工夫,防止重入时过期
— 这里说明是“可重入锁”
if redis.call(“GET”, KEYS[1]) == ARGV[1] then
-- 设置
redis.call("SET", KEYS[1], ARGV[1], "PX", ARGV[2])
return "OK"
else
-- 锁 key.value 不等于传入的 value 则说明是第一次获取锁
-- SET key value NX PX timeout : 当 key 不存在时才设置 key 的值
-- 设置胜利会主动返回“OK”,设置失败返回“NULL Bulk Reply”-- 为什么这里要加“NX”呢,因为需要防止把别人的锁给覆盖了
return redis.call("SET", KEYS[1], ARGV[1], "NX", "PX", ARGV[2])
end