Redis實現多級緩存
本文實例為大傢分享瞭Redis實現多級緩存的具體代碼,供大傢參考,具體內容如下
一、多級緩存
1. 傳統緩存方案
請求到達tomcat後,先去redis中獲取緩存,不命中則去mysql中獲取
2. 多級緩存方案
- tomcat的請求並發數,是遠小於redis的,因此tomcat會成為瓶頸
- 利用請求處理每個環節,分別添加緩存,減輕tomcat壓力,提升服務性能
二、JVM本地緩存
緩存是存儲在內存中,數據讀取速度較快,能大量減少對數據庫的訪問,減少數據庫壓力
分佈式緩存,如redis
– 優點: 存儲容量大,可靠性好,可以在集群中共享
– 缺點: 訪問緩存有網絡開銷
– 場景: 緩存數據量大,可靠性高,需要在集群中共享的數據
進程本地緩存, 如HashMap, GuavaCache
– 優點:讀取本地內存,沒有網絡開銷,速度更快
– 缺點:存儲容量有限,可靠性低(如重啟後丟失),無法在集群中共享
– 場景:性能要求高,緩存數據量少
1. 實用案例
Caffeine是一個基於java8開發的,提供瞭近乎最佳命中率的高性能的本地緩存庫
目前spring內部的緩存用的就是這個
<dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> <version>3.0.5</version> </dependency>
package com.erick.cache; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import java.time.Duration; public final class CacheUtil { private static int expireSeconds = 2; public static Cache<String, String> cacheWithExpireSeconds; private static int maxPairs = 1; public static Cache<String, String> cacheWithMaxPairs; static { /*過期策略,寫完60s後過期*/ cacheWithExpireSeconds = Caffeine.newBuilder() .expireAfterWrite(Duration.ofSeconds(expireSeconds)) .build(); /*過期策略,達到最大值後刪除 * 1. 並不會立即刪除,等一會兒才會刪除 * 2. 會將之前存儲的數據刪除掉*/ cacheWithMaxPairs = Caffeine.newBuilder() .maximumSize(maxPairs) .build(); } /*從緩存中獲取數據 * 1. 如果緩存中有,則直接從緩存中返回 * 2. 如果緩存中沒有,則去數據查詢並返回結果*/ public static String getKeyWithExpire(String key) { return cacheWithExpireSeconds.get(key, value -> { return getResultFromDB(); }); } public static String getKeyWithMaxPair(String key) { return cacheWithMaxPairs.get(key, value -> { return getResultFromDB(); }); } private static String getResultFromDB() { System.out.println("數據庫查詢"); return "db result"; } }
package com.erick.cache; import java.util.concurrent.TimeUnit; public class Test { @org.junit.Test public void test01() throws InterruptedException { CacheUtil.cacheWithExpireSeconds.put("name", "erick"); System.out.println(CacheUtil.getKeyWithExpire("name")); TimeUnit.SECONDS.sleep(3); System.out.println(CacheUtil.getKeyWithExpire("name")); } @org.junit.Test public void test02() throws InterruptedException { CacheUtil.cacheWithMaxPairs.put("name", "erick"); CacheUtil.cacheWithMaxPairs.put("age", "12"); System.out.println(CacheUtil.getKeyWithMaxPair("name")); System.out.println(CacheUtil.getKeyWithMaxPair("age")); TimeUnit.SECONDS.sleep(2); System.out.println(CacheUtil.getKeyWithMaxPair("name")); // 查詢不到瞭 System.out.println(CacheUtil.getKeyWithMaxPair("age")); } }
三、緩存一致性
1. 常見方案
1.1 設置有效期
- 給緩存設置有效期,到期後自動刪除。再次查詢時可以更新
- 優勢:簡單,方便
- 缺點:時效性差,緩存過期之前可能不一致
- 場景:更新頻率低,時效性要求比較低的業務
1.2 同步雙寫
- 在修改數據庫的同時,直接修改緩存
- 優勢:有代碼侵入,緩存與數據庫強一致性
- 缺點:代碼進入,耦合性高
- 場景:對一致性,失效性要求較高的緩存數據
1.3 異步通知
- 修改數據庫時發送事件通知,相關服務監聽到後修改緩存數據
- 優勢:低耦合,可以同時通知多個緩存服務
- 缺點:時效性一把,可能存在緩存不一致問題
- 場景:時效性一般,有多個服務需要同步
2. 基於Canal的異步通知
- 是阿裡旗下的一款開源項目,基於java開發
- 基於數據庫增量日志解析,提供增量數據訂閱和消費
- 基於mysql的主從備份的思想
2.1 mysql主從復制
2.2 canal 工作原理
canal 模擬 MySQL slave 的交互協議,偽裝自己為 MySQL slave ,向 MySQL master 發送dump 協議
MySQL master 收到 dump 請求, 開始推送 binary log 給 slave (即 canal )
canal 解析 binary log 對象(原始為 byte 流)
以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 淺談MySQL與redis緩存的同步方案
- Java TimedCache 帶時間緩存工具類詳解使用
- SpringBoot+SpringCache實現兩級緩存(Redis+Caffeine)
- 詳解高性能緩存Caffeine原理及實戰
- IDEA版使用Java操作Redis數據庫的方法