实现Redis分布式锁

自己实现Redis分布式锁

业务需求:秒杀商品

初步,2台服务器负载均衡处理请求

问题1: 服务器A处理请求,事务时间比较长,中间服务器B更新了数据库,A最后更新数据库覆盖B的更新结果,最后超卖。

解决1:使用乐观锁,秒杀商品,并发量会很大,大量冲突,会导致乐观锁不断回滚,一直重试(没法用)

解决2:由于Redis是单线程的,所以可以使用Redis锁,通过setnx指令保证同一时间只有一台服务器操作库存,操作结束del指令释放锁,解决结果覆盖问题

// 加锁
setnx lock 1
// 释放锁
del lock 

问题2: 如果存锁的服务端挂掉怎么办?

解决1:存锁的客户端挂掉,会导致锁无法释放,这里可以加过期时间

// 加锁
setnx lock 1
// 设置10秒过期
expire lock 100

问题3: 如果加锁成功了,但是加过期时间失败怎么办?

lua脚本使用介绍

-- redis自从2.6.0版本起就采用内置的Lua解释器通过EVAL命令去执行脚本
-- lua脚本中调用redis命令可以使用两个命令 
	redis.call()
	redis.pcall()

解决1:使用lua脚本

 -- 如果加锁成功
if redis.call("SETNX", "lock", "1") == 1 then
  -- 设置过期时间10秒
  local expireResult = redis.call("expire", "lock", "100")
  -- 如果设置过期时间成功
  if expireResult == 1 then
      return "success"
  else
      return "expire failed"
  end
else
  return "setnx not null"
end

解决2:自2.6.12版本开始,Redis的SET 命令的行为可以通过一系列参数来修改, 可以代替SETNX 、 SETEX 和 PSETEX三个命令,直接使用set(key,value,NX,EX,timeout),同时加锁并设置超时时间

-- 设置锁及过期时间
eval "return redis.call('SET','lock','1','NX','PX','100')"

问题4: 如果锁过期了,但是没执行完怎么办?

解决:如果过期没执行完会导致同一时间多个客户端操作库存,导致超卖,这里通过锁续期来解决

-- ARGV[1] 是可传入的参数变量,表示持有锁的系统的唯一值,也就是只有持有锁的客户端才能刷新 key 的超时时间。
if redis.call("get", "lock") == ARGV[1] 
  then 
    return redis.call("expire", "lock", "10")
	else 
    return 0 
end

问题5: 如果锁释放错了怎么办?

每个服务设置key时带上自己服务的唯一标识,如UUID,这样每个服务在删除锁前,先比较value值,值相同在进行删除操作

问题6: 如果Redis单例挂掉,分布式锁没法用怎么办?

解决:组建Redis主从集群,实现高可用

问题7: Redis主从集群数据同步延迟,存在问题主机上的Redis已经建好了锁,但是锁还未同步到从机上,主机宕机了,这个时候从机升级为主机,锁丢了。

解决: 使用RedLock,取消slave节点,不需要从库和哨兵,由此解决数据同步丢失锁的问题

实现原理:设有5个节点

1、客户端获取当前时间戳startTime

2、客户端分别向5个节点申请加锁

3、单个节点加锁超时则立即向下一个节点申请加锁

4、加锁成功:如果最后有3个及以上节点加锁成功,则获取时间戳endTime,如果endTime-startTime<锁过期时间则成功加锁

5、加锁失败:如果少于3个节点加锁成功则通知所有节点释放锁

问题8:

1、要实现RedLock,官方推荐最少5个实例,成本太高

2、同时整个流程下来锁太重

3、分布式系统中的NPC问题

  • N:Network Delay,网络延迟

  • P:Process Pause,进程暂停(GC)

  • C:Clock Drift,时钟漂移

解决:相比下来主从切换概率小,兜底操作性价比高,问题不大,而且发生NPC也需要兜底操作

参考博客:

面试题详解:如何用Redis实现分布式锁?_四猿外的博客-CSDN博客_redission实现分布式锁

Redis实现分布式锁_玄郭郭的博客-CSDN博客_redis分布式锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值