爬梯:浅谈高并发下分布式集群锁的实现

学习资料:图灵诸葛

分布式锁问题及解决方案

模拟高并发情况下分布式集群的锁应对情况。

1、分布式集群的问题复现

制造一个双程序负载场面,共同访问单个redis减扣库存

场景方案图

在这里插入图片描述

减库存程序

@RequestMapping("/reduceStock")
public String reduceStock(){

    synchronized (this){
        int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
        if(stock>0){
            stringRedisTemplate.opsForValue().set("stock",--stock+"");
            System.out.println("扣减成功。当前库存:"+stock);
        }else{
            System.out.println("扣减失败!当前库存:"+stock);
        }
    }

    return "ok";
}

nginx

upstream myserver{
        server 192.168.0.101:8080;
        server 192.168.0.101:8090;
    }

    server {
        listen       80;
        server_name  192.168.1.106;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            proxy_pass http://myserver;
            index  index.html index.htm;
        }
}

单机访问

在这里插入图片描述

访问Nginx

在这里插入图片描述

两次访问都落在8080应用上

在这里插入图片描述

使用Jmeter简单压测

在这里插入图片描述

在这里插入图片描述

结论:分布式环境下出现超卖情况。

2、使用Redis setnx实现分布式锁

@RequestMapping("/reduceStock")
public String reduceStock(){
    String productKey = "book001";//产品key
    try {
        String productUUid = UUID.randomUUID().toString();
        //使用nx确保只有一个应用线程能拿到产品的key,然后进行后续操作
        Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(productKey, productUUid, 10, TimeUnit.SECONDS);

        /*
            关于key超时的后业务代未完成却提前过期的问题,
            可以在获取到redis锁之后,开启一个新线程,去循环判断当前redis锁是否存,
            :若存在则设置为10/3,既业务代码大概进行实践的三分之一。
            :若存在则关闭线程。
            目的是控制超时时间在业务代码完成之后超时,让业务代码finally去施放redis锁。
             */

        if (result) {
            return "try again.";
        }

        int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
        if (stock > 0) {
            stringRedisTemplate.opsForValue().set("stock", --stock + "");
            System.out.println("扣减成功。当前库存:" + stock);
        } else {
            System.out.println("扣减失败!当前库存:" + stock);
        }
    } finally {
        //施放产品key
        stringRedisTemplate.delete(productKey);
    }
    return "ok";
}

3、使用redisson实现分布式锁

官网:https://redisson.org

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.6.5</version>
</dependency>

程序

@RequestMapping("/reduceStock")
public String reduceStock(){
    String productKey = "book001";//产品key
    RLock lock = redisson.getLock(productKey);//创建产品锁

    try {
        lock.lock(10,TimeUnit.SECONDS);//上锁

        int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
        if (stock > 0) {
            stringRedisTemplate.opsForValue().set("stock", --stock + "");
            System.out.println("扣减成功。当前库存:" + stock);
        } else {
            System.out.println("扣减失败!当前库存:" + stock);
        }
    } finally {
        //施放产品key
        lock.unlock();
    }
    return "ok";
}

redisson原理图解(概括)

在这里插入图片描述

4、分布式锁性能提升

1、产品库存分段存储:

  • p_001:10
  • p_002:10
  • p_003:10

5、Redis集群,主从切换导致锁失效

  1. redlock(不推荐)
  2. zookeeper(更完善)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值