1. 程式人生 > >照顧好應用的快取-應付大流量

照顧好應用的快取-應付大流量

概述

為了提升系統的響應速度,通常會系統中使用快取,例如:中央快取,本地快取等。但是使用快取有好有壞,壞處是,如果快取資料是舊的,那麼應用輸出的資料便是錯誤的資料,可能造成嚴重的影響。本文介紹一些讓快取保持新鮮以及使用快取的一些技巧

利用MQ實時重新整理快取

一旦db資料發生變化,則可以傳送一條mq訊息,通知消費者,資訊有變動,消費者感知到後,立刻呼叫重新整理快取的介面,把資料涮新到中央快取裡。這裡有三個點要注意一下:
1、如果快取中的資料存在依賴關係,那麼必須級聯的進行重新整理,不然會出現,資料在快取中不一致。
2、MQ可能掛掉,得使用其他輔助方案來重新整理中央快取。比如說,定時任務全量刷,增量刷。


3、如果應用中Mysql使用一主多從,那麼一定要注意主從延遲的問題,如下圖:
這裡寫圖片描述

一旦訊息消費者判斷資料已經從master庫同步到slave1的時候,就開始呼叫呼叫刷快取的介面,重新整理快取的應用這個時候讀取的是slave2,那麼可能資料還未從master同步到slave2,那麼這個時候讀取的資料其實還是舊的,刷到快取的資料也是舊的。

基於這種情況,有一種辦法,就是保證訊息消費者和重新整理快取的應用讀取的db必須是同一個。這樣即使出現主從延遲,也沒問題。

備註:一主一從不會出現這種情況。

全量刷中央快取

可以使用一個job,每天凌晨把所有熱點資料重新整理到中央快取裡。

增量刷中央快取

全量刷,有個缺點,就是得等到晚上凌晨,資料才能被刷到中央快取裡。如果想讓資料快點刷到中央快取裡,可以使用一個增量的job,每隔兩個小時,把最新的熱點資料刷到快取裡。使用增量job也注意一個問題,避免高峰期刷。比如說,你的應用是早上十點,晚上八點流量最大,那麼這個時候,就不要去刷快取了,給應用多留一些資源,應付大流量

使用哨兵機制

有些情況下,中央快取也會快取外部其他系統的資料,如果這些資料訪問比較頻繁,那麼可以使用哨兵機制,當這些資料快要過期的時候,主動呼叫外部系統,把資料重新整理到中央快取裡。個人認為這是一個相當不錯的技巧。因為呼叫一次外部系統的介面,開銷還是很大的,而且也需要時間,如果能提前呼叫的話,那麼將大大提高本系統介面的響應速度。

使用本地快取

使用本地快取的時候,有幾點要注意
1、本地快取的選型,到底是使用堆外快取還是堆內快取。
堆外快取有:
OHC、ehcache、OpenHFT Chronicle Map 2、OpenHFT Chronicle Map 3。
堆內的有:ConcurrentHashMap、Google Loading Cache
快取的資料量比較大的話,使用堆外的,量小的,使用堆內的。

2、注意同一個key的防穿透,就是說,有相同的key併發的訪問到本地快取,那麼應該只是讓其中一個key穿透過去,其他的key只能等待,防止大量的key穿透過去,對中央快取或者db造成壓力。

本地快取重新整理策略

1、自動過期。這種方式非常的簡單,就是設定本地快取資料的失效時間,比如說,設定5分鐘,5分鐘後自動失效,請求穿透過去。
如果使用資料過期這種方式的話,要注意,當系統有大流量的時候,要延遲本地快取資料的失效時間,比如說設定20分鐘失效,避免穿透的資料太多

2、釋出訂閱的方式,在每個應用中部署一個監聽者,寫資料的一方,一旦把資料寫到db後,就通知每個應用的監聽者,重新整理本地快取。這種方式稍微有點難度,也不是特別可控。目前我參與的應用,本地快取資料的重新整理策略是自動失效。

做好快取開關(重要)

無論是中央快取還是本地快取,都要設定一個開關:是否從快取讀取資料
因為由於資料原因或者程式的bug,可能出現快取資料是不正確的,這個時候外部系統發請求過來的時候,
拿到資料就是錯的。那麼我們可以先利用快取開關,讓請求直接穿透,獲取正確資料,這樣後續的請求拿到的資料就是對的了。然後同時使用快取重新整理工具,把不正確的資料重新整理掉。

特別是,快取中有很多資料是不對的時候,手動人工重新整理快取可能需要比較長的時間,為了保證後續請求能拿到正確的資料,必須使用快取開關。

一定要有手動重新整理快取的工具

如果出現快取資料不正確的情況下,而且資料量不大,那麼直接使用快取重新整理工具重新整理即可。

統計命中率

為了能知道快取的命中率,分析快取框架的效果,最好用程式輸出快取的命中率。如果快取命中不高的話,就得分析原因了。可能是演算法有問題,快取key的維度有問題等等。