ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

分布式缓存和分布式锁

2021-07-09 14:00:21  阅读:176  来源: 互联网

标签:info 缓存 log lock redis 获取 tryLock 分布式


分布式缓存和分布式锁

个人博客传送门


一.技术方案选型:

  • 基于redisson的分布式缓存和springboot的整合实现
  • 对于锁的选择:可重入锁、可重入公平锁、联锁、红锁等
  • 对于业务场景的支持:
  • lock.lock() 不设置过期时间和等待时间
  • lock.lock(10,TimeUnit) 设置过期时间,超过过期时间主动释放锁
  • lock.lock(20,10,TimeUnit) 设置竞争获取锁的最大等待时间和锁的超时时间

二.依赖和版本说明

  • 整合redisson引入相关的包
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>${version}</version>
</dependency>
  • 版本需要注意和springboot的版本需要兼容具体的根据springboot的版本进行选择
  • 对于关系可以参考 redisson整合springboot
  • 配置项
spring:
  redis:
    database: #库名
    host:     #主机名
    port:     #端口号
    password: #密码
    ssl:      #ssl认证
    timeout:  #超时时间  
    cluster:  
      nodes:  #集群的节点
    sentinel:
      master: #哨兵的mastername
      nodes:  #节点

参数的具体说明和配置可以参考文档 配置方法

  • 使用方法

可以注入RedissonClient或者RedisTemplate使用

三.项目集成方案

1.数据库和redis一致性的方案

  • 操作redis的方法按照如下操作
  • 主动获取redis锁,当未获取到锁的时候登录获取
  • 主要设置超时时间和最大等待时间
   @Resource
    RedissonClient redissonClient;

    /**
     * rule
     *
     * @return
     * @throws InterruptedException
     */
    @GetMapping("/lock")
    public String lock() throws InterruptedException {
        RLock lock = redissonClient.getFairLock("anyLock");
        // 尝试加锁,最多等待10秒,上锁以后10秒自动解锁
        lock.lock.tryLock( 10,10, TimeUnit.SECONDS);
        try {
            log.info("lock 睡眠开始");
            //具体的业务操作
            Thread.sleep(9000);
            log.info("lock 睡眠结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            log.info("lock 主动释放锁");
            lock.unlock();
        }
        return "";
    }

2.查询接口获取到最新数据的方案

  • 查询redis最新的数据的接口如下
  • 判断是否有锁,未加说明redis为最新的值,直接进行查询
  • 所有加索,则当前正在修改redis的操作,即需要等待操作完成释放掉锁之后,获取锁才能进行redis的操作
    @GetMapping("/tryLock")
    public String tryLock() throws InterruptedException {
        RLock lock = redissonClient.getFairLock("anyLock");
        if(lock.isLocked()){
            // 尝试加锁,最多等待20秒,上锁以后10秒自动解锁
            boolean res = lock.tryLock(20, 10, TimeUnit.SECONDS);
            log.info("tryLock 方法获取到锁:{}",res);
            if (res) {
                try {
                    log.info("tryLock 睡眠开始");
                    Thread.sleep(9000);
                    log.info("tryLock 睡眠结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                    log.info("tryLock 主动释放锁");
                }
            }else {
                log.info("tryLock 方法未获取到锁:{}",res);
            }
        }else {
            //查询接口,未加锁直接获取当前的redis数据
            log.info("未加锁直接过去资源");
        }
        return "";
    }

操作工具类(koal.ngaudit.rule.util)

@Slf4j
@Component
public class RedissonLockUtil {

    @Resource
    RedissonClient redissonClient;

    /**
     * 主动获取锁,若超时直接返回异常
     * 
     * @param lockName 锁定资源的key 
     * @param waitTime 获取锁最大等待时间
     * @param timeOutTime 超时时间
     * @return
     * @throws InterruptedException
     */
    public boolean tryLock(String lockName,long waitTime,long timeOutTime) throws InterruptedException {
        RLock fairLock = redissonClient.getFairLock(lockName);
        return fairLock.tryLock( waitTime,timeOutTime, TimeUnit.SECONDS);
    }

    /**
     * 查询时候判断是否可以进行查询操作,若超时直接返回异常
     *
     * @param lockName 锁定资源的key 
     * @param waitTime 获取锁最大等待时间
     * @param timeOutTime 超时时间
     * @return
     * @throws InterruptedException
     */
    public boolean queryAndTryLock(String lockName, long waitTime, long timeOutTime) throws InterruptedException {
        RLock lock = redissonClient.getFairLock(lockName);
        if(lock.isLocked()){
            return lock.tryLock(waitTime, timeOutTime, TimeUnit.SECONDS);
        }else {
            log.info("未加锁直接获取资源");
            return true;
        }
    }
    

四.实现方案设计

1.业务操作数据库和redis的方案

业务操作 Redis 锁 Mysql Redis 尝试获取redis锁 1 返回redis锁 2 等待获取锁 3 返回redis锁 4 alt [获取到] [未获取到] 对业务数据进行处理 5 返回处理结果 6 删除掉对应业务数据 7 释放掉对业务对象的锁 8 业务操作 Redis 锁 Mysql Redis

2.业务操作数据库和redis的方案

业务查询 Redis 锁 Redis APi 判断操作的对象是否加锁 1 查询redis 2 等待获取锁 3 返回redis锁 4 查询redis 5 alt [未加锁] [加锁] 返回redis的结果 6 返回结果 7 调用api查询 8 查询接口结果缓存redis,空值处理防止缓存穿透 返回最新的数据 9 返回结果 10 alt [存在] [不存在] 业务查询 Redis 锁 Redis APi

五.注意事项

  1. redis的编码格式问题
  2. 获取锁的最大等待时间和超时时间问题
  3. api的接口feign调用的熔断和数据库不存在的空值存储问题
  4. 调用util的方法,需要在finally中主动释放锁

在这里插入图片描述

标签:info,缓存,log,lock,redis,获取,tryLock,分布式
来源: https://blog.csdn.net/zhaokk_git/article/details/118605024

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有