「京東開濤」應用多級緩存模式支撐海量讀服務

轉載:應用多級緩存模式支撐海量讀服務

? ? ? 緩存技術是一個老生常談的問題,但是它也是解決性能問題的利器,一把瑞士軍刀;而且在各種面試過程中或多或少會被問及一些緩存相關的問題,如緩存算法、熱點數據與更新緩存、更新緩存與原子性、緩存崩潰與快速恢復等各種與緩存相關的問題。而這些問題中有些問題又是與場景相關,因此如何合理應用緩存來解決問題也是一個選擇題。本文所有內容是跟讀服務緩存相關,不會涉及寫服務數據的緩存。本文也不考慮內容型應用前置的CDN架構。本文也不會涉及緩存數據結構優化、緩存空間利用率跟業務數據相關的細節問題,主要從架構和提升命中率等層面來探討緩存方案。本文將基于多級緩存模式來介紹下應用緩存時需要注意的問題和一些解決方案,其中一些方案已經實現,而有一些也是想使用來解決痛點問題。

1、多級緩存介紹

所謂多級緩存,即在整個系統架構的不同系統層級進行數據緩存,以提升訪問效率,這也是應用最廣的方案之一。我們應用的整體架構如下圖所示:

整體流程如上圖所示:

1、首先接入Nginx將請求負載均衡到應用Nginx,此處常用的負載均衡算法是輪詢或者一致性哈希,輪詢可以使服務器的請求更加均衡,而一致性哈希可以提升應用Nginx的緩存命中率;后續負載均衡和緩存算法部分我們再細聊;

2、接著應用Nginx讀取本地緩存(本地緩存可以使用Lua Shared Dict、Nginx Proxy Cache(磁盤/內存)、Local Redis實現),如果本地緩存命中則直接返回,使用應用Nginx本地緩存可以提升整體的吞吐量,降低后端的壓力,尤其應對熱點問題非常有效;為什么要使用應用Nginx本地緩存我們將在熱點數據與緩存失效部分細聊;

3、如果Nginx本地緩存沒命中,則會讀取相應的分布式緩存(如Redis緩存,另外可以考慮使用主從架構來提升性能和吞吐量),如果分布式緩存命中則直接返回相應數據(并回寫到Nginx本地緩存);

4、如果分布式緩存也沒有命中,則會回源到Tomcat集群,在回源到Tomcat集群時也可以使用輪詢和一致性哈希作為負載均衡算法;

5、在Tomcat應用中,首先讀取本地堆緩存,如果有則直接返回(并會寫到主Redis集群),為什么要加一層本地堆緩存將在緩存崩潰與快速修復部分細聊;

6、作為可選部分,如果步驟4沒有命中可以再嘗試一次讀主Redis集群操作,目的是防止當從有問題時的流量沖擊;

7、如果所有緩存都沒有命中只能查詢DB或相關服務獲取相關數據并返回;

8、步驟7返回的數據異步寫到主Redis集群,此處可能多個Tomcat實例同時寫主Redis集群,可能造成數據錯亂,如何解決該問題將在更新緩存與原子性部分細聊。

整體分了三部分緩存:應用Nginx本地緩存、分布式緩存、Tomcat堆緩存,每一層緩存都用來解決相關的問題,如應用Nginx本地緩存用來解決熱點緩存問題,分布式緩存用來減少訪問回源率、Tomcat堆緩存用于防止相關緩存失效/崩潰之后的沖擊。

雖然就是加緩存,但是怎么加,怎么用細想下來還是有很多問題需要權衡和考量的,接下來部分我們就詳細來討論一些緩存相關的問題。

2、如何緩存數據

2.1、過期與不過期

對于緩存的數據我們可以考慮不過期緩存和帶過期時間緩存;什么場景應該選擇哪種模式需要根據業務和數據量等因素來決定。

不過期緩存場景一般思路如下圖所示:

如上圖所示,首先寫數據庫,如果成功則寫緩存。這種機制存在一些問題:

1、事務在提交時失敗則寫緩存是不會回滾的造成DB和緩存數據不一致;

2、假設多個人并發寫緩存可能出現臟數據的;

3、同步寫對性能有一定的影響,異步寫存在丟數據的風險。

如果對緩存數據一致性要求不是那么高,數據量也不是很大,可以考慮定期全量同步緩存。

為解決以上問題可以考慮使用消息機制,如下圖所示:

1、把寫緩存改成寫消息,通過消息通知數據變更;

2、同步緩存系統會訂閱消息,并根據消息進行更新緩存;

3、數據一致性可以采用:消息體只包括ID、然后查庫獲取最新版本數據;通過時間戳和內容摘要機制(MD5)進行緩存更新;

4、如上方法也不能保證消息不丟失,可以采用:應用在本地記錄更新日志,當消息丟失了回放更新日志;或者采用數據庫binlog,采用如canal訂閱binlog進行緩存更新。

對于長尾訪問的數據、大多數數據訪問頻率都很高的場景、緩存空間足夠都可以考慮不過期緩存,比如用戶、分類、商品、價格、訂單等,當緩存滿了可以考慮LRU機制驅逐老的緩存數據。

過期緩存機制,即采用懶加載,一般用于緩存別的系統的數據(無法訂閱變更消息、或者成本很高)、緩存空間有限、低頻熱點緩存等場景;常見步驟是:首先讀取緩存如果不命中則查詢數據,然后異步寫入緩存并設置過期時間,下次讀取將命中緩存。熱點數據經常使用過期緩存,即在應用系統上緩存比較短的時間。這種緩存可能存在一段時間的數據不一致情況,需要根據場景來決定如何設置過期時間。如庫存數據可以在前端應用上緩存幾秒鐘,短時間的不一致時可以忍受的。

2.2、維度化緩存與增量緩存

對于電商系統,一個商品可能拆成如:基礎屬性、圖片列表、上下架、規格參數、商品介紹等;如果商品變更了要把這些數據都更新一遍那么整個更新成本很高:接口調用量和帶寬;因此最好將數據進行維度化并增量更新(只更新變的部分)。尤其如上下架這種只是一個狀態變更,但是每天頻繁調用的,維度化后能減少服務很大的壓力。

3、分布式緩存與應用負載均衡

3.1、緩存分布式

此處說的分布式緩存一般采用分片實現,即將數據分散到多個實例或多臺服務器。算法一般采用取模和一致性哈希。如之前說的做不過期緩存機制可以考慮取模機制,擴容時一般是新建一個集群;而對于可以丟失的緩存數據可以考慮一致性哈希,即使其中一個實例出問題只是丟一小部分,對于分片實現可以考慮客戶端實現,或者使用如Twemproxy中間件進行代理(分片對客戶端是透明的)。如果使用Redis可以考慮使用redis-cluster分布式集群方案。

3.2、應用負載均衡

應用負載均衡一般采用輪詢和一致性哈希,一致性哈希可以根據應用請求的URL或者URL參數將相同的請求轉發到同一個節點;而輪詢即將請求均勻的轉發到每個服務器;如下圖所示:

整體流程:

1、首先請求進入接入層Nginx;

2、根據負載均衡算法將請求轉發給應用Nginx;

3、如果應用Nginx本地緩存命中,則直接返回數據,否則讀取分布式緩存或者回源到Tomcat。

輪詢的優點:到應用Nginx的請求更加均勻,使得每個服務器的負載基本均衡;輪詢的缺點:隨著應用Nginx服務器的增加,緩存的命中率會下降,比如原來10臺服務器命中率為90%,再加10臺服務器將可能降低到45%;而這種方式不會因為熱點問題導致其中某一臺服務器負載過重。

一致性哈希的優點:相同請求都會轉發到同一臺服務器,命中率不會因為增加服務器而降低;一致性哈希的缺點:因為相同的請求會轉發到同一臺服務器,因此可能造成某臺服務器負載過重,甚至因為請求太多導致服務出現問題。

解決辦法是根據實際情況動態選擇使用哪種算法:

1、負載較低時使用一致性哈希;

2、熱點請求降級一致性哈希為輪詢;

3、將熱點數據推送到接入層Nginx,直接響應給用戶。

4、熱點數據與更新緩存

熱點數據會造成服務器壓力過大,導致服務器性能、吞吐量、帶寬達到極限,出現響應慢或者拒絕服務的情況,這肯定是不允許的。可以從如下幾個方案去解決。

4.1、單機全量緩存+主從

如上圖所示,所有緩存都存儲在應用本機,回源之后會把數據更新到主Redis集群,然后通過主從復制到其他從Redis集群。緩存的更新可以采用懶加載或者訂閱消息進行同步。

4.2、分布式緩存+應用本地熱點

對于分布式緩存,我們需要在Nginx+Lua應用中進行應用緩存來減少Redis集群的訪問沖擊;即首先查詢應用本地緩存,如果命中則直接緩存,如果沒有命中則接著查詢Redis集群、回源到Tomcat;然后將數據緩存到應用本地。

此處到應用Nginx的負載機制采用:正常情況采用一致性哈希,如果某個請求類型訪問量突破了一定的閥值,則自動降級為輪詢機制。另外對于一些秒殺活動之類的熱點我們是可以提前知道的,可以把相關數據預先推送到應用Nginx并將負載均衡機制降級為輪詢。

另外可以考慮建立實時熱點發現系統來發現熱點:

1、接入Nginx將請求轉發給應用Nginx;

2、應用Nginx首先讀取本地緩存;如果命中直接返回,不命中會讀取分布式緩存、回源到Tomcat進行處理;

3、應用Nginx會將請求上報給實時熱點發現系統,如使用UDP直接上報請求、或者將請求寫到本地kafka、或者使用flume訂閱本地nginx日志;上報給實時熱點發現系統后,它將進行統計熱點(可以考慮storm實時計算);

4、根據設置的閥值將熱點數據推送到應用Nginx本地緩存。

因為做了本地緩存,因此對于數據一致性需要我們去考慮,即何時失效或更新緩存:

1、如果可以訂閱數據變更消息,那么可以訂閱變更消息進行緩存更新;

2、如果無法訂閱消息或者訂閱消息成本比較高,并且對短暫的數據一致性要求不嚴格(比如在商品詳情頁看到的庫存,可以短暫的不一致,只要保證下單時一致即可),那么可以設置合理的過期時間,過期后再查詢新的數據;

3、如果是秒殺之類的,可以訂閱活動開啟消息,將相關數據提前推送到前端應用,并將負載均衡機制降級為輪詢;

4、建立實時熱點發現系統來對熱點進行統一推送和更新。

5、更新緩存與原子性

正如之前說的如果多個應用同時操作一份數據很可能造成緩存數據是臟數據,解決辦法:

1.1、更新數據時使用更新時間戳或者版本對比,如果使用Redis可以利用其單線程機制進行原子化更新;

1.2、使用如canal訂閱數據庫binlog;

2.1、將更新請求按照相應的規則分散到多個隊列,然后每個隊列的進行單線程更新,更新時拉取最新的數據保存;

2.2、分布式鎖,更新之前獲取相關的鎖。

6、緩存崩潰與快速修復

6.1、取模

對于取模機制如果其中一個實例壞了,如果摘除此實例將導致大量緩存不命中,瞬間大流量可能導致后端DB/服務出現問題。對于這種情況可以采用主從機制來避免實例壞了的問題,即其中一個實例壞了可以那從/主頂上來。但是取模機制下如果增加一個節點將導致大量緩存不命中,一般是建立另一個集群,然后把數據遷移到新集群,然后把流量遷移過去。

6.2、一致性哈希

對于一致性哈希機制如果其中一個實例壞了,如果摘除此實例將只影響一致性哈希環上的部分緩存不命中,不會導致瞬間大量回源到后端DB/服務,但是也會產生一些影響。

另外也可能因為一些誤操作導致整個緩存集群出現了問題,如何快速恢復呢?

6.3、快速恢復

如果出現之前說到的一些問題,可以考慮如下方案:

1、主從機制,做好冗余,即其中一部分不可用,將對等的部分補上去;

2、如果因為緩存導致應用可用性已經下降可以考慮:1、部分用戶降級,然后慢慢減少降級量;2、后臺通過Worker預熱緩存數據。

也就是如果整個緩存集群壞了,而且沒有備份,那么只能去慢慢將緩存重建;為了讓部分用戶還是可用的,可以根據系統承受能力,通過降級方案讓一部分用戶先用起來,將這些用戶相關的緩存重建;另外通過后臺Worker進行緩存數據的預熱。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,908評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,324評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,018評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,675評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,417評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,783評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,779評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,960評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,522評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,267評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,471評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,009評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,698評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,099評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,386評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,204評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,436評論 2 378

推薦閱讀更多精彩內容