Redis(十八)Redlock算法

自研锁逻辑

按照JUC里面java.util.concurrent.locks.Lock接规范编写

lock加锁关键逻辑

  1. 加锁的Lua脚本,通过redis里面的hash数据模型,加锁和可重入性都要保证
  2. 加锁不成,需要while进行重试并自旋
  3. 自动续期,加个钟
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException
{
   
   
    if(time == -1L)
    {
   
   
    	//第一步
        String script =
                "if redis.call('exists',KEYS[1]) == 0 or redis.call('hexists',KEYS[1],ARGV[1]) == 1 then    " +
                        "redis.call('hincrby',KEYS[1],ARGV[1],1)    " +
                        "redis.call('expire',KEYS[1],ARGV[2])    " +
                        "return 1  " +
                "else   " +
                        "return 0 " +
                "end";
        System.out.println("lockName:"+lockName+"\t"+"uuidValue:"+uuidValue);
		//第二步
        while(!stringRedisTemplate.execute(new DefaultRedisScript<>(script,Boolean.class), Arrays.asList(lockName), uuidValue,String.valueOf(expireTime)))
        {
   
   
            //暂停60毫秒
            try {
   
    TimeUnit.MILLISECONDS.sleep(60); } catch (InterruptedException e) {
   
    e.printStackTrace(); }
        }
        //第三步:新建一个后台扫描程序,来坚持key目前的ttl,是否到我们规定的1/2 1/3来实现续期
        renewExpire();
        return true;
    }
    return false;
}

Redlock红锁算法

https://redis.io/docs/manual/patterns/distributed-locks/

自研锁存在的问题

在这里插入图片描述

线程 1 首先获取锁成功,将键值对写入 redis 的 master 节点,在 redis 将该键值对同步到 slave 节点之前,master 发生了故障;redis 触发故障转移,其中一个 slave 升级为新的 master,此时新上位的master并不包含线程1写入的键值对,因此线程 2 尝试获取锁也可以成功拿到锁,此时相当于有两个线程获取到了锁,可能会导致各种预期之外的情况发生,例如最常见的脏数据。
我们加的是排它独占锁,同一时间只能有一个建redis锁成功并持有锁,严禁出现2个以上的请求线程拿到锁。危险的在这里插入图片描述

Redlock算法设计理念

Redis也提供了Redlock算法,用来实现基于多个实例的分布式锁。
锁变量由多个实例维护,即使有实例发生了故障,锁变量仍然是存在的,客户端还是可以完成锁操作。
Redlock算法是实现高可靠分布式锁的一种有效解决方案,可以在实际开发中使用。

Redison

https://github.com/redisson/redisson/wiki/8.-distributed-locks-and-synchronizers/#84-redlock

@Autowired
private Redisson redisson;
public String saleByRedisson()
{
   
   
    String retMessage = "";

    RLock redissonLock = redisson.getLock("zzyyRedisLock");
    redissonLock.lock();

    try
    {
   
   
        //1 查询库存信息
        String result = stringRedisTemplate.opsForValue().get("inventory001");
        //2 判断库存是否足够
        Integer inventoryNumber = result == null ? 0 : Integer.parseInt(result);
        //3 扣减库存,每次减少一个
        if(inventoryNumber > 0)
        {
   
   
            stringRedisTemplate.opsForValue().set("inventory001",String.valueOf(--inventoryNumber));
            retMessage = "成功卖出一个商品,库存剩余:"+inventoryNumber;
            System.out.println(retMessage+"\t"+"服务端口号"+port);
        }else{
   
   
            retMessage = "商品卖完了,o(╥﹏╥)o";
        }
    }finally {
   
   
        //改进点,只能删除属于自己的key,不能删除别人的
        if(redissonLock.isLocked() && redissonLock.isHeldByCurrentThread())
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lucky_Turtle

感谢您的打赏,作者会多多努力的

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值