0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何在SpringBoot中解決Redis的緩存穿透等問題

jf_78858299 ? 來(lái)源:JAVA日知錄 ? 作者:飄渺Jam ? 2023-04-28 11:35 ? 次閱讀

今天給大家介紹一下如何在SpringBoot中解決Redis的緩存穿透、緩存擊穿、緩存雪崩的問題。

緩存穿透

什么是緩存穿透

緩存穿透指的是一個(gè)緩存系統(tǒng)無(wú)法緩存某個(gè)查詢的數(shù)據(jù),從而導(dǎo)致這個(gè)查詢每一次都要訪問數(shù)據(jù)庫(kù)。

常見的Redis緩存穿透場(chǎng)景包括:

  1. 查詢一個(gè)不存在的數(shù)據(jù):攻擊者可能會(huì)發(fā)送一些無(wú)效的查詢來(lái)觸發(fā)緩存穿透。
  2. 查詢一些非常熱門的數(shù)據(jù):如果一個(gè)數(shù)據(jù)被訪問的非常頻繁,那么可能會(huì)導(dǎo)致緩存系統(tǒng)無(wú)法處理這些請(qǐng)求,從而造成緩存穿透。
  3. 查詢一些異常數(shù)據(jù):這種情況通常發(fā)生在數(shù)據(jù)服務(wù)出現(xiàn)故障或異常時(shí),從而造成緩存系統(tǒng)無(wú)法訪問相關(guān)數(shù)據(jù),從而導(dǎo)致緩存穿透。

如何解決

我們可以使用Guava在內(nèi)存中維護(hù)一個(gè)布隆過濾器。具體步驟如下:

  1. 添加Guava和Redis依賴:
<dependency>
    <groupId>com.google.guava<span class="hljs-name"groupId>
    <artifactId>guava<span class="hljs-name"artifactId>
    <version>29.0-jre<span class="hljs-name"version>
<span class="hljs-name"dependency>

<dependency>
    <groupId>org.springframework.boot<span class="hljs-name"groupId>
    <artifactId>spring-boot-starter-data-redis<span class="hljs-name"artifactId>
<span class="hljs-name"dependency>
  1. 創(chuàng)建一個(gè)BloomFilterUtil類,用于在緩存中維護(hù)Bloom Filter。
public class BloomFilterUtil {
    // 布隆過濾器的預(yù)計(jì)容量
    private static final int expectedInsertions = 1000000;
    // 布隆過濾器誤判率
    private static final double fpp = 0.001;
    private static BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()), expectedInsertions, fpp);
    /**
     * 向Bloom Filter中添加元素
     */
    public static void add(String key){
        bloomFilter.put(key);
    }
    /**
     * 判斷元素是否存在于Bloom Filter中
     */
    public static boolean mightContain(String key){
        return bloomFilter.mightContain(key);
    }
}
  1. 在Controller中查詢數(shù)據(jù)時(shí),先根據(jù)請(qǐng)求參數(shù)進(jìn)行Bloom Filter的過濾
@Autowired
private RedisTemplate

緩存擊穿

什么是緩存擊穿

緩存擊穿指的是在一些高并發(fā)訪問下,一個(gè)熱點(diǎn)數(shù)據(jù)從緩存中不存在,每次請(qǐng)求都要直接查詢數(shù)據(jù)庫(kù),從而導(dǎo)致數(shù)據(jù)庫(kù)壓力過大,并且系統(tǒng)性能下降的現(xiàn)象。

緩存擊穿的原因通常有以下幾種:

  1. 緩存中不存在所需的熱點(diǎn)數(shù)據(jù):當(dāng)系統(tǒng)中某個(gè)熱點(diǎn)數(shù)據(jù)需要被頻繁訪問時(shí),如果這個(gè)熱點(diǎn)數(shù)據(jù)最開始沒有被緩存,那么就會(huì)導(dǎo)致系統(tǒng)每次請(qǐng)求都需要直接查詢數(shù)據(jù)庫(kù),造成數(shù)據(jù)庫(kù)負(fù)擔(dān)。
  2. 緩存的熱點(diǎn)數(shù)據(jù)過期:當(dāng)一個(gè)熱點(diǎn)數(shù)據(jù)過期并需要重新緩存時(shí),如果此時(shí)有大量請(qǐng)求,那么就會(huì)導(dǎo)致所有請(qǐng)求都要直接查詢數(shù)據(jù)庫(kù)。

如何解決

主要思路 : 在遇到緩存擊穿問題時(shí),我們可以在查詢數(shù)據(jù)庫(kù)之前,先判斷一下緩存中是否已有數(shù)據(jù),如果沒有數(shù)據(jù)則使用Redis的單線程特性,先查詢數(shù)據(jù)庫(kù)然后將數(shù)據(jù)寫入緩存中。

  1. 添加Redis依賴
<dependency>
    <groupId>org.springframework.boot<span class="hljs-name"groupId>
    <artifactId>spring-boot-starter-data-redis<span class="hljs-name"artifactId>
<span class="hljs-name"dependency>
  1. 在Controller中查詢數(shù)據(jù)時(shí),先從緩存中查詢數(shù)據(jù),如果緩存中無(wú)數(shù)據(jù)則進(jìn)行鎖操作
@Autowired
private RedisTemplate<String, Object> redisTemplate;

@GetMapping("/user/{id}")
public User getUserById(@PathVariable Long id){
    // 先從緩存中獲取值
    String userKey = "user_"+id.toString();
    User user = (User) redisTemplate.opsForValue().get(userKey);
    if(user == null){
        // 查詢數(shù)據(jù)庫(kù)之前加鎖
        String lockKey = "lock_user_"+id.toString();
        String lockValue = UUID.randomUUID().toString();
        try{
            Boolean lockResult = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 60, TimeUnit.SECONDS);
            if(lockResult != null && lockResult){
                // 查詢數(shù)據(jù)庫(kù)
                user = userRepository.findById(id).orElse(null);
                if(user != null){
                    // 將查詢到的數(shù)據(jù)加入緩存
                    redisTemplate.opsForValue().set(userKey, user, 300, TimeUnit.SECONDS);
                }
            }
        }finally{
            // 釋放鎖
            if(lockValue.equals(redisTemplate.opsForValue().get(lockKey))){
                redisTemplate.delete(lockKey);
            }
        }
    }
    return user;
}

緩存雪崩

什么是緩存雪崩

指緩存中大量數(shù)據(jù)的失效時(shí)間集中在某一個(gè)時(shí)間段,導(dǎo)致在這個(gè)時(shí)間段內(nèi)緩存失效并額外請(qǐng)求數(shù)據(jù)庫(kù)查詢數(shù)據(jù)的請(qǐng)求大量增加,從而對(duì)數(shù)據(jù)庫(kù)造成極大的壓力和負(fù)荷。

常見的Redis緩存雪崩場(chǎng)景包括:

  1. 緩存服務(wù)器宕機(jī):當(dāng)緩存服務(wù)器宕機(jī)或重啟時(shí),大量的訪問請(qǐng)求將直接命中數(shù)據(jù)庫(kù),并在同一時(shí)間段內(nèi)導(dǎo)致大量的數(shù)據(jù)庫(kù)查詢請(qǐng)求,從而將數(shù)據(jù)庫(kù)壓力大幅提高。
  2. 緩存數(shù)據(jù)同時(shí)失效:在某個(gè)特定時(shí)間點(diǎn),緩存中大量數(shù)據(jù)的失效時(shí)間集中在一起,這些數(shù)據(jù)會(huì)在同一時(shí)間段失效,并且這些數(shù)據(jù)被高頻訪問,將導(dǎo)致大量的訪問請(qǐng)求去查詢數(shù)據(jù)庫(kù)。
  3. 緩存中數(shù)據(jù)過期時(shí)間設(shè)計(jì)不合理:當(dāng)緩存中的數(shù)據(jù)有效時(shí)間過短,且數(shù)據(jù)集中在同一時(shí)期失效時(shí),就容易導(dǎo)致大量的請(qǐng)求直接查詢數(shù)據(jù)庫(kù),加劇數(shù)據(jù)庫(kù)壓力。
  4. 波動(dòng)式的訪問過程:當(dāng)數(shù)據(jù)的訪問存在波動(dòng)式特征時(shí),例如輸出某些活動(dòng)物品或促銷商品時(shí),將會(huì)帶來(lái)高頻的查詢請(qǐng)求訪問,導(dǎo)致緩存大量失效并產(chǎn)生緩存雪崩。

如何解決

在遇到緩存雪崩時(shí),我們可以使用兩種方法:一種是將緩存過期時(shí)間分散開,即為不同的數(shù)據(jù)設(shè)置不同的過期時(shí)間;另一種是使用Redis的多級(jí)緩存架構(gòu),通過增加一層代理層來(lái)解決。具體步驟如下:

  1. 添加相關(guān)依賴
<dependency>
    <groupId>org.springframework.boot<span class="hljs-name"groupId>
    <artifactId>spring-boot-starter-data-redis<span class="hljs-name"artifactId>
<span class="hljs-name"dependency>
<dependency>
    <groupId>net.sf.ehcache<span class="hljs-name"groupId>
    <artifactId>ehcache<span class="hljs-name"artifactId>
    <version>2.10.6<span class="hljs-name"version>
<span class="hljs-name"dependency>
  1. 在application.properties中配置Ehcache緩存
spring.cache.type=ehcache
  1. 創(chuàng)建一個(gè)CacheConfig類,用于配置Ehcache:
@Configuration
@EnableCaching
public class CacheConfig {
    @Bean
    public EhCacheCacheManager ehCacheCacheManager(CacheManager cm){
        return new EhCacheCacheManager(cm);
    }
    @Bean
    public CacheManager ehCacheManager(){
        EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean();
        cmfb.setConfigLocation(new ClassPathResource("ehcache.xml"));
        cmfb.setShared(true);
        return cmfb.getObject();
    }
}
  1. 在ehcache.xml中添加緩存配置
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
    updateCheck="true"
    monitoring="autodetect"
    dynamicConfig="true">

    <cache name="userCache" maxEntriesLocalHeap="10000" timeToLiveSeconds="60" timeToIdleSeconds="30"/>

<span class="hljs-name"ehcache>
  1. 在Controller中查詢數(shù)據(jù)時(shí),先從Ehcache緩存中獲取,如果緩存中無(wú)數(shù)據(jù)則再?gòu)腞edis緩存中獲取數(shù)據(jù)
@Autowired
private RedisTemplate

以上就是使用SpringBoot時(shí)如何解決Redis的緩存穿透、緩存擊穿、緩存雪崩的常用方法。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • spring
    +關(guān)注

    關(guān)注

    0

    文章

    340

    瀏覽量

    14343
  • Boot
    +關(guān)注

    關(guān)注

    0

    文章

    149

    瀏覽量

    35839
  • Redis
    +關(guān)注

    關(guān)注

    0

    文章

    375

    瀏覽量

    10877
  • SpringBoot
    +關(guān)注

    關(guān)注

    0

    文章

    173

    瀏覽量

    179
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    使用Redis緩存model層

    〈譯〉使用REDIS處理RAILS MODEL緩存
    發(fā)表于 04-18 17:07

    redis緩存注解怎么使用

    spring boot —— redis 緩存注解使用教程
    發(fā)表于 09-11 14:43

    Spring bootRedis的使用

    【本人禿頂程序員】springboot專輯:Spring bootRedis的使用
    發(fā)表于 03-27 11:42

    Redis在高速緩存系統(tǒng)的序列化算法研究

    Redis是一個(gè)key?value存儲(chǔ)系統(tǒng),通過對(duì)Redis高速緩存系統(tǒng)的序列化算法優(yōu)化,可提高緩存讀取的效率和存儲(chǔ)容量。引入現(xiàn)代統(tǒng)計(jì)學(xué)B
    發(fā)表于 11-23 16:07 ?0次下載

    Java 使用Redis緩存工具的詳細(xì)解說(shuō)

    本文是關(guān)于Java 使用Redis緩存工具的詳細(xì)解說(shuō)。詳細(xì)步驟請(qǐng)看下文
    的頭像 發(fā)表于 02-09 14:10 ?7887次閱讀
    Java 使用<b class='flag-5'>Redis</b><b class='flag-5'>緩存</b>工具的詳細(xì)解說(shuō)

    Redis常見面試題及答案

    本文的面試題如下: Redis 持久化機(jī)制 緩存雪崩、緩存穿透、緩存預(yù)熱、緩存更新、
    的頭像 發(fā)表于 12-16 11:44 ?2205次閱讀
    <b class='flag-5'>Redis</b>常見面試題及答案

    緩存雪崩/穿透/擊穿的解決方案

    緩存是我們項(xiàng)目應(yīng)用肯定會(huì)使用,是我們數(shù)據(jù)庫(kù)的守護(hù)神,能夠保證數(shù)據(jù)庫(kù)的穩(wěn)定,能夠提高整個(gè)系統(tǒng)的性能。一般我們采用市面上的redis、memcahce方案;redis已經(jīng)非常強(qiáng)大了,每秒支持幾萬(wàn)的連接時(shí)不成問題。
    發(fā)表于 01-26 09:44 ?1311次閱讀
    <b class='flag-5'>緩存</b>雪崩/<b class='flag-5'>穿透</b>/擊穿的解決方案

    Redis緩存的異常原因及其處理辦法分析

    Redis 是當(dāng)前最流行的 NoSQL 數(shù)據(jù)庫(kù)。Redis 主要用來(lái)做緩存使用,在提高數(shù)據(jù)查詢效率、保護(hù)數(shù)據(jù)庫(kù)等方面起到了關(guān)鍵性的作用,很大程度上提高系統(tǒng)的性能。
    的頭像 發(fā)表于 02-06 15:02 ?744次閱讀

    SpringBoot+Redis實(shí)現(xiàn)點(diǎn)贊功能的緩存和定時(shí)持久化(附源碼)

    用戶對(duì)瀏覽內(nèi)容進(jìn)行【點(diǎn)贊/取贊】,并發(fā)送【點(diǎn)贊/取贊】請(qǐng)求到后端,這些信息先存入Redis緩存,再每隔兩小時(shí)將Redis的內(nèi)容直接寫入數(shù)
    的頭像 發(fā)表于 02-09 16:38 ?4573次閱讀

    基于SpringBoot+Redis的轉(zhuǎn)盤抽獎(jiǎng)

    基于SpringBoot+Redis技術(shù)實(shí)現(xiàn)轉(zhuǎn)盤抽獎(jiǎng)活動(dòng)項(xiàng)目,含前端、后臺(tái)及數(shù)據(jù)庫(kù)文件
    的頭像 發(fā)表于 02-28 14:24 ?1534次閱讀
    基于<b class='flag-5'>SpringBoot+Redis</b>的轉(zhuǎn)盤抽獎(jiǎng)

    緩存穿透了如何解決

    首先來(lái)了解幾個(gè)概念: 緩存穿透:大量請(qǐng)求根本不存在的key 緩存雪崩:redis中大量key集體過期 緩存擊穿:
    的頭像 發(fā)表于 05-23 09:54 ?693次閱讀
    <b class='flag-5'>緩存</b>被<b class='flag-5'>穿透</b>了如何解決

    如何用Springboot整合Redis

    本篇文件我們來(lái)介紹如何用Springboot整合Redis。 1、Docker 安裝 Redis 1.1 下載鏡像 docker pull redis: 6 . 2 . 6 1.2 創(chuàng)
    的頭像 發(fā)表于 10-08 14:56 ?588次閱讀
    如何用<b class='flag-5'>Springboot</b>整合<b class='flag-5'>Redis</b>

    SpringBoot AOP + Redis 延時(shí)雙刪功能實(shí)戰(zhàn)

    注意:要知道經(jīng)常修改的數(shù)據(jù)表不適合使用Redis,因?yàn)殡p刪策略執(zhí)行的結(jié)果是把Redis中保存的那條數(shù)據(jù)刪除了,以后的查詢就都會(huì)去查詢數(shù)據(jù)庫(kù)。所以Redis使用的是讀遠(yuǎn)遠(yuǎn)大于改的數(shù)據(jù)緩存
    的頭像 發(fā)表于 10-13 16:08 ?638次閱讀
    <b class='flag-5'>SpringBoot</b> AOP + <b class='flag-5'>Redis</b> 延時(shí)雙刪功能實(shí)戰(zhàn)

    Oracle與Redis Enterprise協(xié)同,作為企業(yè)緩存解決方案

    單獨(dú)使用Oracle作為企業(yè)緩存數(shù)據(jù)庫(kù)時(shí),會(huì)出現(xiàn)哪些問題呢?使用Redis Enterprise與Oracle共同用作企業(yè)級(jí)緩存或副本數(shù)據(jù)庫(kù),會(huì)出現(xiàn)哪些喜人的提升呢?Orcle配合使用Redi
    的頭像 發(fā)表于 11-22 10:00 ?479次閱讀
    Oracle與<b class='flag-5'>Redis</b> Enterprise協(xié)同,作為企業(yè)<b class='flag-5'>緩存</b>解決方案

    Redis緩存預(yù)熱+緩存雪崩+緩存擊穿+緩存穿透要點(diǎn)簡(jiǎn)析

    緩存預(yù)熱就是系統(tǒng)上線后,提前將相關(guān)的緩存數(shù)據(jù)直接加載到緩存系統(tǒng)。
    的頭像 發(fā)表于 12-25 09:41 ?907次閱讀
    <b class='flag-5'>Redis</b><b class='flag-5'>緩存</b>預(yù)熱+<b class='flag-5'>緩存</b>雪崩+<b class='flag-5'>緩存</b>擊穿+<b class='flag-5'>緩存</b><b class='flag-5'>穿透</b>要點(diǎn)簡(jiǎn)析