最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

搭建Caffeine+Redis多級緩存機制

 更新時間:2025年07月28日 09:27:09   作者:moxiaoran5753  
本文主要介紹了搭建Caffeine+Redis多級緩存機制,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

本地緩存的簡單實現(xiàn)方案有HashMap,CucurrentHashMap,成熟的本地緩存方案有Guava 與 Caffeine ,企業(yè)級應(yīng)用推薦下面說下兩者的區(qū)別

0. 核心異同對比

特性Guava CacheCaffeine
誕生背景Google Guava 庫的一部分(2011年)基于 Guava Cache 重構(gòu)的現(xiàn)代緩存庫(2015+)
性能中等(鎖競爭較多)極高(優(yōu)化并發(fā)設(shè)計,吞吐量提升5~10倍)
內(nèi)存管理基于 LRU 算法結(jié)合 W-TinyLFU 算法(高命中率)
過期策略支持 expireAfterWrite/access支持 expireAfterWrite/access + refresh
緩存回收同步阻塞異步非阻塞(后臺線程)
監(jiān)控統(tǒng)計基礎(chǔ)統(tǒng)計(命中率等)詳細(xì)統(tǒng)計(命中率、加載時間等)
依賴需引入整個 Guava 庫輕量(僅依賴 Caffeine)
社區(qū)維護(hù)維護(hù)模式(新功能少)活躍更新(Java 17+ 兼容)

從上面的比較可知, Caffeine 各方面是優(yōu)于Guava的,因此在搭建多級緩存機制時,建議使用Caffeine+Redis的組合方案。

業(yè)務(wù)執(zhí)行流程

  • 請求優(yōu)先讀取 Caffeine 本地緩存(超快,減少網(wǎng)絡(luò)IO)。
  • 本地緩存未命中 → 讀取 Redis 分布式緩存。
  • Redis 未命中 → 查詢數(shù)據(jù)庫,并回填到兩級緩存。

下面介紹下實現(xiàn)方式

注意:下面的實現(xiàn)方式是基于Springboot 2.4+,版本不同,配置上會略有差異

1.maven中引入下面的依賴

<!-- Caffeine 本地緩存 -->
<dependency>
	<groupId>com.github.ben-manes.caffeine</groupId>
	<artifactId>caffeine</artifactId>
</dependency>

<!-- 緩存抽象層 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-cache</artifactId>
</dependency>

<!-- redis 緩存操作 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
	   <exclusions>
		 <exclusion>
			 <groupId>io.lettuce</groupId>
			 <artifactId>lettuce-core</artifactId>
		 </exclusion>
		</exclusions>
</dependency>

<dependency>
 <groupId>redis.clients</groupId>
 <artifactId>jedis</artifactId>
</dependency>

2.application中進(jìn)行配置

spring: 
 cache:
    caffeine:
      spec: maximumSize=1000,expireAfterWrite=10m  # 本地緩存
    redis:
      time-to-live: 1h  # Redis緩存過期時間
  # redis 配置
  redis:
    # 地址
    host: 127.0.0.1
    # 端口,默認(rèn)為6379
    port: 6379
    # 數(shù)據(jù)庫索引
    database: 0
    # 密碼
    password: abc123
    # 連接超時時間
    timeout: 6000ms  # 連接超時時長(毫秒)
    jedis:
      pool:
        max-active: 1000  # 連接池最大連接數(shù)(使用負(fù)值表示沒有限制)
        max-wait: -1ms      # 連接池最大阻塞等待時間(使用負(fù)值表示沒有限制)
        max-idle: 10      # 連接池中的最大空閑連接
        min-idle: 5       # 連接池中的最小空閑連接

3.自定義多級緩存管理器

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.cache.support.CompositeCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.github.benmanes.caffeine.cache.Caffeine;

import java.util.concurrent.TimeUnit;


@Configuration
@EnableCaching
@EnableConfigurationProperties(CacheProperties.class)
public class MyCacheConfig {

    @Bean
    public RedisCacheConfiguration cacheConfiguration(CacheProperties cacheProperties) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
        config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));

        CacheProperties.Redis redisProperties = cacheProperties.getRedis();
        if (redisProperties.getTimeToLive() != null) {
            config = config.entryTtl(redisProperties.getTimeToLive());
        }
        if (redisProperties.getKeyPrefix() != null) {
            config = config.prefixKeysWith(redisProperties.getKeyPrefix());
        }
        if (!redisProperties.isCacheNullValues()) {
            config = config.disableCachingNullValues();
        }
        if (!redisProperties.isUseKeyPrefix()) {
            config = config.disableKeyPrefix();
        }
        return config;
    }

    @Bean
    public Caffeine<Object, Object> caffeineConfig() {
        return Caffeine.newBuilder()
                .maximumSize(1000)
                .expireAfterWrite(10, TimeUnit.MINUTES);
    }

    @Bean
    @Primary  // 添加 @Primary 注解指定 CaffeineCacheManager 作為默認(rèn)的緩存管理器
    public CacheManager caffeineCacheManager(Caffeine<Object, Object> caffeine) {
        CaffeineCacheManager manager = new CaffeineCacheManager();
        manager.setCaffeine(caffeine);
        return manager;
    }

    @Bean
    public RedisCacheManager redisCacheManager(
            RedisConnectionFactory redisConnectionFactory,
            RedisCacheConfiguration cacheConfiguration) {

        return RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(cacheConfiguration)
                .build();
    }

    @Bean
    public CacheManager compositeCacheManager(
            @Qualifier("caffeineCacheManager") CacheManager caffeineCacheManager,
            @Qualifier("redisCacheManager") CacheManager redisCacheManager) {

        return new CompositeCacheManager(
                caffeineCacheManager,
                redisCacheManager
        );
    }
}
        

4.業(yè)務(wù)邏輯層調(diào)用

使用示例:

@Service
public class ProductService {

    @Autowired
    private ProductRepository repository;

    // 優(yōu)先讀本地緩存,其次Redis,最后數(shù)據(jù)庫
    @Cacheable(cacheNames = "product", key = "#id")
    public Product getProductById(Long id) {
        return repository.findById(id).orElseThrow();
    }

    // 更新數(shù)據(jù)時清除兩級緩存
    @CacheEvict(cacheNames = "product", key = "#product.id")
    public Product updateProduct(Product product) {
        return repository.save(product);
    }
}

手動控制多級緩存

@Service
public class CacheService {

    @Autowired
    private CacheManager cacheManager;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public Product getProductWithManualControl(Long id) {
        // 1. 先查本地緩存
        Cache caffeineCache = cacheManager.getCache("product");
        Product product = caffeineCache.get(id, Product.class);
        if (product != null) {
            return product;
        }

        // 2. 查Redis緩存
        product = (Product) redisTemplate.opsForValue().get("product:" + id);
        if (product != null) {
            // 回填本地緩存
            caffeineCache.put(id, product);
            return product;
        }

        // 3. 查數(shù)據(jù)庫
        product = repository.findById(id).orElseThrow();
        
        // 回填兩級緩存
        redisTemplate.opsForValue().set("product:" + id, product, Duration.ofHours(1));
        caffeineCache.put(id, product);
        
        return product;
    }
}

緩存一致性

  • 使用 @CacheEvict 或 Redis Pub/Sub 同步失效兩級緩存。
  • 示例:通過 Redis 消息通知其他節(jié)點清理本地緩存。

防止緩存擊穿

  • Caffeine 配置 refreshAfterWrite
Caffeine.newBuilder()
    .refreshAfterWrite(5, TimeUnit.MINUTES)
    .build(key -> loadFromRedisOrDb(key));

監(jiān)控統(tǒng)計:

  • Caffeine 統(tǒng)計:cache.getNativeCache().stats()
  • Redis 統(tǒng)計:INFO commandstats

驗證多級緩存

  • 本地緩存生效:連續(xù)調(diào)用同一接口,觀察第二次響應(yīng)時間驟降。
  • Redis 緩存生效:重啟應(yīng)用后,首次請求仍快速返回(數(shù)據(jù)來自Redis)。

到此這篇關(guān)于搭建Caffeine+Redis多級緩存機制的文章就介紹到這了,更多相關(guān)Caffeine Redis緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于Redis實現(xiàn)搶紅包和發(fā)紅包功能

    基于Redis實現(xiàn)搶紅包和發(fā)紅包功能

    搶紅包是我們生活常用的社交功能, 這個功能最主要的特點就是用戶的并發(fā)請求高, 在系統(tǒng)設(shè)計上, 可以使用非常多的辦法來扛住用戶的高并發(fā)請求, 在本文中簡要介紹使用Redis緩存中間件來實現(xiàn)搶紅包算法,需要的朋友可以參考下
    2024-04-04
  • redis實現(xiàn)加鎖的幾種方法示例詳解

    redis實現(xiàn)加鎖的幾種方法示例詳解

    這篇文章主要給大家介紹了關(guān)于redis實現(xiàn)加鎖的幾種方法,加鎖命令分別是INCR、SETNX和SET,文中給出了詳細(xì)的示例代碼,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-09-09
  • 關(guān)于Redis未授權(quán)訪問的問題

    關(guān)于Redis未授權(quán)訪問的問題

    這篇文章主要介紹了Redis未授權(quán)訪問的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-07-07
  • redis中使用bloomfilter的白名單功能解決緩存穿透問題

    redis中使用bloomfilter的白名單功能解決緩存穿透問題

    本文主要介紹了redis中使用bloomfilter的白名單功能解決緩存穿透問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • RedisTemplate集成+封裝RedisUtil過程

    RedisTemplate集成+封裝RedisUtil過程

    本文介紹了如何搭建一個多模塊的Redis項目,包括項目搭建、配置和測試,通過使用父項目管理多個子模塊,可以實現(xiàn)單點構(gòu)建、統(tǒng)一版本管理和清晰的項目結(jié)構(gòu),文章還提供了在Spring Boot項目中集成RedisTemplate的示例,并解決了編碼問題
    2024-12-12
  • Redis集群指定主從關(guān)系及動態(tài)增刪節(jié)點方式

    Redis集群指定主從關(guān)系及動態(tài)增刪節(jié)點方式

    這篇文章主要介紹了Redis集群指定主從關(guān)系及動態(tài)增刪節(jié)點方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • redis實現(xiàn)存儲帖子的點贊狀態(tài)和數(shù)量的示例代碼

    redis實現(xiàn)存儲帖子的點贊狀態(tài)和數(shù)量的示例代碼

    使用Redis來實現(xiàn)點贊功能是一種高效的選擇,因為Redis是一個內(nèi)存數(shù)據(jù)庫,適用于處理高并發(fā)的數(shù)據(jù)操作,這篇文章主要介紹了redis實現(xiàn)存儲帖子的點贊狀態(tài)和數(shù)量的示例代碼,需要的朋友可以參考下
    2023-09-09
  • Redis中SDS簡單動態(tài)字符串詳解

    Redis中SDS簡單動態(tài)字符串詳解

    Redis中的SDS(Simple?Dynamic?String)是一種自動擴(kuò)容的字符串實現(xiàn)方式,它可以提供高效的字符串操作,并且支持二進(jìn)制安全。SDS的設(shè)計使得它可以在O(1)時間內(nèi)實現(xiàn)字符串長度的獲取和修改,同時也可以在O(N)的時間內(nèi)進(jìn)行字符串的拼接和截取。
    2023-04-04
  • redis在php中常用的語法【推薦】

    redis在php中常用的語法【推薦】

    string是redis最基本的類型,而且string類型是二進(jìn)制安全的。這篇文章主要介紹了redis在php中常用的語法,需要的朋友可以參考下
    2018-08-08
  • 淺析Redis中紅鎖RedLock的實現(xiàn)原理

    淺析Redis中紅鎖RedLock的實現(xiàn)原理

    RedLock?是一種分布式鎖的實現(xiàn)算法,由?Redis?的作者?Salvatore?Sanfilippo(也稱為?Antirez)提出,本文主要為大家詳細(xì)介紹了紅鎖RedLock的實現(xiàn)原理,感興趣的可以了解下
    2024-02-02

最新評論

井冈山市| 子洲县| 德惠市| 呼图壁县| 于田县| 时尚| 正蓝旗| 垣曲县| 高台县| 扶绥县| 怀化市| 淮安市| 云浮市| 华安县| 都安| 宁远县| 巨鹿县| 健康| 浠水县| 留坝县| 襄城县| 丰宁| 西盟| 阜新市| 汝南县| 阿瓦提县| 禹州市| 延安市| 前郭尔| 岳普湖县| 来安县| 宜丰县| 新昌县| 连山| 西乡县| 永登县| 鹤庆县| 通渭县| 徐水县| 百色市| 广安市|