程序員修神之路--聽說你會緩存?
- 緩存是什么?(沒聽說過你可以走了)
- 哪些場景需要用到緩存呢?
- 緩存可以分類嗎?
- 緩存的實現(xiàn)方式有哪些?
緩存
緩存也被稱為Cache,本質(zhì)上是數(shù)據(jù)交換的一段緩沖區(qū),也可以稱為一種存儲數(shù)據(jù)的組件,緩存主要用于減小數(shù)據(jù)交換雙方速度不匹配的問題。
緩存在計算機世界里是一個常見并且不可忽視的一個重要因素,它幾乎遍布于你所知的各個領(lǐng)域。例如cpu的一級緩存,二級緩存;瀏覽器的緩存等。我們在使用緩存的時候要清除的認識到緩存的數(shù)據(jù)是有有效期的,也就是說可能隨時會消失。有的同學(xué)會說了,類似redis這些組件都提供了數(shù)據(jù)持久化的功能,這樣數(shù)據(jù)就不會消失了。至于這個問題其實我想說兩點:
- 當組件提供了持久化功能的時候,必然會發(fā)生磁盤的IO操作,而磁盤IO的操作必然會大大降低緩存組件的性能,那緩存的價值還有嗎?
- 緩存的數(shù)據(jù)在時間定義上是一種臨時性的數(shù)據(jù),如果做了持久化,這種臨時性的意義就不存在了,而且還占用了磁盤的存儲空間
緩存最常見的存儲介質(zhì)是內(nèi)存,但這并不意味只有內(nèi)存可以存儲緩存數(shù)據(jù),這也是初學(xué)者經(jīng)常會犯的錯誤。緩存的作用是提供高速的讀寫功能,所以如果你的設(shè)備足夠快,理論上都可以作為緩存使用,比如現(xiàn)在的SSD,在一些性能不太嚴格和敏感的場景下就可以作為存儲緩存數(shù)據(jù)的介質(zhì),至于計算機的各種硬件之間的速度差距可以參考之前的文章:
高并發(fā)下為什么更喜歡進程內(nèi)緩存
緩存應(yīng)用場景
“從理論上來說,任何需要提高訪問速度的環(huán)節(jié)都可以加入緩存
但是系統(tǒng)加入緩存模塊會在一定程度上增加系統(tǒng)的復(fù)雜度,所以在是否引入緩存的問題上,需要根據(jù)業(yè)務(wù)場景來平衡。一般符合以下幾種特征的數(shù)據(jù)可以考慮引入緩存模塊:
數(shù)據(jù)很少變動
這類數(shù)據(jù)最適合緩存的應(yīng)用場景,因為它基本不涉及到負責的緩存更新操作,所以只要將其加載到緩存中即可。最具有代表性的像網(wǎng)站用到的js,css等這些靜態(tài)資源,用戶登錄之后生成的session信息等。
說到數(shù)據(jù)很少變動,不得不提CDN這種服務(wù)了,很多大型網(wǎng)站都會利用CDN來加速一些不變資源的訪問速度,比如一些圖片,視頻等。由于用戶訪問這些資源的本源需要跨越多個主干網(wǎng),在速度上較慢,而CDN恰恰彌補了這個缺陷,所以這里也可以把CDN看成是一種緩存的服務(wù)。
熱點數(shù)據(jù)
這種數(shù)據(jù)是我們平時開發(fā)中要加緩存的主要原因數(shù)據(jù),最有可能導(dǎo)致系統(tǒng)癱瘓的也是這種數(shù)據(jù)。它最大的特點是發(fā)生時間不確定,流量峰值不確定。大家可能還依稀記得微博因為兩個明星出軌而掛掉的事件,雖然微博的系統(tǒng)架構(gòu)后來經(jīng)過改造可以同時抗住N個明星出軌,但是在不確定這個因素上依然無能為力。
熱點數(shù)據(jù)的緩存并不容易設(shè)計,因為它帶有單點屬性,什么意思呢?假設(shè)我們的緩存服務(wù)器有100個節(jié)點,這個時候發(fā)生了某個熱點新聞,而這個熱點新聞的緩存在0號節(jié)點,大量的請求會被路由到0號節(jié)點,很有可能會導(dǎo)致0號節(jié)點垮掉,如果0號節(jié)點垮掉,基于故障轉(zhuǎn)移策略,流量瞬間會轉(zhuǎn)移到另外一個節(jié)點,然后這個節(jié)點會垮掉,以此類推.....緩存雖然提高了系統(tǒng)的整體吞吐量,但是在應(yīng)對有針對性的流量高峰的時候需要單獨針對。這其實也是分布式系統(tǒng)要解決的問題,既然一個節(jié)點扛不住流量高峰,系統(tǒng)可以設(shè)計多個節(jié)點一起來抗,至于以上的熱點數(shù)據(jù)場景,最簡單粗暴的方式就是緩存副本,一份緩存數(shù)據(jù)會存在多份副本,類似于MySQL的讀寫分離方案,多份副本同時提供讀取操作。
耗時操作
某些計算代價或者獲取代價很大的數(shù)據(jù)在特定的條件下也適合進行緩存。為什么要加特定條件呢?如果系統(tǒng)對這些數(shù)據(jù)的一致性有著嚴格的要求,而且會頻繁的變動,雖然獲取數(shù)據(jù)代價比較大,但是你也要充分考慮緩存帶來的副作用。像我們最常用的報表服務(wù),一般生成報表都比較耗時,如果報表的數(shù)據(jù)是相對穩(wěn)定的,那我們就可以考慮用緩存來提高系統(tǒng)的性能。
緩存的淘汰
存儲緩存的設(shè)備限制了緩存是有大小限制的,如果以16G內(nèi)存來存儲緩存,那緩存的上限理論上就是16G(但是實際上要小的多),而且緩存帶有時效性,所以當要緩存的數(shù)據(jù)大于介質(zhì)容量的時候就需要一種淘汰數(shù)據(jù)的策略來保證新數(shù)據(jù)能正常被緩存。
最好的淘汰策略就是把系統(tǒng)不用的數(shù)據(jù)淘汰出去,但是什么數(shù)據(jù)是無用數(shù)據(jù),這是策略的難點所在,基于用戶行為的不確定性,這種數(shù)據(jù)所以很難用程序去預(yù)測。鑒于系統(tǒng)的常規(guī)理論,現(xiàn)在主流的有以下幾種淘汰策略:
- LFU(Least Frequently Used):緩存系統(tǒng)會記住每條緩存數(shù)據(jù)被訪問的頻率,會優(yōu)先淘汰最不常用的數(shù)據(jù)。
- LRU(Least Recently Used):緩存系統(tǒng)會記住每條數(shù)據(jù)最后的訪問時間,會優(yōu)先淘汰長時間未被訪問的數(shù)據(jù)
- ARC(Adaptive Replacement Cache):這個緩存算法同時跟蹤記錄LFU和LRU,以及驅(qū)逐緩存條目,來獲得可用緩存的最佳使用,它被認為是性能最好的緩存算法之一,介于LRU和LFU之間,能夠記憶效果和自調(diào),當然開發(fā)肯定會比較復(fù)雜。
- FIFO:基于隊列的原理的淘汰算法,先進先出。這種算法比較簡單,現(xiàn)實中使用比較少是因為這種業(yè)務(wù)場景比較少。
緩存實現(xiàn)方式
系統(tǒng)中實現(xiàn)緩存的方式大體上可以分為兩種:
進程內(nèi)緩存
進程內(nèi)緩存是指緩存和應(yīng)用程序在同一個進程內(nèi),在獲取緩存數(shù)據(jù)的時候不需要跨越網(wǎng)絡(luò),所以進程內(nèi)緩存是訪問速度最快的一種方式。
進程內(nèi)緩存一般用在單機或者小型系統(tǒng)中,但是,在整體架構(gòu)實現(xiàn)了一致性的前提下,也可用于大型系統(tǒng),什么意思呢?舉個栗子:在多個服務(wù)器節(jié)點的情況下,假如用戶A的信息緩存在0號節(jié)點,如果有一種機制能保證用戶A的所有請求都只會到達0號節(jié)點,這個時候利用進程內(nèi)緩存就完全沒有問題。
進程外緩存
顧名思義,進程外緩存的意思是緩存數(shù)據(jù)和應(yīng)用程序是隔離的,位于不同的進程內(nèi)。當然這里又可以把進程外緩存劃分為單機版和分布式版本,單機版本這里就不多說了,會存在單機故障問題。
進程外的分布式版本通常被稱為分布式緩存,是基于分布式理論的一種架構(gòu)模式。它突破了單機緩存的容量限制和單機故障問題,雖然在訪問速度上比進程內(nèi)緩存要慢很多,但是相比較磁盤IO操作要快的多,所以現(xiàn)在很多大型系統(tǒng)都喜歡用分布式緩存來提高性能。像用的最多的Redis在3.0版本之后就提供了集群方案。
寫在最后
在面對緩存帶給系統(tǒng)的優(yōu)勢之后,也要注意到緩存也會有一些不足。
- 緩存和數(shù)據(jù)源的一致性問題
- 緩存命中問題
- 緩存的雪崩穿透問題
- 緩存的并發(fā)競爭問題
- 緩存適合讀多寫少的系統(tǒng)
- 引入緩存組件會給系統(tǒng)設(shè)計帶來一定的復(fù)雜度
- 緩存會加大運維的成功以及排查bug的成本
雖然緩存帶來了不少問題,但是相比較緩存帶給系統(tǒng)性能的提升是毋庸置疑的。我們在設(shè)計一個高并發(fā)系統(tǒng)的時候,緩存已經(jīng)成為了一種必備設(shè)計,在正確設(shè)計了緩存各種策略之后,才能最大發(fā)揮緩存的優(yōu)勢。
本文轉(zhuǎn)載自微信公眾號「架構(gòu)師修行之路」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系架構(gòu)師修行之路公眾號。