1 緩存的本質
我們常常會講:“加了緩存,我們的系統就會更快” 。所謂的 “更快”,本質上做到了如下兩點:-
減小 CPU 消耗
將原來需要實時計算的內容提前算好、把一些公用的數據進行復用,這可以減少 CPU 消耗,從而提升響應性能。
-
減小 I/O 消耗
將原來對網絡、磁盤等較慢介質的讀寫訪問變為對內存等較快介質的訪問,從而提升響應性能。
2 本地緩存 JDK Map
JDK Map 經常用于緩存實現:-
HashMap
HashMap 是一種基于哈希表的集合類,它提供了快速的插入、查找和刪除操作。可以將鍵值對作為緩存項的存儲方式,將鍵作為緩存項的唯一標識符,值作為緩存項的內容。
-
ConcurrentHashMap
ConcurrentHashMap 是線程安全的 HashMap,它在多線程環境下可以保證高效的并發讀寫操作。
-
LinkedHashMap
LinkedHashMap 是一種有序的 HashMap ,它保留了元素插入的順序,可以按照插入順序或者訪問順序進行遍歷。
-
TreeMap
TreeMap 是一種基于紅黑樹的有序 Map,它可以按照鍵的順序進行遍歷。
-
紅包系統是高并發應用,快速將請求結果響應給前端,大大提升用戶體驗;
-
紅包活動數量并不多,就算全部放入到 Map 里也不會產生內存溢出的問題;
-
定時任務刷新緩存并不會影響紅包系統的業務。
3 本地緩存框架
雖然使用 JDK Map 能快捷構建緩存,但緩存的功能還是比較孱弱的。因為現實場景里,我們可能需要給緩存添加緩存統計、過期失效、淘汰策略等功能。于是,本地緩存框架應運而生。流行的 Java 緩存框架包括:Ehcache , Google Guava , Caffine Cache 。下圖展示了 Caffine 框架的使用示例。雖然本地緩存框架的功能很強大,但是本地緩存的缺陷依然明顯。1、高并發的場景,應用重啟之后,本地緩存就失效了,系統的負載就比較大,需要花較長的時間才能恢復;2、每個應用節點都會維護自己的單獨緩存,緩存同步比較頭疼。4 分布式緩存
分布式緩存是指將緩存數據分布在多臺機器上,以提高緩存容量和并發讀寫能力的緩存系統。分布式緩存通常由多臺機器組成一個集群,每臺機器上都運行著相同的緩存服務進程,緩存數據被均勻地分布在集群中的各個節點上。Redis 是分布式緩存的首選,甚至我們一提到緩存,很多后端工程師首先想到的就它。下圖是神州專車訂單的 Redis 集群架構 。將 Redis 集群拆分成四個分片,每個分片包含一主一從,主從可以切換。應用 A 根據不同的緩存 key 訪問不同的分片。與本地緩存相比,分布式緩存具有以下優點:1、容量和性能可擴展通過增加集群中的機器數量,可以擴展緩存的容量和并發讀寫能力。同時,緩存數據對于應用來講都是共享的。2、高可用性由于數據被分布在多臺機器上,即使其中一臺機器故障,緩存服務也能繼續提供服務。但是分布式緩存的缺點同樣不容忽視。1、網絡延遲分布式緩存通常需要通過網絡通信來進行數據讀寫,可能會出現網絡延遲等問題,相對于本地緩存而言,響應時間更長。2、復雜性分布式緩存需要考慮序列化、數據分片、緩存大小等問題,相對于本地緩存而言更加復雜。筆者曾經也認為無腦上緩存 ,系統就一定更快,但直到一次事故,對于分布式緩存的觀念才徹底改變。2014 年,同事開發了比分直播的系統,所有的請求都是從分布式緩存 Memcached 中獲取后直接響應。常規情況下,從緩存中查詢數據非常快,但在線用戶稍微多一點,整個系統就會特別卡。通過 jstat 命令發現 GC 頻率極高,幾次請求就將新生代占滿了,而且 CPU 的消耗都在 GC 線程上。初步判斷是緩存值過大導致的,果不其然,緩存大小在 300k 到 500k 左右。解決過程還比較波折,分為兩個步驟:-
修改新生代大小,從原來的 2G 修改成 4G,并精簡緩存數據大小 (從平均 300k 左右降為 80k 左右);
-
把緩存拆成兩個部分,第一部分是全量數據,第二部分是增量數據(數據量很?。?。頁面第一次請求拉取全量數據,當比分有變化的時候,通過 websocket 推送增量數據。
5 多級緩存
開源中國網站最開始完全是用本地緩存框架 Ehcache 。后來隨著訪問量的激增,出現了一個可怕的問題:“因為 Java 程序更新很頻繁,每次更新的時候都要重啟。一旦重啟后,整個 Ehcache 緩存里的數據都被清掉。重啟后若大量訪問進來的話,開源中國的數據庫基本上很快就會崩掉”。于是,開源中國開發了多級緩存框架J2Cache,使用了多級緩存Ehcache + Redis。多級緩存有如下優勢:-
離用戶越近,速度越快;
-
減少分布式緩存查詢頻率,降低序列化和反序列化的 CPU 消耗;
-
大幅度減少網絡 IO 以及帶寬消耗。
6 沒有銀彈
沒有銀彈是 Fred Brooks 在 1987 年所發表的一篇關于軟件工程的經典論文。論文強調真正的銀彈并不存在,而所謂的銀彈則是指沒有任何一項技術或方法可以能讓軟件工程的生產力在十年內提高十倍。通俗來講:在技術領域中沒有一種通用的解決方案可以解決所有問題。技術本質上是為了解決問題而存在的,每個問題都有其獨特的環境和限制條件,沒有一種通用的技術或工具可以完美地解決所有問題。雖然技術不斷發展和進步,但是對于復雜的問題,仍需要結合多種技術和方法,進行系統性的思考和綜合性的解決方案設計,才能得到最優解決方案。回到文章開頭的問題 ,如何說服技術老大用 Redis ?假如應用就是一個單體應用,緩存可以不共享,通過定時任務刷新緩存對業務沒有影響,而且本地內存可以 Hold 住緩存的對象大小,那么你的技術老大的方案沒有問題。假如應用業務比較復雜,需要使用緩存提升系統的性能,同時分布式緩存共享的特性對于研發來講開發更加快捷,Redis 確實是個不錯的選擇,可以從研發成本、代碼維護、人力模型等多個角度和技術老大提出自己的觀點。總而言之,在技術領域中,沒有銀彈。我們需要不斷探索和研究新的技術,但同時也需要認識到技術的局限性,不盲目追求所謂的 “銀彈”,而是結合具體問題和需求,選擇最適合的解決方案。
-
框架
+關注
關注
0文章
403瀏覽量
17476 -
磁盤
+關注
關注
1文章
375瀏覽量
25201 -
Redis
+關注
關注
0文章
374瀏覽量
10871
發布評論請先 登錄
相關推薦
評論