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後,就通知每個應用的監聽者,重新整理本地快取。這種方式稍微有點難度,也不是特別可控。目前我參與的應用,本地快取資料的重新整理策略是自動失效。

統計命中率

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