偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

多級(jí)緩存架構(gòu)設(shè)計(jì)與緩存一致性保障

存儲(chǔ) 數(shù)據(jù)管理
多級(jí)緩存架構(gòu)是平衡性能與成本的最優(yōu)解,而緩存一致性則是系統(tǒng)可靠性的基石。在實(shí)際應(yīng)用中,需結(jié)合業(yè)務(wù)場(chǎng)景(如讀寫比例、一致性要求)靈活調(diào)整方案,畢竟沒有什么技術(shù)方案是完美的,只有最適合當(dāng)前業(yè)務(wù)場(chǎng)景的取舍。?

前言

在高并發(fā)系統(tǒng)設(shè)計(jì)中,緩存是提升性能的核心手段,但單一緩存方案往往難以應(yīng)對(duì)復(fù)雜的業(yè)務(wù)場(chǎng)景。多級(jí)緩存架構(gòu)通過分層存儲(chǔ)策略,結(jié)合不同緩存技術(shù)的優(yōu)勢(shì),能有效平衡性能與可靠性;而緩存一致性則是保障系統(tǒng)數(shù)據(jù)準(zhǔn)確性的關(guān)鍵。

多級(jí)緩存架構(gòu)

多級(jí)緩存的核心思想是按照數(shù)據(jù)訪問頻率和系統(tǒng)對(duì)延遲的敏感度,將數(shù)據(jù)分層存儲(chǔ)在不同的緩存介質(zhì)中,通過離用戶越近的緩存響應(yīng)速度越快的原則,最大化降低系統(tǒng)整體延遲。

為什么需要多級(jí)緩存

  • 本地緩存(如Caffeine、HashMap):優(yōu)勢(shì)是內(nèi)存級(jí)訪問,但受限于單機(jī)內(nèi)存容量,且在分布式集群中存在數(shù)據(jù)孤島問題,應(yīng)用重啟后緩存會(huì)全部失效。
  • 分布式緩存(如Redis、Memcached):優(yōu)勢(shì)是支持集群部署、容量可擴(kuò)展,能在多實(shí)例間共享數(shù)據(jù),但依賴網(wǎng)絡(luò)IO,高頻訪問下延遲成本被放大。

分層設(shè)計(jì)

  • L1:本地緩存層

存儲(chǔ)內(nèi)容:訪問頻率最高的熱點(diǎn)中的熱點(diǎn)數(shù)據(jù)(通常占總請(qǐng)求的 20%-30%),如首頁(yè) Banner、秒殺商品信息等。

技術(shù)選型:推薦使用Caffeine(Java)或LRU Cache(Go),這類工具支持高效的內(nèi)存管理和淘汰策略(如 LRU、LFU)。

核心特點(diǎn):容量?。ㄍǔO拗圃?nbsp;1-10MB)、延遲極低、線程安全,僅在當(dāng)前應(yīng)用實(shí)例中有效。

  • L2:分布式緩存層

存儲(chǔ)內(nèi)容:覆蓋范圍更廣的熱點(diǎn)數(shù)據(jù)(通常占總請(qǐng)求的 60%-70%),如用戶會(huì)話、商品詳情等。

技術(shù)選型:Redis集群(主從 + 哨兵或Redis Cluster),支持?jǐn)?shù)據(jù)持久化和高可用部署。

核心特點(diǎn):容量大(可擴(kuò)展至TB級(jí))、支持集群共享、延遲高于本地緩存但遠(yuǎn)低于數(shù)據(jù)庫(kù)。

  • 兜底層:數(shù)據(jù)庫(kù)

作為最終數(shù)據(jù)源,承接緩存未命中的請(qǐng)求(通常占總請(qǐng)求的5%-10%),并通過主從分離、讀寫分離進(jìn)一步提升性能。

工作流程

  • 優(yōu)先查詢L1本地緩存,命中則直接返回;
  • 若L1未命中,查詢L2分布式緩存,命中則返回,同時(shí)將數(shù)據(jù)同步到L1(按需);
  • 若L2未命中,查詢數(shù)據(jù)庫(kù),返回結(jié)果的同時(shí),將數(shù)據(jù)寫入L2和L1(按需)。

代碼示例

@Component
public class MultiLevelCacheClient {
    // L1本地緩存(Caffeine)
    private final LoadingCache<String, Object> localCache;
    // L2分布式緩存(Redis)
    @Autowired
    private StringRedisTemplate redisTemplate;
    // 數(shù)據(jù)庫(kù)訪問層
    @Autowired
    private DataDao dataDao;

    // 初始化本地緩存
    public MultiLevelCacheClient() {
        this.localCache = Caffeine.newBuilder()
                .maximumSize(10_000)  // 限制最大條目數(shù),防止內(nèi)存溢出
                .expireAfterWrite(5, TimeUnit.MINUTES)  // 寫入后5分鐘過期
                .build(this::loadFromRedis);  // L1未命中時(shí)從L2加載
    }

    // 對(duì)外查詢接口
    public Object query(String key) {
        try {
            return localCache.get(key);  // 優(yōu)先查L(zhǎng)1
        } catch (Exception e) {
            // 緩存查詢異常時(shí)直接查數(shù)據(jù)庫(kù)兜底
            log.error("多級(jí)緩存查詢失敗,key:{}", key, e);
            return dataDao.query(key);
        }
    }

    // 從L2加載數(shù)據(jù)(供Caffeine回調(diào))
    private Object loadFromRedis(String key) {
        // 查L(zhǎng)2
        String valueStr = redisTemplate.opsForValue().get(key);
        if (valueStr != null) {
            return JSON.parseObject(valueStr, Object.class);
        }
        // L2未命中則查數(shù)據(jù)庫(kù),并回寫L2
        Object value = dataDao.query(key);
        if (value != null) {
            redisTemplate.opsForValue().set(key, JSON.toJSONString(value), 30, TimeUnit.MINUTES);
        }
        return value;
    }
}

緩存一致性

當(dāng)數(shù)據(jù)庫(kù)中的數(shù)據(jù)發(fā)生變更時(shí),若緩存中的數(shù)據(jù)未及時(shí)更新,會(huì)導(dǎo)致緩存臟讀問題。在多級(jí)緩存架構(gòu)中,一致性問題更為復(fù)雜,需同時(shí)保證L1、L2與數(shù)據(jù)庫(kù)的數(shù)據(jù)同步。

產(chǎn)生場(chǎng)景

  • 更新覆蓋:A線程更新數(shù)據(jù)庫(kù)后,B線程在緩存更新前讀取到舊數(shù)據(jù)。
  • 緩存殘留:數(shù)據(jù)庫(kù)數(shù)據(jù)已刪除,但緩存中仍保留該數(shù)據(jù)。
  • 多級(jí)不一致:L1緩存已更新,但L2緩存未更新,導(dǎo)致集群中其他實(shí)例讀取到舊數(shù)據(jù)。

策略設(shè)計(jì)

相比更新數(shù)據(jù)庫(kù)后更新緩存,刪除緩存策略更簡(jiǎn)單且能減少并發(fā)沖突。其核心邏輯是:當(dāng)數(shù)據(jù)變更時(shí),先刪除緩存中的舊數(shù)據(jù),后續(xù)請(qǐng)求會(huì)從數(shù)據(jù)庫(kù)加載新數(shù)據(jù)并回填緩存。

L1本地緩存處理:

  • 數(shù)據(jù)變更時(shí)立即刪除當(dāng)前實(shí)例的L1緩存,避免同一實(shí)例后續(xù)讀取到舊數(shù)據(jù)。
  • 若應(yīng)用部署在多實(shí)例集群中,可通過事件通知(如 Redis Pub/Sub)觸發(fā)其他實(shí)例刪除L1 緩存,避免跨實(shí)例不一致。

L2分布式緩存處理:

  • 采用異步刪除策略,避免阻塞數(shù)據(jù)庫(kù)更新的主流程(如通過線程池或消息隊(duì)列異步執(zhí)行刪除操作)。
  • 為緩存設(shè)置合理的過期時(shí)間(如5-30分鐘),作為刪除操作失敗時(shí)的兜底機(jī)制。

代碼示例

事件類的定義
/**
 * 數(shù)據(jù)更新事件:當(dāng)數(shù)據(jù)庫(kù)數(shù)據(jù)發(fā)生新增/修改/刪除時(shí)發(fā)布
 */
public class DataUpdateEvent extends ApplicationEvent {
    // 數(shù)據(jù)唯一標(biāo)識(shí)(如商品ID、用戶ID)
    private final String key;
    // 操作類型(新增/更新/刪除)
    private final OperationType operationType;

    public DataUpdateEvent(Object source, String key, OperationType operationType) {
        super(source);
        this.key = key;
        this.operationType = operationType;
    }

    // getter方法
    public String getKey() { return key; }
    public OperationType getOperationType() { return operationType; }

    // 操作類型枚舉
    public enum OperationType {
        CREATE, UPDATE, DELETE
    }
}
事件發(fā)布的觸發(fā)時(shí)機(jī)

事件應(yīng)在數(shù)據(jù)庫(kù)操作成功后發(fā)布,確保只有當(dāng)數(shù)據(jù)確實(shí)更新后,才會(huì)觸發(fā)緩存刷新。以商品信息更新為例,發(fā)布邏輯如下:

@Service
public class ProductService {
    @Autowired
    private ProductDao productDao;
    // Spring事件發(fā)布器
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    /**
     * 更新商品信息(包含事件發(fā)布邏輯)
     */
    @Transactional
    public void updateProduct(Product product) {
        // 1. 執(zhí)行數(shù)據(jù)庫(kù)更新
        productDao.update(product);
        
        // 2. 數(shù)據(jù)庫(kù)操作成功后,發(fā)布數(shù)據(jù)更新事件
        String key = "product:" + product.getId(); // 緩存鍵(與查詢時(shí)保持一致)
        eventPublisher.publishEvent(
            new DataUpdateEvent(this, key, DataUpdateEvent.OperationType.UPDATE)
        );
    }

    /**
     * 刪除商品(包含事件發(fā)布邏輯)
     */
    @Transactional
    public void deleteProduct(Long productId) {
        // 1. 執(zhí)行數(shù)據(jù)庫(kù)刪除
        productDao.delete(productId);
        
        // 2. 發(fā)布刪除事件
        String key = "product:" + productId;
        eventPublisher.publishEvent(
            new DataUpdateEvent(this, key, DataUpdateEvent.OperationType.DELETE)
        );
    }
}
事件處理
@Component
public class CacheConsistencyManager {
    @Autowired
    private LoadingCache<String, Object> localCache;
    @Autowired
    private StringRedisTemplate redisTemplate;
    // 線程池用于異步操作
    private final ExecutorService cacheExecutor = Executors.newFixedThreadPool(5);

    // 處理數(shù)據(jù)更新事件
    @EventListener
    public void onDataUpdated(DataUpdateEvent event) {
        String key = event.getKey();
        // 1. 立即刪除本地緩存(同步操作,確保當(dāng)前實(shí)例無(wú)舊數(shù)據(jù))
        localCache.invalidate(key);

        // 2. 異步刪除分布式緩存(避免阻塞主流程)
        cacheExecutor.submit(() -> {
            try {
                redisTemplate.delete(key);
                // 發(fā)送緩存刪除事件,通知其他實(shí)例清理L1(集群場(chǎng)景)
                redisTemplate.convertAndSend("cache:invalid:channel", key);
            } catch (Exception e) {
                log.error("異步刪除Redis緩存失敗,key:{}", key, e);
                // 失敗不影響主流程,依賴過期時(shí)間兜底
            }
        });
    }

    // 監(jiān)聽其他實(shí)例的緩存刪除通知
    @Bean
    public RedisMessageListenerContainer redisListener() {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(redisTemplate.getConnectionFactory());
        container.addMessageListener((message, pattern) -> {
            String key = new String(message.getBody());
            localCache.invalidate(key);  // 清理當(dāng)前實(shí)例的L1緩存
        }, new PatternTopic("cache:invalid:channel"));
        return container;
    }
}
異步事件發(fā)布(可選)
@Configuration
@EnableAsync // 開啟異步支持
public class AsyncConfig {
    @Bean
    public Executor eventExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(3);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("event-publisher-");
        executor.initialize();
        return executor;
    }
}

// 在發(fā)布者中指定異步執(zhí)行
@Service
public class ProductService {
    @Async("eventExecutor") // 使用自定義線程池異步發(fā)布
    public void publishUpdateEvent(String key) {
        eventPublisher.publishEvent(
            new DataUpdateEvent(this, key, DataUpdateEvent.OperationType.UPDATE)
        );
    }
}

總結(jié)

多級(jí)緩存架構(gòu)是平衡性能與成本的最優(yōu)解,而緩存一致性則是系統(tǒng)可靠性的基石。在實(shí)際應(yīng)用中,需結(jié)合業(yè)務(wù)場(chǎng)景(如讀寫比例、一致性要求)靈活調(diào)整方案,畢竟沒有什么技術(shù)方案是完美的,只有最適合當(dāng)前業(yè)務(wù)場(chǎng)景的取舍。

責(zé)任編輯:武曉燕 來(lái)源: 一安未來(lái)
相關(guān)推薦

2022-12-14 08:23:30

2020-06-01 22:09:48

緩存緩存同步緩存誤用

2017-05-19 15:00:05

session架構(gòu)web-server

2020-05-12 10:43:22

Redis緩存數(shù)據(jù)庫(kù)

2021-06-11 09:21:58

緩存數(shù)據(jù)庫(kù)Redis

2024-04-11 13:45:14

Redis數(shù)據(jù)庫(kù)緩存

2024-05-28 00:50:00

RedisMySQL緩存

2023-08-15 09:31:01

分布式緩存

2024-12-26 15:01:29

2019-03-27 13:56:39

緩存雪崩穿透

2023-08-14 08:10:33

CPU緩存RFO

2023-12-01 13:51:21

數(shù)據(jù)一致性數(shù)據(jù)庫(kù)

2017-07-25 14:38:56

數(shù)據(jù)庫(kù)一致性非鎖定讀一致性鎖定讀

2022-09-06 15:30:20

緩存一致性

2018-09-11 10:46:10

緩存數(shù)據(jù)庫(kù)一致性

2021-08-10 11:05:09

服務(wù)器緩存 架構(gòu)

2022-07-25 09:48:22

緩存數(shù)據(jù)服務(wù)

2020-09-03 09:45:38

緩存數(shù)據(jù)庫(kù)分布式

2023-09-24 14:35:43

Redis數(shù)據(jù)庫(kù)

2023-05-09 10:59:33

緩存技術(shù)派MySQL
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)