聊聊如何利用redis實現多級快取同步

linyb極客之路發表於2022-12-20

前言

前陣子參加業務部門的技術方案評審,故事的背景是這樣:業務部門上線一個專為公司高管使用的系統。這個系統技術架構形如下圖

按理來說這個系統因為受眾很小,可以說基本上沒併發,業務也沒很複雜,但就是這麼一個系統,連續2次出現資料庫當機,而導致系統無法正常執行。因為這幾次事故,業務部門負責人組織這次技術方案評審,主題如何避免再次出現類似這種故障?

當時有個比較資深的技術,他提出當資料庫出現當機時,可以切換到redis,redis裡面快取熱點資料,另外一個技術說他贊同這個方案,但他提出不需要用到redis,直接用本地快取即可。因為tomcat是叢集部署,就等於本地快取也具備了叢集能力。而如果切換成redis,redis也可能會掛現象。

然後那個說用redis的技術又說,用本地快取,如果資料變更,其他叢集的本地快取如何感知資料已經發生變化,他覺得還是用redis靠譜,首先redis容量肯定是比本地快取高,而且redis也可以部署叢集,可用性可以得到保障,利用redis集中儲存,當資料發生變更,其他叢集也可以感知到。

在他們爭論不休的情況下,有人提出不然就同時使用,當資料庫掛了,切換到redis,redis掛了,使用本地快取。這個方案得到不少人的同意,包括這兩個爭論不休的技術。但使用這種方案,就得考慮多級快取資料如何同步。

鋪墊了那麼多,才剛要說今天的主題,多級快取資料如何進行同步

多級快取資料同步

1、方案一:使用MQ或者canal進行同步

方案如下圖


如果是使用MQ來同步,實現方案大致如下,資料發生變更,業務系統傳送變更資料到MQ,其他系統從MQ消費。

如果是使用canal,實現方案大致如下,資料發生變更,canal會接到到變更的binlog,業務系統編寫canal tcp客戶端,和canal進行互動獲取變更資料

2、方案二:利用redis6提供的客戶端快取機制

方案如下圖


redis6客戶端快取實現機制原理,官方有詳細文件介紹,感興趣大家可以檢視如下連結
https://redis.io/docs/manual/client-side-caching/

這邊就講下如何使用

如何使用redis6客戶端快取

前置條件:redis服務端版本必須是>=6。lettuce版本>=6 目前java的redis客戶端找了一圈,貌似只有lettuce 6支援,其他客戶端估計後期會支援

1、專案中pom引入lettuce GAV
  <dependency>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
            <version>6.1.8.RELEASE</version>
        </dependency>
2、利用lettuce6提供的ClientSideCaching進行實現
    /**
     * 客戶端快取同步
     *
     */
    public String getClientCacheValue(Map<String,String> clientCache,String key){
        StatefulRedisConnection<String, String> connect = redisClient.connect();
      //  Map<String,String> clientCache = new ConcurrentHashMap<>();
        CacheFrontend<String,String> frontend = ClientSideCaching.enable(CacheAccessor.forMap(clientCache),
                connect, TrackingArgs.Builder.enabled().noloop());
        return frontend.get(key);

    }
3、測試
    @Override
    public void run(ApplicationArguments args) throws Exception {
        while(true){
            System.out.println(lettuceRedisTemplate.getClientCacheValue("zhangsan"));
            TimeUnit.SECONDS.sleep(1);
        }


    }

redis裡面的zhangsan資料未發生變更時,


控制檯輸出的資料為

我們將redis zhangsan的密碼改成9999,

看本地快取能否立馬捕捉到


控制檯發現密碼已經改成9999

總結

由示例我們可以看出redis6提供了一個很好的多級快取同步的實現方案。

我們再聊下那個技術評審的後續,後面業務部門並沒有採用當mysql當機,使用redis作為兜底,也沒采用本地快取,更沒采用兩者結合的方案。

不知道大家開會的時候,有沒有這樣的體會,有時候我們在聊一個東西,後面聊著聊著就發散出去,把方向搞丟了。業務部門他們需要資料庫當機的解決方案嗎,看著像是,其實他們更核心的需要,是業務系統不當機。

奧卡姆剃刀定律:如無必要,勿增實體。其實不管加redis或者本地快取,額外都增加系統維護成本。因為系統本身不復雜,加了快取,就要額外考慮快取資料一致性等

後面業務部門的處理方式,是將自己搭建的mysql,切換成雲廠商的mysql。這樣的好處是,雲廠商的mysql會更穩定,其次當出現問題,可以找雲廠商進行解決,畢竟雲廠商的運維能力是比較強的,花錢買心安

這次事故會讓業務部門那麼重視,主要是使用方是高管,如果是一般使用者,掛就掛吧,大不了重啟,使用物件不一樣,應急處理方式就不一樣

demo連結

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-localcache-redis-sync

相關文章