6.1.多級緩存架構

目錄

一、多級緩存基礎與核心概念

  1. 緩存的定義與價值 ? 緩存的應用場景(高并發、低延遲、減輕數據庫壓力) ? 多級緩存 vs 單級緩存的優劣對比

  2. 多級緩存核心組件 ? 本地緩存(Caffeine、Guava Cache) ? 分布式緩存(Redis、Memcached)

  3. 緩存一致性挑戰 ? 數據一致性模型(強一致、最終一致) ? 常見問題:緩存穿透、雪崩、擊穿


二、多級緩存架構設計模式

  1. 經典三級緩存模型 ? L1:JVM堆內緩存(Caffeine) ? L2:堆外緩存(Offheap/Redis) ? L3:持久化存儲(MySQL/MongoDB)

  2. 讀寫策略設計 ? Cache-Aside(旁路緩存) ? Read/Write Through(穿透讀寫) ? Write Behind(異步回寫)

  3. 微服務場景下的多級緩存 ? 網關層緩存(Nginx/OpenResty) ? 服務層緩存(Spring Cache注解集成) ? 分布式緩存同步機制


三、本地緩存實戰與性能優化

  1. Caffeine深度解析 ? 緩存淘汰策略(LRU、LFU、W-TinyLFU) ? 過期策略(基于大小、時間、引用)

  2. 堆外緩存應用 ? Ehcache堆外緩存配置 ? MapDB實現本地持久化緩存

  3. 熱點數據發現與預熱 ? 基于LRU的熱點數據統計 ? 定時任務預熱(Quartz/Spring Scheduler)


四、分布式緩存集成與高可用

  1. Redis多級緩存架構 ? 主從復制與哨兵模式 ? Cluster集群分片與數據分布

  2. 緩存與數據庫同步策略 ? 延遲雙刪(Double Delete) ? 基于Binlog的異步同步(Canal+MQ)

  3. 分布式鎖保障數據一致性 ? Redisson實現分布式鎖 ? 鎖粒度控制與鎖續期機制


五、多級緩存實戰場景解析

  1. 電商高并發場景 ? 商品詳情頁多級緩存設計(靜態化+動態加載) ? 庫存緩存與預扣減方案

  2. 社交平臺熱點數據 ? 用戶Feed流緩存策略(推拉結合) ? 實時排行榜(Redis SortedSet)

  3. 金融交易場景 ? 資金賬戶余額緩存(強一致性保障) ? 交易流水異步歸檔


六、緩存問題解決方案

  1. 緩存穿透 ? 布隆過濾器(Bloom Filter)實現 ? 空值緩存與短過期時間

  2. 緩存雪崩 ? 隨機過期時間 ? 熔斷降級與本地容災緩存

  3. 緩存擊穿 ? 互斥鎖(Mutex Lock) ? 邏輯過期時間(Logical Expiration)


七、性能監控與調優

  1. 緩存命中率分析 ? 監控指標(Hit Rate、Miss Rate、Load Time) ? Prometheus + Grafana可視化

  2. JVM緩存調優 ? 堆內緩存GC優化(G1/ZGC) ? 堆外緩存內存泄漏排查(NMT工具)

  3. Redis性能調優 ? 內存碎片整理(Memory Purge) ? Pipeline批處理與Lua腳本優化


八、面試高頻題與實戰案例

  1. 經典面試題 ? Redis如何實現分布式鎖?如何處理鎖續期? ? 如何設計一個支持百萬QPS的緩存架構?

  2. 場景設計題 ? 設計一個秒殺系統的多級緩存方案 ? 如何保證緩存與數據庫的最終一致性?

  3. 實戰案例分析 ? 某電商大促緩存架構優化(TPS從1萬到10萬) ? 社交平臺熱點數據動態降級策略


一、多級緩存基礎與核心概念


1. 緩存的定義與價值

1.1 緩存的應用場景

? 高并發場景: ? 示例:電商秒殺活動,用戶瞬時請求量激增,直接訪問數據庫會導致宕機。 ? 緩存作用:將商品庫存信息緩存在Redis中,請求優先讀取緩存,緩解數據庫壓力。 ? 低延遲需求: ? 示例:社交App的Feed流內容,用戶期望快速加載。 ? 緩存作用:本地緩存(如Caffeine)存儲熱門帖子,響應時間從100ms降至5ms。 ? 減輕數據庫壓力: ? 示例:用戶詳情頁查詢頻繁,但數據更新頻率低。 ? 緩存作用:通過“旁路緩存”模式(Cache-Aside),90%的請求命中緩存。

1.2 多級緩存 vs 單級緩存對比
對比維度單級緩存多級緩存
性能單一層級,性能提升有限本地緩存+分布式緩存,響應速度更快
可用性緩存宕機則請求直接壓到數據庫本地緩存兜底,分布式緩存故障時仍可部分響應
一致性維護一致性管理簡單多層級數據同步復雜,需設計同步策略
適用場景低并發、數據量小高并發、數據量大、延遲敏感型業務

2. 多級緩存核心組件

2.1 本地緩存(Caffeine/Guava Cache)

? Caffeine核心配置

 ?Cache<String, User> cache = Caffeine.newBuilder() ?.maximumSize(10_000) ? ? ? ? ?// 最大緩存條目數 ?.expireAfterWrite(10, TimeUnit.MINUTES) ?// 寫入后10分鐘過期 ?.recordStats() ? ? ? ? ? ? ? ?// 開啟統計(命中率監控) ?.build(); ?
?// 使用示例 ?User user = cache.get("user:123", key -> userDao.findById(123)); ?

? Guava Cache特性: ? 優勢:輕量級、與Spring良好集成。 ? 局限:性能略低于Caffeine,不支持異步加載。

2.2 分布式緩存(Redis/Memcached)

? Redis核心能力: ? 數據結構豐富:String、Hash、List、SortedSet等。 ? 集群模式:主從復制、Cluster分片、Sentinel高可用。 ? 生產級配置yaml spring: redis: cluster: nodes: redis-node1:6379,redis-node2:6379,redis-node3:6379 lettuce: pool: max-active: 20 # 連接池最大連接數

? Memcached適用場景: ? 簡單KV存儲:無需復雜數據結構,追求極致內存利用率。 ? 多線程模型:相比Redis單線程,在多核CPU下吞吐量更高。


3. 緩存一致性挑戰

3.1 數據一致性模型

? 強一致性: ? 定義:緩存與數據庫數據實時一致(如金融賬戶余額)。 ? 實現成本:高(需同步阻塞寫入、分布式鎖)。 ? 最終一致性: ? 定義:允許短暫不一致,但最終數據一致(如商品庫存)。 ? 實現方式:異步消息(MQ)或定時任務同步。

3.2 常見問題與解決方案

? 緩存穿透: ? 問題:惡意請求不存在的數據(如查詢id=-1),繞過緩存擊穿數據庫。 ? 解決方案java // 布隆過濾器(Guava實現) BloomFilter<String> filter = BloomFilter.create( Funnels.stringFunnel(Charset.defaultCharset()), 10000, 0.01); if (!filter.mightContain(key)) { return null; // 直接攔截非法請求 }

? 緩存雪崩: ? 問題:大量緩存同時過期,請求集中訪問數據庫。 ? 解決方案java // 隨機過期時間(30分鐘±隨機10分鐘) redisTemplate.opsForValue().set(key, value, 30 + ThreadLocalRandom.current().nextInt(10), TimeUnit.MINUTES);

? 緩存擊穿: ? 問題:熱點Key過期后,高并發請求擊穿緩存直達數據庫。 ? 解決方案java // Redisson分布式鎖 RLock lock = redissonClient.getLock("product_lock:" + productId); try { if (lock.tryLock(3, 10, TimeUnit.SECONDS)) { // 獲取鎖成功,重新加載數據到緩存 return loadDataFromDB(); } } finally { lock.unlock(); }


總結與面試要點

? 面試高頻問題: ? Q:如何選擇本地緩存和分布式緩存? A:本地緩存用于高頻讀、低一致性要求的場景(如靜態配置),分布式緩存用于跨服務共享數據(如用戶會話)。 ? Q:多級緩存如何保證數據一致性? A:通過“刪除緩存”而非更新緩存、結合消息隊列異步同步、設置合理過期時間。 ? 技術選型建議: ? 小型系統:單級緩存(Redis) + 數據庫。 ? 中大型系統:Caffeine(L1) + Redis(L2) + MySQL(L3)。

通過理解多級緩存的核心概念與挑戰,開發者能夠設計出高性能、高可用的緩存架構,有效應對高并發場景的復雜性。


二、多級緩存架構設計模式


1. 經典三級緩存模型

1.1 L1:JVM堆內緩存(Caffeine)

? 核心特性: ? 極速訪問:數據存儲在JVM堆內存中,基于內存尋址,訪問速度在納秒級。 ? 適用場景:高頻讀取、數據量小(如配置信息、用戶會話Token)。 ? Caffeine實戰配置

Cache<String, Product> productCache = Caffeine.newBuilder() ?.maximumSize(10_000) ? ? ? ? ? ? ? ? ? ? ? ?// 最大緩存條目數 ?.expireAfterWrite(5, TimeUnit.MINUTES) ? ? ?// 寫入后5分鐘過期 ?.refreshAfterWrite(1, TimeUnit.MINUTES) ? ?// 1分鐘后異步刷新 ?.recordStats() ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 開啟命中率統計 ?.build(key -> productDao.getById(key)); ? ? // 緩存加載邏輯 ?

? 性能優化點: ? 使用WeakKeysSoftValues減少內存壓力。 ? 結合異步刷新(refreshAfterWrite)避免緩存過期瞬間的請求風暴。

1.2 L2:堆外緩存(Offheap/Redis)

? 堆外緩存(Ehcache Offheap): ? 優勢:突破JVM堆內存限制,存儲更大數據量(如百MB級商品列表)。 ? 配置示例xml <ehcache> <cache name="productOffheapCache" maxEntriesLocalHeap="0" maxBytesLocalOffHeap="500MB" timeToLiveSeconds="3600"/> </ehcache> ? 分布式緩存(Redis): ? 場景:跨服務共享數據(如用戶會話、分布式鎖)。 ? 數據結構優化java // 使用Hash存儲用戶信息,減少序列化開銷 redisTemplate.opsForHash().put("user:123", "name", "Alice"); redisTemplate.opsForHash().put("user:123", "age", "30");

1.3 L3:持久化存儲(MySQL/MongoDB)

? 兜底策略: ? 緩存未命中時:查詢數據庫并回填緩存,避免直接穿透。 ? 批量加載優化java public List<Product> batchLoadProducts(List<String> ids) { // 先查緩存 Map<String, Product> cachedProducts = cache.getAllPresent(ids); // 未命中部分查數據庫 List<String> missingIds = ids.stream() .filter(id -> !cachedProducts.containsKey(id)) .collect(Collectors.toList()); List<Product> dbProducts = productDao.batchGet(missingIds); cache.putAll(dbProducts.stream() .collect(Collectors.toMap(Product::getId, Function.identity()))); return Stream.concat(cachedProducts.values().stream(), dbProducts.stream()) .collect(Collectors.toList()); }


2. 讀寫策略設計

2.1 Cache-Aside(旁路緩存)

? 讀流程

  1. 先查詢緩存,命中則返回數據。

  2. 未命中則查詢數據庫,并將結果寫入緩存。 ? 寫流程

  3. 更新數據庫。

  4. 刪除或更新緩存(推薦刪除,避免并發寫導致臟數據)。 ? 適用場景:讀多寫少(如用戶詳情頁)。 ? 代碼示例

@Transactional ?
public void updateProduct(Product product) { ?productDao.update(product); ?// 刪除緩存而非更新,避免并發問題 ?cache.invalidate(product.getId()); ?
} ?
2.2 Read/Write Through(穿透讀寫)

? 核心機制:緩存層代理所有數據庫操作。 ? 讀穿透:緩存未命中時,緩存組件自動加載數據庫數據。 ? 寫穿透:寫入緩存時,緩存組件同步更新數據庫。 ? 實現示例(Caffeine + Spring Cache)

 ?@Cacheable(value = "products", unless = "#result == null") ?public Product getProduct(String id) { ?return productDao.getById(id); ?} ?
?@CachePut(value = "products", key = "#product.id") ?public Product updateProduct(Product product) { ?return productDao.update(product); ?} ?
2.3 Write Behind(異步回寫)

? 核心邏輯

  1. 數據先寫入緩存,立即返回成功。

  2. 異步批量或延遲寫入數據庫。 ? 風險與優化

? **數據丟失風險**:緩存宕機導致未持久化數據丟失,需結合WAL(Write-Ahead Logging)。 ?
? **批量合并寫入**:將多次更新合并為一次數據庫操作,減少IO壓力。 ?

? 應用場景:寫密集且容忍最終一致性的場景(如點贊計數)。


3. 微服務場景下的多級緩存

3.1 網關層緩存(Nginx/OpenResty)

? 靜態資源緩存

location /static/ { ?proxy_cache static_cache; ?proxy_pass http://static_service; ?proxy_cache_valid 200 1h; ?add_header X-Cache-Status $upstream_cache_status; ?
} ?

? 動態API緩存

-- OpenResty Lua腳本 ?
local cache = ngx.shared.my_cache ?
local key = ngx.var.uri .. ngx.var.args ?
local value = cache:get(key) ?
if value then ?ngx.say(value) ?return ?
end ?
-- 未命中則請求后端并緩存 ?
local resp = ngx.location.capture("/backend" .. ngx.var.request_uri) ?
cache:set(key, resp.body, 60) ?-- 緩存60秒 ?
ngx.say(resp.body) ?
3.2 服務層緩存(Spring Cache集成)

? 注解驅動開發

 ?@Cacheable(value = "users", key = "#userId", sync = true) ?public User getUser(String userId) { ?return userDao.getById(userId); ?} ?
?@CacheEvict(value = "users", key = "#userId") ?public void updateUser(User user) { ?userDao.update(user); ?} ?

? 多級緩存配置

spring:  cache:  type: caffeine  caffeine:  spec: maximumSize=10000,expireAfterWrite=5m  redis:  time-to-live: 1h  
3.3 分布式緩存同步機制

? 緩存失效廣播

// 使用Redis Pub/Sub通知其他節點  
redisTemplate.convertAndSend("cache:invalidate", "user:123");  

? 版本號控制

  // 緩存值攜帶版本號  public class CacheValue<T> {  private T data;  private long version;  }  // 更新時校驗版本號  if (currentVersion == expectedVersion) {  updateDataAndVersion();  }  

總結與設計原則

? 多級緩存設計原則: ? 層級分明:L1追求速度,L2平衡容量與性能,L3保障數據持久化。 ? 失效策略:結合TTL、LRU和主動失效,避免臟數據。 ? 微服務緩存要點: ? 網關層:攔截高頻請求,減少下游壓力。 ? 服務層:通過注解簡化開發,結合本地與分布式緩存。 ? 同步機制:采用事件驅動或版本控制,確保跨服務緩存一致性。

生產案例:某電商平臺通過三級緩存(Caffeine + Redis + MySQL),將商品詳情頁QPS從5萬提升至50萬,數據庫負載降低80%。


三、本地緩存實戰與性能優化


1. Caffeine深度解析

1.1 緩存淘汰策略對比

? LRU(Least Recently Used): ? 原理:淘汰最久未被訪問的數據。 ? 缺點:無法應對突發流量,可能淘汰高頻訪問但近期未用的數據。 ? 示例:訪問序列A->B->C->A->B,LRU會淘汰C。

? LFU(Least Frequently Used): ? 原理:淘汰訪問頻率最低的數據。 ? 缺點:長期保留歷史熱點數據,無法適應訪問模式變化。 ? 示例:訪問序列A->A->A->B->B,LFU會淘汰B。

? W-TinyLFU(Caffeine默認策略): ? 原理:結合LFU和LRU,通過滑動窗口統計頻率,適應動態訪問模式。 ? 優勢:高吞吐、低內存開銷,適合高并發場景。 ? 配置示例java Cache<String, User> cache = Caffeine.newBuilder() .maximumSize(10_000) .evictionPolicy(EvictionPolicy.W_TinyLFU) .build();

1.2 過期策略配置

? 基于大小淘汰

Caffeine.newBuilder()  .maximumSize(1000)  // 最多緩存1000個條目  .build();  

? 基于時間淘汰

  // 寫入后5分鐘過期  Caffeine.newBuilder()  .expireAfterWrite(5, TimeUnit.MINUTES)  .build();  // 訪問后1分鐘過期  Caffeine.newBuilder()  .expireAfterAccess(1, TimeUnit.MINUTES)  .build();  

? 基于引用淘汰

  // 軟引用緩存(內存不足時GC回收)  Caffeine.newBuilder()  .softValues()  .build();  // 弱引用緩存(GC時直接回收)  Caffeine.newBuilder()  .weakKeys()  .weakValues()  .build();  

2. 堆外緩存應用

2.1 Ehcache堆外緩存配置

? 堆外緩存優勢: ? 突破JVM堆限制:可緩存GB級數據(如大型商品列表)。 ? 減少GC壓力:數據存儲在堆外內存,避免頻繁GC停頓。 ? 配置示例

<ehcache>  <cache name="productCache"  maxEntriesLocalHeap="1000"  maxBytesLocalOffHeap="2G"  timeToIdleSeconds="300">  <persistence strategy="none"/>  </cache>  
</ehcache>  

? Java代碼訪問

CacheManager cacheManager = CacheManager.create();  
Ehcache productCache = cacheManager.getEhcache("productCache");  
productCache.put(new Element("p123", new Product("手機")));  
Product product = (Product) productCache.get("p123").getObjectValue();  
2.2 MapDB實現本地持久化緩存

? 核心特性: ? 持久化存儲:數據落盤,重啟后不丟失。 ? 支持復雜結構:Map、Set、Queue等數據結構。 ? 使用示例

  // 創建或打開數據庫  DB db = DBMaker.fileDB("cache.db").make();  ConcurrentMap<String, Product> map = db.hashMap("products").createOrOpen();  // 寫入數據  map.put("p123", new Product("筆記本電腦"));  // 讀取數據  Product product = map.get("p123");  // 關閉數據庫  db.close();  

? 適用場景: ? 本地緩存需要持久化(如離線應用配置)。 ? 大數據量且允許較高讀取延遲。


3. 熱點數據發現與預熱

3.1 基于LRU的熱點數據統計

? 實現思路

  1. 在緩存訪問時記錄Key的訪問時間和頻率。

  2. 維護一個LRU隊列,定期淘汰尾部低頻數據。 ? 代碼示例

  public class HotspotTracker<K> {  private final LinkedHashMap<K, Long> accessLog = new LinkedHashMap<>(1000, 0.75f, true);  public void trackAccess(K key) {  accessLog.put(key, System.currentTimeMillis());  }  public List<K> getHotKeys(int topN) {  return accessLog.entrySet().stream()  .sorted((e1, e2) -> Long.compare(e2.getValue(), e1.getValue()))  .limit(topN)  .map(Map.Entry::getKey)  .collect(Collectors.toList());  }  }  
3.2 定時任務預熱

? Spring Scheduler預熱示例

@Scheduled(fixedRate = 10 * 60 * 1000) // 每10分鐘執行一次  
public void preloadHotData() {  List<String> hotKeys = hotspotTracker.getHotKeys(100);  hotKeys.forEach(key -> {  Product product = productDao.getById(key);  cache.put(key, product);  });  
}  

? Quartz動態預熱

  public class PreloadJob implements Job {  @Override  public void execute(JobExecutionContext context) {  // 根據業務指標動態調整預熱頻率  int preloadSize = calculatePreloadSize();  List<String> keys = getHotKeys(preloadSize);  preloadToCache(keys);  }  }  // 配置觸發器(每天凌晨2點執行)  Trigger trigger = newTrigger()  .withSchedule(cronSchedule("0 0 2 * * ?"))  .build();  

總結與性能調優建議

? Caffeine調優要點: ? 監控命中率:通過cache.stats()獲取hitRate,低于80%需優化淘汰策略。 ? 合理設置過期時間:結合業務特征(如商品信息1小時,價格信息1分鐘)。 ? 堆外緩存注意事項: ? 內存泄漏:確保及時釋放不再使用的緩存條目。 ? 序列化優化:使用Protostuff等高效序列化工具減少CPU開銷。 ? 熱點數據預熱策略: ? 冷啟動優化:服務啟動時加載基礎熱數據(如首頁商品)。 ? 動態調整:根據實時流量監控動態增減預熱數據量。

面試高頻問題: ? Q: Caffeine的W-TinyLFU相比傳統LRU/LFU有何優勢? A: W-TinyLFU通過頻率統計窗口和LRU隊列,既保留了高頻訪問數據,又能快速淘汰過時熱點,適合動態變化的訪問模式。 ? Q: 堆外緩存可能引發什么問題? A: 數據需序列化/反序列化(CPU開銷),且內存不受JVM管理(需自行監控防止OOM)。

通過本地緩存的精細化管理,系統可顯著提升吞吐量,降低響應延遲,為高并發場景提供穩定支撐。


四、分布式緩存集成與高可用


1. Redis多級緩存架構

1.1 主從復制與哨兵模式

? 主從復制機制: ? 核心原理:主節點(Master)處理寫請求,數據異步復制到從節點(Slave),從節點僅支持讀操作。 ? 配置示例: ```bash # 主節點配置(redis.conf) requirepass masterpass

# 從節點配置  
replicaof <master-ip> 6379  
masterauth masterpass  
```  

? 優勢:讀寫分離提升讀吞吐量,主節點宕機時從節點可接管(需手動切換)。

? 哨兵模式(Sentinel): ? 功能:監控主節點健康狀態,自動故障轉移(選舉新主節點)。 ? 部署方案bash # 哨兵節點配置(sentinel.conf) sentinel monitor mymaster 192.168.1.100 6379 2 sentinel down-after-milliseconds mymaster 5000 sentinel failover-timeout mymaster 60000 ? 高可用流程: 1. 哨兵檢測主節點不可達(超過down-after-milliseconds)。 2. 觸發故障轉移,選舉新主節點。 3. 客戶端通過哨兵獲取新主節點地址。

1.2 Cluster集群分片與數據分布

? 數據分片原理: ? 哈希槽(Hash Slot):Redis Cluster將數據劃分為16384個槽,每個節點負責部分槽。 ? 分片算法CRC16(key) % 16384 計算鍵所屬槽。 ? 集群部署

  # 啟動集群節點  redis-server redis-7000.conf --cluster-enabled yes  # 創建集群(3主3從)  redis-cli --cluster create 192.168.1.100:7000 192.168.1.101:7001 ... --cluster-replicas 1  

? 節點擴縮容

  # 添加新節點  redis-cli --cluster add-node 192.168.1.105:7005 192.168.1.100:7000  # 遷移槽位  redis-cli --cluster reshard 192.168.1.100:7000  

2. 緩存與數據庫同步策略

2.1 延遲雙刪(Double Delete)

? 流程

  1. 刪除緩存:更新數據庫前先刪除緩存。

  2. 更新數據庫:執行數據庫寫操作。

  3. 延遲刪除:等待短暫時間(如500ms)后再次刪除緩存。 ? 代碼示例

public void updateProduct(Product product) {  // 第一次刪除  redisTemplate.delete("product:" + product.getId());  // 更新數據庫  productDao.update(product);  // 延遲刪除(異步線程池執行)  executor.schedule(() -> {  redisTemplate.delete("product:" + product.getId());  }, 500, TimeUnit.MILLISECONDS);  
}  

? 適用場景:應對并發寫導致的臟數據,需結合業務容忍短暫不一致。

2.2 基于Binlog的異步同步(Canal+MQ)

? 技術棧: ? Canal:解析MySQL Binlog,捕獲數據變更事件。 ? 消息隊列:傳輸變更事件(如Kafka、RocketMQ)。 ? 實現步驟

  1. Canal配置

    # canal.properties  
    canal.destinations = test  
    canal.instance.master.address = 127.0.0.1:3306  
  2. 監聽Binlog事件

    // Canal客戶端監聽  
    CanalConnector connector = CanalConnectors.newClusterConnector(  "127.0.0.1:2181", "test", "", "");  
    connector.subscribe(".*\\..*");  
    Message message = connector.getWithoutAck(100);  
    // 解析消息并發送到MQ  
    kafkaTemplate.send("binlog-events", message.getEntries());  
  3. 消費MQ更新緩存

    @KafkaListener(topics = "binlog-events")  
    public void handleBinlogEvent(Event event) {  if (event.getTable().equals("product")) {  redisTemplate.delete("product:" + event.getRow().get("id"));  }  
    }  

    ? 優勢:保證最終一致性,適用于寫多讀少場景。


3. 分布式鎖保障數據一致性

3.1 Redisson分布式鎖實現

? 加鎖與釋放鎖

RLock lock = redissonClient.getLock("product_lock:" + productId);  
try {  // 嘗試加鎖,等待時間5秒,鎖有效期30秒  if (lock.tryLock(5, 30, TimeUnit.SECONDS)) {  Product product = productDao.getById(productId);  // 業務邏輯...  }  
} finally {  lock.unlock();  
}  

? 鎖續期機制: ? Watchdog(看門狗):Redisson后臺線程每隔10秒檢查鎖持有狀態,若業務未完成則續期鎖至30秒。

3.2 鎖粒度控制與優化

? 細粒度鎖:按業務ID鎖定資源(如lock:order:1001),避免全局鎖競爭。 ? 分段鎖優化

// 將庫存拆分為多個段(如10個)  
int segment = productId.hashCode() % 10;  
RLock lock = redissonClient.getLock("stock_lock:" + segment);  

? 讀寫鎖(ReadWriteLock)

RReadWriteLock rwLock = redissonClient.getReadWriteLock("product_rw_lock");  
rwLock.readLock().lock();  // 允許多個讀  
rwLock.writeLock().lock(); // 獨占寫  

總結與最佳實踐

? Redis高可用方案選型

場景推薦方案
中小規模、高可用需求哨兵模式(Sentinel)
大規模數據、水平擴展Cluster集群分片
跨地域多活Redis + 代理層(如Twemproxy)

? 緩存同步策略對比

策略一致性級別適用場景
延遲雙刪最終一致寫并發中等,容忍短暫延遲
Binlog+MQ最終一致寫頻繁,要求可靠同步
分布式鎖強一致高并發寫,需嚴格一致性

? 生產經驗: ? 緩存預熱:服務啟動時加載熱點數據,結合歷史訪問記錄預測熱點。 ? 監控告警:通過Prometheus監控緩存命中率、鎖等待時間,設置閾值告警。 ? 降級策略:緩存故障時降級為直接讀數據庫,避免服務雪崩。

故障案例:某電商平臺因未設置鎖續期機制,導致庫存超賣。引入Redisson看門狗后,鎖自動續期,問題得以解決。

通過合理設計分布式緩存架構與同步策略,可顯著提升系統吞吐量與可用性,同時保障數據一致性,應對高并發挑戰。


五、多級緩存實戰場景解析


1. 電商高并發場景

1.1 商品詳情頁多級緩存設計

? 靜態化 + 動態加載架構

  1. 靜態化HTML:通過模板引擎(如Thymeleaf)生成靜態頁面,緩存至CDN或Nginx本地。

    location /product/{id} {  # 優先返回靜態HTML  try_files /static/product_$id.html @dynamic_backend;  
    }  
  2. 動態加載:未命中靜態頁時,通過Ajax加載實時數據(價格、庫存)。

    // 前端動態請求  
    fetch(`/api/product/${productId}/dynamic`).then(res => res.json());  
  3. 多級緩存策略: ? L1(Nginx):緩存靜態HTML,TTL=10分鐘。 ? L2(Redis):存儲動態數據(JSON格式),TTL=30秒。 ? L3(MySQL):持久化商品基礎信息。

? 緩存更新機制

@CachePut(value = "product", key = "#product.id")  
public Product updateProduct(Product product) {  // 更新數據庫  productDao.update(product);  // 刷新靜態HTML(異步任務)  staticPageService.refresh(product.getId());  return product;  
}  
1.2 庫存緩存與預扣減方案

? 預扣減流程

  1. 緩存扣減:使用Redis原子操作扣減庫存。

    // Lua腳本保證原子性  
    String script = "if redis.call('get', KEYS[1]) >= ARGV[1] then " +  "return redis.call('decrby', KEYS[1], ARGV[1]) " +  "else return -1 end";  
    Long stock = redisTemplate.execute(script, Collections.singletonList("stock:1001"), "1");  
  2. 數據庫同步:異步MQ消息觸發數據庫庫存更新。

    @Transactional  
    public void deductStock(String productId, int count) {  // 先扣Redis  if (redisStockService.deduct(productId, count)) {  // 發送MQ消息同步數據庫  mqTemplate.send("stock_deduct", new StockDeductEvent(productId, count));  }  
    }  

    ? 補償機制

? **超時回滾**:若數據庫更新失敗,通過定時任務回滾Redis庫存。  
? **對賬系統**:每日對比Redis與數據庫庫存差異,修復數據不一致。  

2. 社交平臺熱點數據

2.1 用戶Feed流緩存策略(推拉結合)

? 推模式(寫擴散): ? 場景:大V發布內容時,主動推送到所有粉絲的Feed緩存中。 ? Redis實現java // 大V發帖時推送到粉絲的Feed列表 followers.forEach(follower -> redisTemplate.opsForList().leftPush("feed:" + follower, post.toJSON()) ); // 控制列表長度,保留最新1000條 redisTemplate.opsForList().trim("feed:" + follower, 0, 999); ? 拉模式(讀擴散): ? 場景:普通用戶讀取Feed時,實時拉取關注用戶的動態并合并。 ? 緩存優化: ```java public List<Post> getFeed(String userId) { // 先查本地緩存 List<Post> cached = caffeineCache.getIfPresent(userId); if (cached != null) return cached;

    // 未命中則查詢Redis  List<String> followees = getFollowees(userId);  List<Post> feed = followees.parallelStream()  .flatMap(f -> redisTemplate.opsForList().range("feed:" + f, 0, 100).stream())  .sorted(Comparator.comparing(Post::getTimestamp).reversed())  .limit(100)  .collect(Collectors.toList());  // 寫入本地緩存  caffeineCache.put(userId, feed);  return feed;  
}  
```  
2.2 實時排行榜(Redis SortedSet)

? 積分更新與排名查詢

  // 用戶完成操作后更新積分  redisTemplate.opsForZSet().incrementScore("leaderboard", "user:123", 10);  // 查詢Top 10  Set<ZSetOperations.TypedTuple<String>> topUsers = redisTemplate.opsForZSet()  .reverseRangeWithScores("leaderboard", 0, 9);  

? 冷熱數據分離: ? 熱榜:Redis存儲當天實時數據,TTL=24小時。 ? 歷史榜:每日凌晨將數據歸檔至MySQL,供離線分析。


3. 金融交易場景

3.1 資金賬戶余額緩存(強一致性保障)

? 同步雙寫策略

  1. 數據庫事務:在事務中更新賬戶余額。

  2. 立即更新緩存:事務提交后同步更新Redis。

    @Transactional  
    public void transfer(String from, String to, BigDecimal amount) {  // 扣減轉出賬戶  accountDao.deduct(from, amount);  // 增加轉入賬戶  accountDao.add(to, amount);  // 同步更新緩存  redisTemplate.opsForValue().set("balance:" + from, getBalance(from));  redisTemplate.opsForValue().set("balance:" + to, getBalance(to));  
    }  

    ? 兜底校驗

? **對賬服務**:每小時比對緩存與數據庫余額,差異超過閾值觸發告警。  
? **事務補償**:若緩存更新失敗,記錄日志并異步重試。  
3.2 交易流水異步歸檔

? 削峰填谷設計

  1. 流水寫入緩存:交易發生時,先寫入Redis List。

    redisTemplate.opsForList().rightPush("txn_log", txn.toJSON());  
  2. 批量持久化:定時任務每5分鐘批量讀取并寫入數據庫。

    @Scheduled(fixedDelay = 5 * 60 * 1000)  
    public void archiveTxnLogs() {  List<Txn> txns = redisTemplate.opsForList().range("txn_log", 0, -1)  .stream().map(this::parseTxn).collect(Collectors.toList());  txnDao.batchInsert(txns);  redisTemplate.delete("txn_log");  
    }  

    ? 可靠性保障

? **Redis持久化**:開啟AOF確保日志不丟失。  
? **冪等寫入**:為每條流水生成唯一ID,避免重復插入。  

總結與面試高頻問題

? 場景策略對比

場景緩存核心目標一致性要求關鍵技術
電商高并發高可用、低延遲最終一致靜態化、預扣減、異步對賬
社交熱點實時性、動態合并最終一致推拉結合、SortedSet、冷熱分離
金融交易強一致、數據安全強一致同步雙寫、事務補償、冪等設計

? 高頻面試題: ? Q:如何解決商品詳情頁的緩存與數據庫不一致問題? A:采用延遲雙刪策略,結合異步對賬服務修復差異。 ? Q:推拉結合模式中,如何避免大V粉絲量過大導致的推送性能問題? A:分批次異步推送,或采用“活躍粉絲”策略僅推送最近在線的用戶。 ? Q:金融場景下,如何保證緩存與數據庫的強一致性? A:通過數據庫事務保證數據持久化,事務提交后同步更新緩存,結合對賬機制兜底。

生產案例:某支付系統通過“同步雙寫+對賬服務”,將余額查詢的響應時間從50ms降至5ms,且全年未出現資損事件。

通過針對不同業務場景設計定制化的多級緩存方案,開發者能夠在高并發、低延遲、強一致性等需求中找到平衡點,構建高性能且可靠的系統架構。


六、緩存問題解決方案


1. 緩存穿透

1.1 布隆過濾器(Bloom Filter)實現

? 核心原理:通過多個哈希函數將元素映射到位數組中,判斷元素是否存在。 ? Guava實現示例

  // 初始化布隆過濾器(預期插入10000個元素,誤判率1%)  BloomFilter<String> bloomFilter = BloomFilter.create(  Funnels.stringFunnel(Charset.defaultCharset()), 10000, 0.01);  // 預熱數據  List<String> validKeys = getValidKeysFromDB();  validKeys.forEach(bloomFilter::put);  // 查詢攔截  public Product getProduct(String id) {  if (!bloomFilter.mightContain(id)) {  return null; // 直接攔截非法請求  }  return cache.get(id, () -> productDao.getById(id));  }  

? 適用場景:攔截明確不存在的數據(如無效ID、惡意攻擊)。

1.2 空值緩存與短過期時間

? 實現邏輯:將查詢結果為空的Key也緩存,避免重復穿透。 ? 代碼示例

public Product getProduct(String id) {  Product product = cache.get(id);  if (product == null) {  product = productDao.getById(id);  if (product == null) {  // 緩存空值,過期時間5分鐘  cache.put(id, Product.EMPTY, 5, TimeUnit.MINUTES);  } else {  cache.put(id, product);  }  }  return product == Product.EMPTY ? null : product;  
}  

? 注意事項: ? 空值需明確標記(如特殊對象),避免與正常數據混淆。 ? 短過期時間(如5分鐘)防止存儲大量無效Key。


2. 緩存雪崩

2.1 隨機過期時間

? 核心思路:為緩存Key設置隨機過期時間,避免同時失效。 ? 代碼實現

public void setWithRandomExpire(String key, Object value, long baseExpire, TimeUnit unit) {  long expire = baseExpire + ThreadLocalRandom.current().nextInt(0, 300); // 隨機增加0~5分鐘  redisTemplate.opsForValue().set(key, value, expire, unit);  
}  

? 適用場景:緩存批量預熱或定時刷新場景。

2.2 熔斷降級與本地容災緩存

? 熔斷機制:當數據庫壓力過大時,觸發熔斷直接返回默認值。

  // Resilience4j熔斷配置  CircuitBreakerConfig config = CircuitBreakerConfig.custom()  .failureRateThreshold(50) // 失敗率閾值50%  .waitDurationInOpenState(Duration.ofSeconds(30))  .build();  CircuitBreaker circuitBreaker = CircuitBreaker.of("dbCircuitBreaker", config);  public Product getProduct(String id) {  return circuitBreaker.executeSupplier(() -> productDao.getById(id));  }  

? 本地容災緩存:使用Ehcache緩存兜底數據。

public Product getProduct(String id) {  Product product = redisTemplate.get(id);  if (product == null) {  product = ehcache.get(id); // 本地緩存兜底  if (product == null) {  throw new ServiceUnavailableException("服務不可用");  }  }  return product;  
}  

3. 緩存擊穿

3.1 互斥鎖(Mutex Lock)

? 分布式鎖實現:使用Redisson保證只有一個線程加載數據。

public Product getProduct(String id) {  Product product = cache.get(id);  if (product == null) {  RLock lock = redissonClient.getLock("product_lock:" + id);  try {  if (lock.tryLock(3, 10, TimeUnit.SECONDS)) { // 嘗試加鎖  product = cache.get(id); // 雙重檢查  if (product == null) {  product = productDao.getById(id);  cache.put(id, product, 30, TimeUnit.MINUTES);  }  }  } finally {  lock.unlock();  }  }  return product;  
}  

? 優化點: ? 鎖粒度細化(按資源ID加鎖)。 ? 鎖超時時間合理設置(避免死鎖)。

3.2 邏輯過期時間(Logical Expiration)

? 實現邏輯:緩存永不過期,但存儲邏輯過期時間,異步刷新。

  public class CacheWrapper<T> {  private T data;  private long expireTime; // 邏輯過期時間  public boolean isExpired() {  return System.currentTimeMillis() > expireTime;  }  }  public Product getProduct(String id) {  CacheWrapper<Product> wrapper = cache.get(id);  if (wrapper == null || wrapper.isExpired()) {  // 異步刷新緩存  executor.submit(() -> reloadProduct(id));  return wrapper != null ? wrapper.getData() : null;  }  return wrapper.getData();  }  

? 優勢:用戶無感知,始終返回數據,避免請求堆積。


總結與方案對比

問題解決方案適用場景實現復雜度
緩存穿透布隆過濾器 + 空值緩存惡意攻擊、無效ID高頻訪問
緩存雪崩隨機過期時間 + 熔斷降級批量緩存失效、數據庫高負載
緩存擊穿互斥鎖 + 邏輯過期時間熱點數據失效、高并發場景

生產經驗: ? 監控告警:通過Prometheus監控緩存命中率、穿透率、鎖競爭次數。 ? 動態調整:根據實時流量調整熔斷閾值和鎖超時時間。 ? 壓測驗證:定期模擬高并發場景,驗證方案有效性。

面試高頻問題: ? Q:布隆過濾器有什么缺點? A:存在誤判率(可通過增加哈希函數降低),且刪除元素困難(需使用Counting Bloom Filter)。 ? Q:邏輯過期時間如何保證數據最終一致? A:異步線程定期掃描過期Key并刷新,結合版本號或時間戳控制并發更新。

通過針對不同緩存問題的特性設計解決方案,系統可在高并發場景下保持穩定,兼顧性能與可靠性。


七、性能監控與調優


1. 緩存命中率分析

1.1 監控指標定義

? Hit Rate(命中率): ? 公式Hit Rate = (Cache Hits) / (Cache Hits + Cache Misses) ? 健康指標:建議保持在80%以上,低于60%需優化緩存策略。 ? Miss Rate(未命中率): ? 公式Miss Rate = 1 - Hit Rate,突增可能預示緩存穿透或雪崩。 ? Load Time(加載耗時): ? 定義:緩存未命中時從數據庫加載數據的平均耗時。 ? 告警閾值:若Load Time > 500ms,需優化查詢或引入異步加載。

1.2 Prometheus + Grafana可視化

? Exporter配置(以Caffeine為例):

// 注冊Caffeine指標到Micrometer  
CaffeineCache cache = Caffeine.newBuilder().recordStats().build();  
Metrics.gauge("cache.size", cache, c -> c.estimatedSize());  
Metrics.counter("cache.hits").bindTo(cache.stats().hitCount());  
Metrics.counter("cache.misses").bindTo(cache.stats().missCount());  

? Grafana儀表盤

-- 查詢命中率  
sum(rate(cache_hits_total[5m])) /   
(sum(rate(cache_hits_total[5m])) + sum(rate(cache_misses_total[5m])))  


2. JVM緩存調優

2.1 堆內緩存GC優化

? G1垃圾收集器配置

# 啟動參數  
java -Xms4G -Xmx4G -XX:+UseG1GC -XX:MaxGCPauseMillis=200  

? 優勢:通過Region分區和并發標記,減少GC停頓時間。 ? 適用場景:堆內存較大(>4GB)且緩存對象生命周期短。 ? ZGC低延遲優化

java -Xms8G -Xmx8G -XX:+UseZGC -XX:MaxMetaspaceSize=512M  

? 優勢:亞毫秒級停頓,適合對延遲敏感的實時系統。 ? 限制:JDK 11+支持,內存需超過8GB。

2.2 堆外緩存內存泄漏排查

? NMT(Native Memory Tracking)工具

  # 啟動應用時開啟NMT  java -XX:NativeMemoryTracking=detail -jar app.jar  # 生成內存報告  jcmd <pid> VM.native_memory detail > nmt.log  

? 分析重點:檢查Internal部分的malloc調用是否持續增長。 ? Ehcache堆外緩存監控

// 獲取堆外內存使用量  
long offHeapSize = ehcache.calculateOffHeapSize();  

3. Redis性能調優

3.1 內存碎片整理

? 手動觸發整理

# 執行內存碎片整理(阻塞操作,建議低峰期執行)  
redis-cli MEMORY PURGE  

? 自動整理配置

# 當碎片率超過1.5時自動整理  
config set activedefrag yes  
config set active-defrag-ignore-bytes 100mb  
config set active-defrag-threshold-lower 10  
3.2 Pipeline與Lua腳本優化

? Pipeline批處理

List<Object> results = redisTemplate.executePipelined(connection -> {  for (int i = 0; i < 1000; i++) {  connection.stringCommands().set(("key:" + i).getBytes(), ("value:" + i).getBytes());  }  return null;  
});  

? 性能提升:減少網絡往返時間(RTT),吞吐量提升5-10倍。 ? Lua腳本原子操作

-- 統計在線用戶數并設置過期時間  
local key = KEYS[1]  
local user = ARGV[1]  
redis.call('SADD', key, user)  
redis.call('EXPIRE', key, 3600)  
return redis.call('SCARD', key)  

? 優勢:原子性執行復雜操作,減少多次網絡交互。


總結與調優建議

? 緩存命中率調優: ? 提升策略:增加緩存容量、優化淘汰策略、預加載熱點數據。 ? 告警規則:設置命中率低于70%觸發告警,并自動擴容Redis集群。 ? JVM內存管理: ? 堆內緩存:選擇G1/ZGC降低GC影響,監控Old Gen使用率。 ? 堆外緩存:定期通過NMT分析內存泄漏,限制Ehcache的Offheap大小。 ? Redis性能調優: ? 內存優化:使用ziplist編碼小規模數據,啟用jemalloc內存分配器。 ? 高并發寫入:分片(Sharding)降低單節點壓力,開啟AOF持久化。

生產案例:某社交平臺通過優化Lua腳本(合并10次操作為1次),Redis的QPS從5萬提升至15萬,CPU使用率下降40%。

持續監控與迭代

  1. 自動化巡檢:每周生成緩存健康報告,包含命中率Top10的Key和碎片率。

  2. 容量規劃:根據業務增長預測緩存容量,提前擴容。

  3. 壓測驗證:通過JMeter模擬高峰流量,驗證調優效果。

通過系統化的監控與調優,多級緩存架構能夠在高并發場景下保持高性能與穩定性,支撐業務快速發展。


八、面試高頻題與實戰案例


1. 經典面試題

1.1 Redis如何實現分布式鎖?如何處理鎖續期?

? 實現原理

  1. 加鎖:使用SET key value NX EX seconds命令,保證原子性。

    -- Lua腳本確保原子性  
    if redis.call("SET", KEYS[1], ARGV[1], "NX", "EX", ARGV[2]) then  return 1  
    else  return 0  
    end  
  2. 解鎖:通過Lua腳本驗證鎖持有者,避免誤刪他人鎖。

    if redis.call("GET", KEYS[1]) == ARGV[1] then  return redis.call("DEL", KEYS[1])  
    else  return 0  
    end  

    ? 鎖續期(Redisson Watchdog)

? 后臺線程每隔10秒檢查鎖是否仍被持有,若持有則續期至30秒。  
? **代碼示例**:  ```java  
RLock lock = redissonClient.getLock("order_lock");  
lock.lock(30, TimeUnit.SECONDS);  // 自動觸發Watchdog  
```  

? 面試加分點: ? 誤刪風險:必須通過唯一客戶端標識(UUID)驗證鎖歸屬。 ? 鎖粒度優化:按業務ID分段加鎖(如lock:order:1001)。

1.2 如何設計一個支持百萬QPS的緩存架構?

? 分層設計

  1. 客戶端緩存:瀏覽器緩存靜態資源(HTML/CSS/JS),CDN加速。

  2. 網關層緩存:Nginx/OpenResty緩存動態API響應(TTL=1秒)。

  3. 服務層緩存: ? 本地緩存:Caffeine(L1)緩存熱點數據,TTL=500ms。 ? 分布式緩存:Redis Cluster(L2)分片存儲,單節點QPS可達10萬。

  4. 持久層優化:MySQL分庫分表 + 讀寫分離,異步批量寫入。 ? 核心策略

? **熱點數據預加載**:通過離線分析提前緩存高頻訪問數據。  
? **請求合并**:使用Redis Pipeline或Lua腳本減少網絡開銷。  
? **限流熔斷**:Sentinel或Hystrix保護下游服務。  

2. 場景設計題

2.1 設計一個秒殺系統的多級緩存方案

? 架構分層

  1. 網關層: ? 限流:Nginx漏桶算法限制每秒10萬請求。 ? 靜態化:商品詳情頁HTML緩存至CDN。

  2. 服務層: ? 本地緩存:Caffeine緩存庫存余量,TTL=100ms。 ? Redis集群:庫存預扣減(原子操作DECRBY),扣減成功后再異步落庫。

    // Lua腳本保證原子扣減  
    String script = "if redis.call('GET', KEYS[1]) >= ARGV[1] then " +  "redis.call('DECRBY', KEYS[1], ARGV[1]) " +  "return 1 else return 0 end";  
    Long result = redisTemplate.execute(script, List.of("stock:1001"), "1");  
  3. 數據庫層: ? 異步隊列:Kafka緩沖訂單請求,批量寫入MySQL。 ? 分庫分表:訂單表按用戶ID哈希分16庫,每庫256表。 ? 容災設計

? **降級策略**:若Redis不可用,直接拒絕請求(非核心功能降級)。  
? **對賬補償**:定時任務對比Redis與數據庫庫存,修復不一致。  
2.2 如何保證緩存與數據庫的最終一致性?

? 方案對比

方案一致性級別實現復雜度適用場景
延遲雙刪最終一致寫并發中等,容忍短暫延遲
Canal+MQ最終一致寫頻繁,要求可靠同步
分布式事務強一致極高金融交易等高敏感場景
? Canal+MQ實現步驟
  1. Binlog訂閱:Canal解析MySQL Binlog,推送變更事件到MQ。

  2. 消費MQ更新緩存

    @KafkaListener(topics = "db_events")  
    public void handleEvent(DbEvent event) {  if (event.getTable().equals("product")) {  redisTemplate.delete("product:" + event.getId());  }  
    }  

    ? 版本號控制

// 緩存數據攜帶版本號  
public class CacheValue {  private Object data;  private long version;  
}  
// 更新時校驗版本號  
if (currentVersion == expectedVersion) {  updateDataAndVersion();  
}  

3. 實戰案例分析

3.1 某電商大促緩存架構優化(TPS從1萬到10萬)

? 優化措施

  1. 多級緩存引入: ? L1:Caffeine本地緩存商品詳情,TTL=200ms。 ? L2:Redis Cluster分片存儲庫存和價格,單節點QPS提升至5萬。

  2. 庫存預扣減優化: ? Redis Lua腳本原子扣減,異步MQ同步數據庫。

  3. 熱點數據動態預熱: ? 基于歷史訪問數據,提前加載Top 1000商品到本地緩存。

  4. 限流熔斷: ? 網關層限流(每秒10萬請求),服務層熔斷(失敗率>30%觸發)。 ? 效果

? TPS從1萬提升至10萬,數據庫負載降低70%。  
? 用戶平均響應時間從200ms降至50ms。  
3.2 社交平臺熱點數據動態降級策略

? 背景:明星發帖導致瞬時流量激增,Feed流服務崩潰。 ? 解決方案

  1. 熱點探測:實時統計接口QPS,Top 10熱點數據標記為“高危”。

  2. 動態降級: ? 本地緩存兜底:返回3分鐘前的緩存數據,犧牲實時性保可用性。 ? 熔斷策略:若Feed流接口QPS超過閾值,直接返回靜態推薦列表。

  3. 異步更新:降級期間,后臺線程異步刷新熱點數據。 ? 結果

? 服務可用性從80%提升至99.9%,峰值QPS支持100萬。  
? 用戶感知為“信息延遲”,但無服務崩潰。  

總結與面試技巧

? 回答框架

  1. 問題拆解:將復雜問題分解為緩存設計、一致性、性能優化等子問題。

  2. 分層設計:從客戶端到數據庫逐層分析,明確每層技術選型。

  3. 數據支撐:引用生產案例數據(如QPS提升比例)增強說服力。 ? 高頻考點

? **緩存 vs 數據庫**:何時用緩存?如何保證一致性?  
? **鎖 vs 無鎖**:Redis鎖與CAS無鎖化方案的取舍。  

? 避坑指南: ? 避免過度設計:非金融場景不必強求強一致性。 ? 監控先行:沒有監控的優化是盲目的,Prometheus + Grafana必備。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/80599.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/80599.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/80599.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MySQL的MVCC【學習筆記】

MVCC 事務的隔離級別分為四種&#xff0c;其中Read Committed和Repeatable Read隔離級別&#xff0c;部分實現就是通過MVCC&#xff08;Multi-Version Concurrency Control&#xff0c;多版本并發控制&#xff09; 版本鏈 版本鏈是通過undo日志實現的&#xff0c; 事務每次修改…

基于OpenMV+STM32+OLED與YOLOv11+PaddleOCR的嵌入式車牌識別系統開發筆記

基于OpenMV、STM32與OLED的嵌入式車牌識別系統開發筆記 基于OpenMV、STM32與OLED的嵌入式車牌識別系統開發筆記系統架構全景 一、實物演示二、OpenMV端設計要點1. 硬件配置優化2. 智能幀率控制算法3. 數據傳輸協議設計 三、PyTorch后端核心實現&#xff1a;YOLOv11與PaddleOCR的…

C#中常見的設計模式

文章目錄 引言設計模式的分類創建型模式 (Creational Patterns)1. 單例模式 (Singleton)2. 工廠方法模式 (Factory Method)3. 抽象工廠模式 (Abstract Factory)4. 建造者模式 (Builder) 結構型模式 (Structural Patterns)5. 適配器模式 (Adapter)6. 裝飾器模式 (Decorator)7. 外…

Nacos簡介—3.Nacos的配置簡介

大綱 1.Nacos生產集群Web端口與數據庫配置 2.Nacos生產集群的Distro協議核心參數 3.Nacos打通CMDB實現跨機房的就近訪問 4.Nacos基于SPI動態擴展機制來獲取CMDB的數據 5.基于Nacos SPI機制開發CMDB動態擴展 6.Nacos基于CMDB來實現多機房就近訪問 7.Nacos生產集群Prometh…

Jest 快照測試

以下是關于 Jest 快照測試的系統化知識總結,從基礎使用到底層原理全面覆蓋: 一、快照測試核心原理 1. 工作機制三階段 #mermaid-svg-GC46t2NBvGv7RF0M {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GC46t2NBvGv…

第十六屆藍橋杯大賽軟件賽省賽 C/C++ 大學B組 [京津冀]

由于官方沒有公布題目的數據, 所以代碼僅供參考 1. 密密擺放 題目鏈接&#xff1a;P12337 [藍橋杯 2025 省 AB/Python B 第二場] 密密擺放 - 洛谷 題目描述 小藍有一個大箱子&#xff0c;內部的長寬高分別是 200、250、240&#xff08;單位&#xff1a;毫米&#xff09;&…

Spring 學習筆記之 @Transactional 異常不回滾匯總

使用springboot時&#xff0c;只要引入spring-jdbc/jpa相關的依賴后&#xff0c;在想要啟用事務的方法上加上Transactional注解就能開啟事務&#xff0c;碰到異常就能自動回滾。大大的提高了編碼的便捷性性&#xff0c;同時也不侵入代碼&#xff0c;保持了代碼的簡潔性。 默認情…

React 與 Vue 虛擬 DOM 實現原理深度對比:從理論到實踐

在現代前端開發中&#xff0c;React 和 Vue 作為最流行的兩大框架&#xff0c;都采用了虛擬 DOM&#xff08;Virtual DOM&#xff09; 技術來優化渲染性能。虛擬 DOM 的核心思想是通過 JavaScript 對象模擬真實 DOM&#xff0c;減少直接操作 DOM 的開銷&#xff0c;從而提高頁面…

WordPress AI 原創文章自動生成插件 24小時全自動生成SEO原創文章 | 多語言支持 | 智能配圖與排版

為什么選擇Linkreate AI內容生成插件&#xff1f; ? 全自動化工作流程 - 從關鍵詞挖掘到文章發布一站式完成 ? 多語言支持 - 輕松覆蓋全球市場&#xff08;中/英等多語種&#xff09; ? 智能SEO優化 - 自動生成搜索引擎友好的內容結構 ? AI智能配圖 - 每篇文章自動匹配高質…

GPU加速-系統CUDA12.5-Windows10

誤區注意 查看當前系統可支持的最高版本cuda&#xff1a;nvidia-smi 說明&#xff1a; 此處顯示的12.7只是驅動對應的最高版本&#xff0c;不一定是 / 也不一定需要是 當前Python使用的版本。但我們所安裝的CUDA版本需要 小于等于它&#xff08;即≤12.7&#xff09;因此即使…

IOT項目——DIY 氣象站

開源項目&#xff1a;ESP32 氣象站 作者&#xff1a;GiovanniAggiustatutto 原文鏈接&#xff1a;原文 開源項目&#xff1a;太陽能 WiFi 氣象站 V4.0 作者&#xff1a;opengreenenergy 原文鏈接&#xff1a;原文 DIY 氣象站 簡介1-制版2-物料 溫度設備塔風向標風速計雨量計框…

5G助力智慧城市的崛起——從概念到落地的技術實踐

5G助力智慧城市的崛起——從概念到落地的技術實踐 引言&#xff1a;智慧城市中的“隱形脈絡” 隨著城市化的快速推進&#xff0c;傳統的城市管理方式已經難以滿足人口增長和資源優化的需求。智慧城市的概念應運而生&#xff0c;通過技術創新實現智能化、可持續發展的城市生態…

【Linux】web服務器的部署和優化

目錄 nginx的安裝與啟用--/usr/share/nginx/html默認發布目錄 nginx的主配置文件--/etc/nginx/nginx_conf nginx的端口 nginx默認發布文件--index.html nginx默認發布目錄 nginx的訪問控制 基于IP地址的訪問控制 基于用戶認證的訪問控制 nginx的虛擬主機--/etc/nginx/…

結合五層網絡結構講一下用戶在瀏覽器輸入一個網址并按下回車后到底發生了什么?

文章目錄 實際應用第一步&#xff1a;用戶在瀏覽器輸入 www.baidu.com 并按下回車1. 瀏覽器觸發域名解析&#xff08;DNS查詢&#xff09; 第二步&#xff1a;DNS請求的逐層封裝與傳輸1. 應用層&#xff08;DNS協議&#xff09;2. 傳輸層&#xff08;UDP協議&#xff09;3. 網絡…

深入理解N皇后問題:從DFS到對角線優化

N皇后問題是一個經典的算法問題&#xff0c;要求在NN的棋盤上放置N個皇后&#xff0c;使得它們互不攻擊。本文將全面解析該問題的解法&#xff0c;特別聚焦于DFS算法和對角線優化的數學原理。 問題描述 在NN的國際象棋棋盤上放置N個皇后&#xff0c;要求&#xff1a; 任意兩個…

Java面試場景篇:分布式鎖的實現與組件詳解

互聯網大廠Java求職者面試&#xff1a;分布式鎖的實現與組件 在一場緊張而又充滿挑戰的面試中&#xff0c;Java架構師馬架構正面對著一位經驗豐富的面試官。以下是他們之間關于分布式鎖實現方式及相關問題的對話。 第一輪提問 面試官&#xff1a;請介紹一下分布式鎖的概念。…

關于使用 讀光-文字檢測-DBNet行檢測模型-中英-通用領域,版本問題

關于使用 讀光-文字檢測-DBNet行檢測模型-中英-通用領域&#xff0c;版本問題 pip install modelscopeSuccessfully installed certifi-2025.4.26 charset-normalizer-3.4.1 colorama-0.4.6 idna-3.10 modelscope-1.25.0 requests-2.32.3 tqdm-4.67.1 urllib3-2.4.0 pip insta…

刷刷刷刷刷RCE

云曦歷年考核 25年春開學考 RCCCE 開啟題目進行代碼審計 GET傳參傳入一個參數cmd&#xff0c;但對參數內容給了黑名單進行過濾 $blacklist /bash|nc|wget|ping|ls|cat|more|less|phpinfo|base64|echo|php|python|mv|cp|la|\-|\*|"|\>|\<|\%|\$/i; ls、cat等都…

2024江西ICPC部分題解

題目列表 A - Maliang Learning PaintingC - LiarG - Multiples of 5H - ConvolutionJ - Magic MahjongK - Magic Tree A - Maliang Learning Painting 題目來源&#xff1a;A - Maliang Learning Painting 思路分析 這是個簽到題&#xff0c;直接輸出abc即可 #include<b…

Pytorch圖像數據轉為Tensor張量

PyTorch的所有模型&#xff08;nn.Module&#xff09;都只接受Tensor格式的輸入&#xff0c;所以我們在使用圖像數據集時&#xff0c;必須將圖像轉換為Tensor格式。PyTorch提供了torchvision.transforms模塊來處理圖像數據集。torchvision.transforms模塊提供了一些常用的圖像預…