• redis分布式锁


    部署在一个tomcat下

    1. 模拟一个减库存的代码 这段代码请求少的话是没有问题的,但是在高并发的场景下就会出现问题
      @RequestMapping("redisTest")
      public String redisTest() {
          String key = "count";
          //获取库存数量
          int count = Integer.parseInt(stringRedisTemplate.opsForValue().get(key));
          //有库存减少
          if (count > 0) {
              count = count - 1;
              stringRedisTemplate.opsForValue().set(key, String.valueOf(count));
              System.out.println("扣除成功,剩余数量:" + count);
          } else {
              System.out.println("扣除失败");
          }
          return "end";
      }
      
    2. 当前redis count的值为500
    3. 使用jmemter 200个线程同时访问

    4. 结果,可以看到有些库存并没有减掉
    5. 解决方案,加个方法锁(必须获取到锁才能进入,否则阻塞)
          @RequestMapping("redisTest")
      public synchronized String redisTest() {
          System.out.println(this);
      
          String key = "count";
          //获取库存数量
          int count = Integer.parseInt(stringRedisTemplate.opsForValue().get(key));
          //有库存减少
          if (count > 0) {
              count = count - 1;
              stringRedisTemplate.opsForValue().set(key, String.valueOf(count));
              System.out.println("扣除成功,剩余数量:" + count);
          } else {
              System.out.println("扣除失败");
          }
          return "end";
      }
      

    集群

    1. 以上是一个tomcat,如果有两个tomcat使用nginx代理做负载均衡指向8080和8081端口
    2. 本机启动两个客户端,启动jmemter测试,可以看到会有重复的剩余数量

    3. 此时我们就需要使用到redis的分布式锁来解决,这种也没有完美的解决方案
    /**
     * 分布式锁
     *    1.  stringRedisTemplate.opsForValue().setIfAbsent("key", "value");if (!flag){return "";}finally { stringRedisTemplate.delete("key");}   如果加锁后运维部署把程序kill了,其他线程永远进不来
     *   2. stringRedisTemplate.opsForValue().setIfAbsent("key", "value", 10, TimeUnit.SECONDS);finally { stringRedisTemplate.delete("key");}
     *   在超高并发时程序运行时间不一致,第一个线程15秒 10秒后锁自动解除程序还未运行完,第二个线程进来获得锁后第一个线程运行完把锁删除了  依次类推,释放的永远不是自己的锁
     *   3. 动态设置锁的方法String lockValue = UUID.randomUUID().toString();Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(lock, lockValue, 10, TimeUnit.SECONDS);if (!flag) { return ""; }
     *   if (lockValue.equals(stringRedisTemplate.opsForValue().get(lock))) { stringRedisTemplate.delete("key"); }, 这里还是会出现锁失效的可能
     *   4. 续命   获取锁后开一个定时器进行在锁自动释放前获取当前自己锁是否被释放 如果没有证明代码还没执行完,进行续命,若执行完删除当前定时器
     */
    

    redisson

    redis客户端,内部实现了很多对分布式锁的支持

    <dependency>
    	<groupId>org.redisson</groupId>
    	<artifactId>redisson</artifactId>
    	<version>3.13.2</version>
    </dependency>	
    
    @Bean
    public Redisson redisson() {
       Config config = new Config();
       config.useSingleServer().setAddress("redis://192.168.150.110").setDatabase(0);
        return ((Redisson) Redisson.create(config));
     }
        String lockKey = "key";
        RLock redissonLock = redisson.getLock(lockKey);
        try {
         	//内部使用续命的方式 使用lua脚本保证原子性
            redissonLock.lock();
            String countKey = "count";
            //获取库存数量
            int count = Integer.parseInt(stringRedisTemplate.opsForValue().get(countKey));
            //有库存减少
            if (count > 0) {
                count = count - 1;
                stringRedisTemplate.opsForValue().set(countKey, String.valueOf(count));
                System.out.println("扣除成功,剩余数量:" + count);
            } else {
                System.out.println("扣除失败");
            }
        } finally {
            redissonLock.unlock();
        }
        return "end";
    
    作者: JaminYe
    版权声明:本文原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
  • 相关阅读:
    406, "PRECONDITION_FAILED
    windows10x64环境安装RabbitMQ
    jquery插件formValidator的ajaxValidator传参数问题
    “~/Views/Home/Text.aspx”处的视图必须派生自 ViewPage、ViewPage<TModel>、ViewUserControl 或 ViewUserControl<TModel>。
    无法安装程序包“MIcrosoft.Owin.Security 2.0.2”。您正在尝试将此程序包安装到某个将“.NETFramework,Version=v4.0”作为目标的项目中。
    MSSQL优化之——查看语句执行情况
    C# 测试代码运行时间
    转换 Html 内容为纯文本内容(html,文本互转)
    腾讯微博OAuth2.0 .NET4.0 SDK 发布以及网站腾讯微博登陆示例代码(原创)
    QQ互联OAuth2.0 .NET SDK 发布以及网站QQ登陆示例代码(转)
  • 原文地址:https://www.cnblogs.com/JaminYe/p/13418106.html
Copyright © 2020-2023  润新知