設(shè)計強悍的本地緩存需綜合考慮數(shù)據(jù)結(jié)構(gòu)、淘汰策略、更新機制及監(jiān)控功能,以下是關(guān)鍵設(shè)計要點:
核心設(shè)計原則
?數(shù)據(jù)結(jié)構(gòu)選擇?:優(yōu)先使用ConcurrentHashMap等線程安全的數(shù)據(jù)結(jié)構(gòu),避免并發(fā)訪問時的性能瓶頸。 ?1?淘汰策略?:推薦使用LRU(最近最少使用)或FIFO(先進先出)策略,結(jié)合容量限制確保內(nèi)存高效利用。 ?
?更新策略?:采用Write-Through(寫時穿透)或Write-Behind(寫后延遲)策略,平衡數(shù)據(jù)一致性和寫入性能。 ?
性能優(yōu)化
?過期策略?:支持基于創(chuàng)建時間或訪問時間的動態(tài)過期機制,例如設(shè)置5分鐘未訪問則自動失效。 ?
?多級緩存架構(gòu)?:結(jié)合分布式緩存(如Redis)作為后備,提升命中率并減少數(shù)據(jù)庫壓力。 ?
監(jiān)控與維護
?動態(tài)調(diào)整?:通過緩存命中率、寫入延遲等指標動態(tài)調(diào)整容量和策略。 ?
?異常處理?:設(shè)置緩存失效回退機制,避免因緩存故障導(dǎo)致服務(wù)中斷。 ?
典型應(yīng)用場景
?高頻訪問靜態(tài)數(shù)據(jù)?:如系統(tǒng)配置、字典表等,命中率可達90%以上。 ?
?實時性要求低的數(shù)據(jù)?:如商品分類列表,可設(shè)置較長的過期時間(如1小時)。 ?
工具選擇
?Java框架?:Guava、Caffeine提供豐富的API和監(jiān)控功能,適合復(fù)雜業(yè)務(wù)場景。 ?
?內(nèi)存管理?:通過maximumSize限制內(nèi)存占用,避免OOM異常。 ?
緩存是一種常見的技術(shù),目標是提高系統(tǒng)的性能和可伸縮性。 緩存將經(jīng)常訪問的數(shù)據(jù)暫時復(fù)制到靠近應(yīng)用程序的快速存儲。 當(dāng)快速數(shù)據(jù)存儲比其原始數(shù)據(jù)存儲更靠近應(yīng)用程序時,緩存可以通過更快地提供數(shù)據(jù),大幅改善客戶端應(yīng)用程序的響應(yīng)時間。
當(dāng)客戶端實例重復(fù)讀取同一數(shù)據(jù)時,緩存是最有效的方式,尤其是在原始數(shù)據(jù)存儲存在以下情況時:
原始數(shù)據(jù)存儲保持相對靜態(tài)。
受限于激烈的資源爭用。
它距離很遠,網(wǎng)絡(luò)延遲可能會導(dǎo)致對存儲的訪問速度變慢。
假設(shè) Tailwind Traders 正在向產(chǎn)品演示應(yīng)用程序添加一項新功能,以增加其零售網(wǎng)站的客戶流量。 事件功能在移動應(yīng)用頂部添加了一個橫幅,以宣布特價優(yōu)惠和有限的產(chǎn)品折扣。 新優(yōu)惠在整點發(fā)布,每種優(yōu)惠的剩余產(chǎn)品可用性在每個訂單得到處理后更新。 第一位響應(yīng)新優(yōu)惠的客戶將獲得雙倍折扣! 建議客戶經(jīng)常查看其移動應(yīng)用,了解優(yōu)惠和產(chǎn)品可用性的相關(guān)更新。 若要實現(xiàn)這項新功能,你需要設(shè)計一個可支持內(nèi)存中快速讀取和寫入的緩存解決方案。
1. 確定緩存需求
分析業(yè)務(wù)場景:明確哪些數(shù)據(jù)需要緩存。通常,訪問頻繁、變化頻率低的數(shù)據(jù)適合緩存,如商品分類列表、系統(tǒng)配置參數(shù)等。而實時性要求極高、頻繁變動的數(shù)據(jù)(如股票價格、即時聊天消息)可能不適合長時間緩存。
設(shè)定性能目標:確定緩存機制要達到的性能指標,例如緩存命中率要達到多少(一般建議 80%以上),緩存數(shù)據(jù)的讀取和寫入延遲控制在什么范圍內(nèi)等。
2. 選擇緩存技術(shù)
內(nèi)存緩存:
Redis:是最常用的內(nèi)存緩存之一,支持多種數(shù)據(jù)結(jié)構(gòu)(如字符串、哈希、列表、集合等),具有高性能、可持久化、分布式等特點。適用于各種規(guī)模的應(yīng)用,能滿足不同業(yè)務(wù)場景下的數(shù)據(jù)緩存需求。
Memcached:也是一款流行的內(nèi)存緩存系統(tǒng),專注于簡單的鍵值存儲,在處理高并發(fā)讀寫時性能出色。常用于緩存數(shù)據(jù)庫查詢結(jié)果、網(wǎng)頁片段等。
分布式緩存:
Apache Ignite:提供分布式內(nèi)存計算和數(shù)據(jù)存儲功能,支持集群環(huán)境下的緩存管理,具備強大的容錯性和可擴展性,適合大規(guī)模分布式系統(tǒng)。
Couchbase:是一個分布式文檔數(shù)據(jù)庫,同時也可作為高性能緩存使用,支持多數(shù)據(jù)中心部署,能滿足復(fù)雜的企業(yè)級應(yīng)用需求。
3. 設(shè)計緩存結(jié)構(gòu)鍵值設(shè)計:
鍵的設(shè)計:確保緩存鍵的唯一性和可讀性。鍵名應(yīng)能清晰反映緩存數(shù)據(jù)的內(nèi)容,例如以 “category_list_${language}_${version}” 表示特定語言和版本的商品分類列表緩存鍵。同時,要避免鍵名過長,以免占用過多內(nèi)存和影響查詢效率。
值的設(shè)計:根據(jù)數(shù)據(jù)類型和業(yè)務(wù)需求選擇合適的值結(jié)構(gòu)。對于簡單數(shù)據(jù),直接使用字符串存儲即可;對于復(fù)雜對象,可以序列化為 JSON 或二進制格式(如 Protocol Buffers)后存儲,以節(jié)省內(nèi)存空間。
緩存分區(qū):
按功能分區(qū):將不同業(yè)務(wù)功能的數(shù)據(jù)緩存到不同區(qū)域,如用戶相關(guān)緩存、商品相關(guān)緩存等,便于管理和維護。
按數(shù)據(jù)熱度分區(qū):把熱門數(shù)據(jù)和冷門數(shù)據(jù)分開緩存。熱門數(shù)據(jù)可以放在高性能的緩存區(qū)域或設(shè)置較短的過期時間以保證數(shù)據(jù)新鮮度;冷門數(shù)據(jù)則可以存儲在相對較慢但成本較低的存儲介質(zhì)中,或者設(shè)置較長的過期時間。
4. 緩存策略
緩存過期策略:
絕對過期時間:為緩存數(shù)據(jù)設(shè)置固定的過期時間,到期后緩存自動失效。例如,對于一些時效性較強的新聞資訊緩存,可設(shè)置 1 小時的過期時間。
滑動過期時間:每次訪問緩存數(shù)據(jù)時,自動延長其過期時間。適用于經(jīng)常被訪問的數(shù)據(jù),如熱門商品詳情緩存,只要有用戶訪問,就保持緩存的有效性。
緩存更新策略:
寫后更新:在數(shù)據(jù)發(fā)生變化后,立即更新緩存。這種方式簡單直接,但可能會導(dǎo)致短時間內(nèi)緩存數(shù)據(jù)與實際數(shù)據(jù)不一致。例如,在更新商品價格后,馬上更新對應(yīng)的商品價格緩存。
讀寫鎖策略:在讀取緩存時加讀鎖,允許多個線程同時讀取;在更新緩存時加寫鎖,獨占緩存資源,確保數(shù)據(jù)一致性。這種策略適用于讀多寫少的場景。
緩存淘汰策略:
LRU(最近最少使用):當(dāng)緩存達到最大容量時,淘汰最近最少使用的緩存數(shù)據(jù)。許多緩存庫(如 Redis)都支持 LRU 淘汰策略,它能保證經(jīng)常使用的數(shù)據(jù)始終留在緩存中。
LFU(最不經(jīng)常使用):淘汰使用頻率最低的緩存數(shù)據(jù)。與 LRU 不同,LFU 更關(guān)注數(shù)據(jù)的使用頻率,而非最近使用時間。
5. 緩存一致性雙寫模式:在更新數(shù)據(jù)庫的同時更新緩存,確保兩者數(shù)據(jù)一致。但要注意操作順序和可能出現(xiàn)的并發(fā)問題,例如先更新緩存再更新數(shù)據(jù)庫時,如果數(shù)據(jù)庫更新失敗,可能導(dǎo)致數(shù)據(jù)不一致。
失效模式:更新數(shù)據(jù)庫時,使關(guān)緩存失效,下次讀取時重新從數(shù)據(jù)庫加載數(shù)據(jù)并更新緩存。這種方式相對簡單,但可能會在緩存失效期間出現(xiàn)短暫的數(shù)據(jù)不一致。
在高性能服務(wù)架構(gòu)設(shè)計中,緩存是不可或缺的環(huán)節(jié)。在實際項目中,我們通常會將一些熱點數(shù)據(jù)存儲在Redis或Memcached等緩存中間件中,只有在緩存訪問未命中時才查詢數(shù)據(jù)庫。
在提高訪問速度的同時,還可以減輕數(shù)據(jù)庫的壓力。
為什么要使用本地緩存?
隨著不斷的發(fā)展,這個架構(gòu)也得到了完善。在某些場景下,僅僅使用Redis類的遠程緩存可能還不夠。需要進一步與本地緩存配合使用,比如Guava或者Caffeine,從而再次提高程序的響應(yīng)速度和服務(wù)性能。
由此,形成了以本地緩存作為一級緩存、遠程緩存作為二級緩存的二級緩存架構(gòu)。
總結(jié):
本地緩存基于本地環(huán)境的內(nèi)存,訪問速度非??臁τ谝恍┳兓l率不高、實時性要求不高的數(shù)據(jù),可以放在本地緩存中,以提高訪問速度。
使用本地緩存可以減少與Redis類的遠程緩存的數(shù)據(jù)交互,減少網(wǎng)絡(luò)I/O開銷,減少這個過程中網(wǎng)絡(luò)通信的耗時。
本地存儲的基本功能
它可以存儲、讀取和寫入。
原子操作(線程安全),例如ConcurrentHashMap。
可以設(shè)置緩存的最大限制。
超過最大限制有相應(yīng)的淘汰策略,如LRU、LFU。
統(tǒng)計監(jiān)控。
方案選擇
1.使用ConcurrentHashMap。
緩存的本質(zhì)是KV存儲在內(nèi)存中的數(shù)據(jù)結(jié)構(gòu),對應(yīng)JDK中的線程安全ConcurrentHashMap,但是要實現(xiàn)緩存,需要考慮消除、最大限制、消除緩存過期時間等功能。
優(yōu)點ConcurrentHashMap是實現(xiàn)簡單,不需要引入第三方包,所以比較適合一些簡單的業(yè)務(wù)場景。
缺點是如果需要更多的功能,需要定制開發(fā),成本會比較高,穩(wěn)定性和可靠性難以保證。
對于更復(fù)雜的場景,建議使用相對穩(wěn)定的開源工具。
2. 使用Guava緩存
Guava是Google團隊開源的一個Java核心增強庫。它包括集合、并發(fā)原語、緩存、IO、反射和其他工具箱。性能和穩(wěn)定性有保證,應(yīng)用廣泛。
Guava Cache 支持許多功能:
支持最大容量限制。
支持兩種過期刪除策略。
支持簡單的統(tǒng)計功能。 它是基于LRU算法實現(xiàn)的。





