一、前言

在分布式环境下,传统的一些技术会失败,比如传统的synchronized或者lock锁,以及创建数据库的事务,无法保证ACID,还有定时任务也可能会出现重复执行的问题。

二、分布式锁介绍

由于传统的锁是基于Tomcat服务器内部的,搭建了集群之后,导致锁失效,使用分布式锁来处理。

图片.png

三、分布式锁解决方案【重点】

3.1 搭建环境

创建SpringBoot

编写抢购的业务

  1. @RestController
  2. public class SecondKillController
  3. //1. 准备商品的库存
  4. public static MapString, Integer> itemStock = new HashMap<>0):
  5. 1/2.准备商品的订单
  6. public static Map«String, Integer> itemOrder = new HashMape>();
  7. static{
  8. itemStock.put("FRI",10000):
  9. itemOrder.put("#B)",0):
  10. }
  11. @GetMapping("/kill")
  12. public String kill(String item) throws InterruptedException(
  13. //1.减库存
  14. Integer stock = itemStock.get(item);
  15. if(stock <= 0){
  16. return “商品库存数不足!!!";
  17. }
  18. Thread.sleep(100);
  19. itemStock.put (item, stock - 1);
  20. //2.创建订单
  21. Thread.sleep(100) ;
  22. itemOrder.put (item, itemOrder.get(item) + 1);
  23. return "抢购成功!!!" + item + ": 剩余库存数为 - " + itemStock.get (item) + ", 订单数为 - " + itemOrder.get(item);
  24. }
  25. }

下载ab压力测试

ab -n请求数 一。并发数 访问的路径

测试结果

图片.png

3.2 zookeeper实现分布式锁原理

图片.png

3.3 Zookeeper实现分布式锁

导入依赖

  1. <dependency>
  2. <groupId>org.apache.zookeeper</groupId>
  3. <artifactId>zookeeper</artifactId>
  4. <version>3.6.0</version>
  5. <exclusions>
  6. <exclusion>
  7. <artifactId>slf4j-api</artifactId>
  8. <groupId>org.slf4j</groupId>
  9. </exclusion>
  10. <exclusion>
  11. <artifactId>slf4j-log4j12</artifactId>
  12. <groupId>org.slf4j</groupId>
  13. </exclusions>
  14. <exclusion>
  15. <artifactId>log4j</artifactId>
  16. <groupId>log4j</groupId>
  17. </exclusion>
  18. </exclusions>
  19. </dependency>
  20. <dependency>
  21. <groupId>org.apache.curator</groupId>
  22. <artifactId>curator-recipes</artifactId>
  23. <version>4.0.1</version>
  24. <exclusions>
  25. <exclusion>
  26. <artifactId>slf4j-api</artifactId>
  27. <groupId>orq.slf4j</groupId>
  28. </exclusion>
  29. </exclusions>
  30. </dependency>

编写配置类

  1. @Configuration
  2. public class ZkConfig{
  3. @Bean
  4. public CuratorFramework cf(){
  5. RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000,2);
  6. CuratorFramework curatorFramework = CuratorFrameworkFactory.builder()
  7. .connectString("192.168.199.109:2181,192.168.199.109:2182,192.168.199.109:2183")
  8. .retryPolicy(retryPolicy)
  9. .buildO;
  10. curatorFramework.start();
  11. return curatorFramework;
  12. }
  13. }

在业务代码中添加分布式锁

  1. @Autowired
  2. private CuratorFramework cf;
  3. InterProcessMutex lock = new InterProcessMutex(cf,"/lock") ;
  4. //...加锁
  5. lock.acquire();
  6. lock .acquire(1,TimeUnit.SECONDS);//指定排队多久就放奔获取锁资源
  7. //-----------业务逻辊代码-----------
  8. //释放锁
  9. lock.release();

3.4 Redis实现分布式锁原理

图片.png

3.5Redis实现分布式锁

导入依赖,添加配置文件

  1. # redis依赖
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-data-redis</artifactId>
  5. </dependency>
  6. # 配置文件
  7. spring:
  8. redis:
  9. host: 192.168.199.109
  10. port: 6379

编号工具类

@Component
public class RedisLockUtil{
    @Autowired
    private StringRedisTemplate redisTemplate;

    public boolean lock(String key, String value, int second){
        return redisTemplate.opsForValue().setIfAbsent(key,value, second, TimeUnit.SECONDS);
    }

    public void unlock(String key) {
        redisTemplate.delete(key);
    }
}

修改业务逻辑代码

@GetMapping("/redis/kill")
public String redisKill(String item) throws Exception (
    //...加锁
    if(lock.lock (item, System.currentTimeMillis0) +"",1)){
    //业务代码 .....


    //释放锁
    lock.unlock(itme);
    }
}

再测试