redis缓存击穿,redisson分布式锁,redis逻辑过期

这篇具有很好参考价值的文章主要介绍了redis缓存击穿,redisson分布式锁,redis逻辑过期。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

什么是缓存击穿:

缓存击穿是指在高并发环境下,某个热点数据的缓存过期,导致大量请求同时访问后端存储系统,引起系统性能下降和后端存储压力过大的现象。

解决方案:
1. redisson分布式锁

本质上是缓存重建的过程中,大量的请求访问到后端的数据库导致数据库压力过大
那么可以使用redisson分布式锁来对缓存重建的过程加锁
其它的线程只有缓存重建完毕之后才可以访问
缺点:所有的请求都要等待拿到锁的线程来进行缓存重建
优点:数据拥有高一致性,适用于某些涉及“钱”的业务,或者要求数据的强一致性的。

  1. 新建redisson子工程单独作为微服务名字叫redisson-starter
  2. 引入redisson相关依赖
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.17.5</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.18</version>
        </dependency>
  1. 项目结构
    redis缓存击穿,redisson分布式锁,redis逻辑过期,面试题,缓存,redis,分布式
    RedissonConfigProperties:一些redisson需要的配置项,如果是集群此处不能用这种方式
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Data
@ConfigurationProperties(prefix = "redisson-lock")
public class RedissonConfigProperties {

    private String redisHost;

    private String redisPort;

}

RedissonConfig:配置RedissonClient,并且加入了一些自动装配的配置

import com.yonchao.redisson.service.RedissonLockService;
import lombok.Data;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;

@Data
@Configuration
@EnableConfigurationProperties({RedissonConfigProperties.class})
//当引入Service接口时
@ConditionalOnClass(RedissonLockService.class)
public class RedissonConfig {


    @Autowired
    private RedissonConfigProperties redissonConfigProperties;

    /**
     * 对 Redisson 的使用都是通过 RedissonClient 对象
     * @return
     */
    @Bean(destroyMethod="shutdown") // 服务停止后调用 shutdown 方法。
    public RedissonClient redisson() {
        // 1.创建配置
        Config config = new Config();
        // 集群模式
        // config.useClusterServers().addNodeAddress("127.0.0.1:7004", "127.0.0.1:7001");
        // 2.根据 Config 创建出 RedissonClient 示例。
        config.useSingleServer().setAddress("redis://"+redissonConfigProperties.getRedisHost()+":"+redissonConfigProperties.getRedisPort());
        return Redisson.create(config);
    }
}

spring.factories:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.yonchao.redisson.service.RedissonLockService

业务类:文章来源地址https://www.toymoban.com/news/detail-736528.html

import com.yonchao.redisson.service.RedissonLockService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class RedissonLockServiceImpl implements RedissonLockService {
    @Autowired
    private RedissonClient redissonClient;
    /**
     * 加锁
     * @param lockKey
     * @return
     */
    public boolean acquireLock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(30, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
    }
    /**
     * 释放锁
     * @param lockKey
     * @return
     */
    public void releaseLock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.unlock();
    }
}
  1. 其它微服务通过pom引入redisson-starter微服务
    redis缓存击穿,redisson分布式锁,redis逻辑过期,面试题,缓存,redis,分布式
  2. 重建缓存过程中使用分布式锁
    首先注入RedissonClient
    接着判断布隆过滤器
    接着从缓存中读数据
    读不到的话需要重建缓存
    重建缓存:
    首先获取分布式锁
    获取成功了就查询数据库并且重建缓存返回数据最后释放锁
    获取分布式锁失败就等待1秒接着递归这个方法,直到有一个线程重建缓存成功。
    /**
     * 使用逻辑过期的方式
     * @param id
     * @return
     */
    @Override
    public ResponseResult selectArticleLogicalExpiration(Long id) {
        // 首先经过布隆过滤器
        // 判断这个id是不是在布隆过滤器中
        boolean mightContain = bloomFilter.mightContain(id);

        // 不存在直接返回
        if (!mightContain) {
            return ResponseResult.okResult();
        }
        
        // 首先从缓存中获取数据
        Object articleObj = redisTemplate.opsForValue().get(ARTICLE_KEY + id);
        
        if (Objects.nonNull(articleObj)){

            String articleJSON = (String) articleObj;

            JSONObject jsonObject = JSON.parseObject(articleJSON);

            Long expired = jsonObject.getLong("expired");
            // 旧的文章对象
            ApArticle article = JSON.parseObject(articleJSON, ApArticle.class);
            if (Objects.nonNull(expired)){
                // 未过期直接返回
                if (expired - System.currentTimeMillis() > 0) {

                    return ResponseResult.okResult(article);
                }

                // 过期了进行缓存的重建
                boolean acquiredLock = redissonLockService.acquireLock(lockKeyRedisson);
                // 拿到锁了就 新开一个线程 进行缓存的重建 此处使用分布式锁,只会有一个线程抢占到缓存重建所以不用使用线程池
                if (acquiredLock) {
                    try {
                        new Thread(() -> {
                            // 直接重建缓存,不关心返回值
                            rebuildCache(id);
                        }).start();

                    } finally {
                        // 最后释放锁
                        redissonLockService.releaseLock(lockKeyRedisson);
                    }
                }
                // 开启多线程后直接返回旧的数据
                return ResponseResult.okResult(article);
            }

        }
        // 缓存中根本没有,那么需要直接加锁重建缓存,此时不能多线程的去重建缓存,只能通过分布式锁的方式,
        boolean lockAcquired = redissonLockService.acquireLock(lockKeyLogicalExpiration);
        if (lockAcquired){
            try {
                ApArticle apArticle = rebuildCache(id);
                if (Objects.isNull(apArticle)){
                    // 数据不存在就直接返回
                    return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
                }
                // 返回获得的文章数据
                return ResponseResult.okResult(apArticle);

            } finally {
                // 最后释放锁
                redissonLockService.releaseLock(lockKeyLogicalExpiration);
            }
        } else {
            // 没有获取到锁就等待一段时间然后再次尝试获取锁
            try {
                Thread.sleep(1000);
            }catch (Exception e){
                log.error(e.getMessage());
            }
            // 等待一段时间重新校验有没有缓存
            return selectArticleLogicalExpiration(id);
        }
    }


    public ApArticle rebuildCache(Long id){
        // 重建缓存
        ApArticle articleDatabase = getById(id);
        // 重建缓存
        if (Objects.nonNull(articleDatabase)) {
            // 设置逻辑过期时间
            // 转为jsonString
            String articleJsonString = JSON.toJSONString(articleDatabase);
            // 转为JSONObject
            JSONObject articleJsonObject = JSON.parseObject(articleJsonString);
            // 当前时间戳加上 设置的过期时间*1000 因为时间戳是毫秒
            articleJsonObject.put("expired", System.currentTimeMillis() + ARTICLE_EXPIRED * 1000);
            redisTemplate.opsForValue().set(ARTICLE_KEY + id, JSON.toJSONString(articleJsonObject));
            // 布隆过滤器过滤过的,这个肯定存在
            return articleDatabase;
        }
        return null;
    }

到了这里,关于redis缓存击穿,redisson分布式锁,redis逻辑过期的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Redis实战——Redisson分布式锁

    目录 1 基于Redis中setnx方法的分布式锁的问题 2 Redisson         2.1 什么是Redisson         2.2 Redisson实现分布式锁快速入门         2.3 Redisson 可重入锁原理                 什么是可重入锁?                 Redisson中又是如何实现的呢?         2

    2024年02月15日
    浏览(49)
  • redis的分布式事务-redisson

    Redisson分布式锁是一种基于redis实现的分布式锁,它利用redis的setnx命令实现分布式锁的互斥访问。同时还支持锁的自动续期功能,可以避免因为某个进程崩溃或者网络故障导致锁无法释放的情况。 只要线程一加锁成功,就会启动一个watch dog看门狗,它是一个后台线程,会每隔

    2024年02月13日
    浏览(47)
  • 高并发下的缓存击穿、雪崩、穿透和分布式锁(三)

    概念: 去查询缓存和数据库都不存在的数据,然后大量请求不存在的数据,导致数据库压力过大崩溃。 解决方案: 把不存在的数据null存入缓存,并给个短期的过期时间。 概念: 缓存采用相同的过期时间,然后在某一时刻会同时过期,然后请求全部访问数据库,导致数据库

    2024年02月07日
    浏览(37)
  • 【go项目-geecache】动手写分布式缓存 - day6 - 防止缓存击穿

    【go项目-geecache】动手写分布式缓存 - day1 - 实现LRU算法 【go项目-geecache】动手写分布式缓存 - day2 - 单机并发缓存 【go项目-geecache】动手写分布式缓存 - day3 - HTTP 服务端 【go项目-geecache】动手写分布式缓存 - day4 - 一致性哈希(hash) 【go项目-geecache】动手写分布式缓存 - day5 - 分布

    2023年04月20日
    浏览(41)
  • redis实战-redis实现分布式锁&redisson快速入门

    前言 集群环境下的并发问题  分布式锁 定义 需要满足的条件 常见的分布式锁 redis实现分布式锁 核心思路 代码实现 误删情况 逻辑说明 解决方案 代码实现 更为极端的误删情况 Lua脚本解决原子性问题 分布式锁-redission redisson的概念 快速入门 总结 在前面我们已经实现了单机

    2024年02月09日
    浏览(52)
  • Redis分布式锁及Redisson的实现原理

    Redis分布式锁 在讨论分布式锁之前我们回顾一下一些单机锁,比如synchronized、Lock 等 锁的基本特性: 1.互斥性:同一时刻只能有一个节点访问共享资源,比如一个代码块,或者同一个订单同一时刻只能有一个线程去支付等。 2.可重入性: 允许一个已经获得锁的线程,在没有释

    2024年02月06日
    浏览(46)
  • Redis分布式缓存

    -- 基于Redis集群解决单机Redis存在的问题 单机的Redis存在四大问题: Redis有两种持久化方案: RDB持久化 AOF持久化        RDB全称Redis Database Backup file(Redis数据备份文件),也被叫做 Redis数据快照 。简单来说就是把 内存中的所有数据都记录到磁盘 中。当Redis实例故障重启后,

    2024年02月12日
    浏览(51)
  • Redis 分布式缓存

    单点 Redis 的问题及解决 数据丢失:实现Redis数据持久化 并发能力:搭建主从集群,实现读写分离 存储能力:搭建分片集群,利用插槽机制实现动态扩容 故障恢复能力:利用哨兵机制,实现健康检测和自动恢复 RDB RDB全称Redis Database Backup file (Redis数据备份文件),也被叫做

    2024年02月10日
    浏览(51)
  • 【业务功能100】补充代码【业务功能88】微服务-springcloud-分布式锁-redis-redisson-springcache

    采用redisson做分布式锁,完成数据的查询接口功能getCatelog2JSONRedis 原先从mysql数据库查询的效率较低,现在将部分固定数据展示比如页面的树形栏目信息等,存储到 redis缓存 ,然后基于分布式集群,需要结合本地锁(synchronized )与分布式锁(redissonClient.getLock(“catelog2JSON-lock”

    2024年02月09日
    浏览(46)
  • 【实践篇】Redis最强Java客户端(三)之Redisson 7种分布式锁使用指南

    前两章我们了解了《【实践篇】Redis最强Java客户端(一)之Redisson入门介绍》和《【实践篇】Redis最强Java客户端(二)之Redisson基础概念》本章第三章主要介绍Redisson的七种分布式锁,分别是简单锁、公平锁、可重入锁、红锁、读写锁、信号量和闭锁。下面是每种锁的基本概念、使用

    2024年02月09日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包