分布式锁以及分布式锁框架Redisson

分布式锁使用

分布式锁特点

1、互斥性
和我们本地锁一样互斥性是最基本,但是分布式锁需要保证在不同节点的不同线程的互斥。

2、可重入性
同一个节点上的同一个线程如果获取了锁之后那么也可以再次获取这个锁。

3、锁超时
和本地锁一样支持锁超时,加锁成功之后设置超时时间,以防止线程故障导致不释放锁,防止死锁。

4、高效,高可用
加锁和解锁需要高效,同时也需要保证高可用防止分布式锁失效,可以增加降级。

redission是基于redis的,redis的故障就会导致redission锁的故障,因此redission支持单节点redis、reids主从、reids集群

5、支持阻塞和非阻塞
和 ReentrantLock 一样支持 lock 和 trylock 以及 tryLock(long timeOut)。

7.5.2 锁的分类的总结

1、乐观锁与悲观锁

  • 乐观锁
  • 悲观锁

2、可重入锁和非可重入锁

  • 可重入锁:当在一个线程中第一次成功获取锁之后,在此线程中就可以再次获取
  • 非可重入锁

3、公平锁和非公平锁

  • 公平锁:按照线程的先后顺序获取锁
  • 非公平锁:多个线程随机获取锁

4、阻塞锁和非阻塞锁

  • 阻塞锁:不断尝试获取锁,直到获取到锁为止

  • 非阻塞锁:如果获取不到锁就放弃,但可以支持在一定时间段内的重试

    ​ ——在一段时间内如果没有获取到锁就放弃

Redission的使用

1、获取锁——公平锁和非公平锁

//获取公平锁
RLock lock = redissonClient.getFairLock(skuId);

//获取非公平锁
RLock lock = redissonClient.getLock(skuId);

2、加锁——阻塞锁和非阻塞锁

//阻塞锁(如果加锁成功之后,超时时间为30s;加锁成功开启看门狗,剩5s延长过期时间)
lock.lock();
//阻塞锁(如果加锁成功之后,设置自定义20s的超时时间)
lock.lock(20,TimeUnit.SECONDS);

//非阻塞锁(设置等待时间为3s;如果加锁成功默认超时间为30s)
boolean b = lock.tryLock(3,TimeUnit.SECONDS);
//非阻塞锁(设置等待时间为3s;如果加锁成功设置自定义超时间为20s)
boolean b = lock.tryLock(3,20,TimeUnit.SECONDS);

3、释放锁

lock.unlock();

4、应用示例

//公平非阻塞锁
RLock lock = redissonClient.getFairLock(skuId);
boolean b = lock.tryLock(3,TimeUnit.SECONDS);

 

分布式锁框架-Redisson

Redisson是基于Redis+看门狗机制的分布式锁框架

Redisson介绍

Redisson在基于NIO的Netty框架上,充分的利用了Redis键值数据库提供的一系列优势,在Java实用工具包中常用接口的基础上,为使用者提供了一系列具有分布式特性的常用工具类。使得原本作为协调单机多线程并发程序的工具包获得了协调分布式多机多线程并发系统的能力,大大降低了设计和研发大规模分布式系统的难度。同时结合各富特色的分布式服务,更进一步简化了分布式环境中程序相互之间的协作

在SpringBoot应用中使用Redisson

  • 添加依赖

    <dependency>
        <groupId>org.redisson</groupId>
        <artifactId>redisson</artifactId>
        <version>3.12.0</version>
    </dependency>
    
  • 配置yml

    redisson:
      addr:
        singleAddr:
          host: redis://192.168.10.101:6379
          password: 密码,若没有则忽略
          database: 0
    
  • 配置RedissonClient

    @Configuration
    public class RedissonConfig {
    
        @Value("${redisson.addr.singleAddr.host}")
        private String host;
    
        @Value("${redisson.addr.singleAddr.password}")
        private String password;
    
        @Value("${redisson.addr.singleAddr.database}")
        private int database;
    
        @Bean
        public RedissonClient redissonClient(){
            Config config = new Config();
            config.useSingleServer()
                .setAddress(host)
                .setPassword(password)
                .setDatabase(database);
            return Redisson.create(config);
        }
    
    }
    
  • 在秒杀业务实现中注入RedissonClient对象

    @Service
    public class OrderServiceImpl2 implements OrderService {
        @Autowired
        private ProductMapper productMapper;
        @Autowired
        private StringRedisTemplate stringRedisTemplate;
        @Autowired
        private RedissonClient redissonClient;
    
        @Override
        public ResultVO orderHandle(Long userId, Integer productId, Integer num) {
            //构造锁
            RLock lock = redissonClient.getLock("product_" + productId);
            //加锁:阻塞锁
            lock.lock();
            try {
                //1.查询商品(Product)库存
                Product product = productMapper.selectById(productId);
                //2.校验库存(√)  stock>num
                if (product.getProductStock() >= num) {
                    System.out.println("-----------生成订单");//3.生成/保存订单
                    System.out.println("-----------生成订单快照");  //4.保存订单快照
                    int newStock = product.getProductStock() - num; //5.扣减库存
                    product.setProductStock(newStock);
                    int i = productMapper.updateById(product);
                    System.out.println("------------订单提交完成!");
                    return new ResultVO(0, "提交订单成功!", "orderId");
                } else {
                    return new ResultVO(1, "库存不足", null);
                }
            }catch (Exception e){
                e.printStackTrace();
            } finally {
                //释放锁
                lock.unlock();
            }
            return null;
        }
    }
    

Redisson工作原理

  • Redis的setnx操作特性

  • 看门狗线程

Redisson工作原理图
在这里插入图片描述

Redisson使用扩展

7.4.1 Redisson单机连接
  • application.yml

    redisson:
      addr:
        singleAddr:
          host: redis://ip地址:6379
          password: 密码,若没有则忽略
          database: 0
    
  • RedissonConfig

    @Configuration
    public class RedissonConfig {
    
        @Value("${redisson.addr.singleAddr.host}")
        private String host;
    
        @Value("${redisson.addr.singleAddr.password}")
        private String password;
    
        @Value("${redisson.addr.singleAddr.database}")
        private int database;
    
    
        @Bean
        public RedissonClient redissonClient(){
            Config config = new Config();
            config.useSingleServer()
                .setAddress(host)
                .setPassword(password)
                .setDatabase(database);
            return Redisson.create(config);
        }
    
    }
    

Redisson集群连接

  • application.yml

    redisson:
      addr:
        cluster:
          hosts: redis://192.168.10.101:6370,...,redis://192.168.10.101:6373
          password: 密码,若没有则忽略
    
  • RedissonConfig——RedissonClient对象

    @Configuration
    public class RedissonConfig {
    
        @Value("${redisson.addr.cluster.hosts}")
        private String hosts;
        @Value("${redisson.addr.cluster.password}")
        private String password;
    
        /**
         * 集群模式
         * @return
         */
        @Bean
        public RedissonClient redissonClient(){
            Config config = new Config();
            config.useClusterServers().addNodeAddress(hosts.split("[,]"))
                    .setPassword(password)
                    .setScanInterval(2000)
                    .setMasterConnectionPoolSize(10000)
                    .setSlaveConnectionPoolSize(10000);
            return Redisson.create(config);
        }
    
    }
    

Redisson主从连接

  • application.yml

    redisson:
      addr:
        masterAndSlave:
          masterhost: redis://47.96.11.185:6370
          slavehosts: redis://47.96.11.185:6371,redis://47.96.11.185:6372
          password: 密码,若没有则忽略
          database: 0
    
  • RedissonConfig — RedissonClient

    @Configuration
    public class RedissonConfig3 {
    
        @Value("${redisson.addr.masterAndSlave.masterhost}")
        private String masterhost;
        @Value("${redisson.addr.masterAndSlave.slavehosts}")
        private String slavehosts;
        @Value("${redisson.addr.masterAndSlave.password}")
        private String password;
        @Value("${redisson.addr.masterAndSlave.database}")
        private int database;
    
        /**
         * 主从模式
         * @return
         */
        @Bean
        public RedissonClient redissonClient(){
            Config config = new Config();
            config.useMasterSlaveServers()
                    .setMasterAddress(masterhost)
                    .addSlaveAddress(slavehosts.split("[,]"))
                    .setPassword(password)
                    .setDatabase(database)
                    .setMasterConnectionPoolSize(10000)
                    .setSlaveConnectionPoolSize(10000);
            return Redisson.create(config);
        }
    
    }
    
  • 17
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值