聽說你會緩存?

{"type":"doc","content":[{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"靈魂拷問"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存是什麼?(沒聽說過你可以走了)"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"哪些場景需要用到緩存呢?"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存可以分類嗎?"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存的實現方式有哪些?"}]}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"link","attrs":{"href":"#緩存","title":null}},{"type":"text","text":"緩存"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存也被稱爲Cache,本質上是數據交換的一段緩衝區,也可以稱爲一種存儲數據的組件,緩存主要用於減小數據交換雙方速度不匹配的問題。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存在計算機世界裏是一個常見並且不可忽視的一個重要因素,它幾乎遍佈於你所知的各個領域。例如cpu的一級緩存,二級緩存;瀏覽器的緩存等。我們在使用緩存的時候要清除的認識到緩存的數據是有有效期的,也就是說可能隨時會消失。有的同學會說了,類似redis這些組件都提供了數據持久化的功能,這樣數據就不會消失了。至於這個問題其實我想說兩點:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當組件提供了持久化功能的時候,必然會發生磁盤的IO操作,而磁盤IO的操作必然會大大降低緩存組件的性能,那緩存的價值還有嗎?"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存的數據在時間定義上是一種臨時性的數據,如果做了持久化,這種臨時性的意義就不存在了,而且還佔用了磁盤的存儲空間"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存最常見的存儲介質是內存,但這並不意味只有內存可以存儲緩存數據,這也是初學者經常會犯的錯誤。緩存的作用是提供高速的讀寫功能,所以如果你的設備足夠快,理論上都可以作爲緩存使用,比如現在的SSD,在一些性能不太嚴格和敏感的場景下就可以作爲存儲緩存數據的介質,至於計算機的各種硬件之間的速度差距可以參考之前的文章:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s/6YL3SnSriKEnpCyB5qkk0g","title":null},"content":[{"type":"text","text":"高併發下爲什麼更喜歡進程內緩存"}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"link","attrs":{"href":"#緩存應用場景","title":null}},{"type":"text","text":"緩存應用場景"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從理論上來說,任何需要提高訪問速度的環節都可以加入緩存"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但是系統加入緩存模塊會在一定程度上增加系統的複雜度,所以在是否引入緩存的問題上,需要根據業務場景來平衡。一般符合以下幾種特徵的數據可以考慮引入緩存模塊:"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"link","attrs":{"href":"#數據很少變動","title":null}},{"type":"text","text":"數據很少變動"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這類數據最適合緩存的應用場景,因爲它基本不涉及到負責的緩存更新操作,所以只要將其加載到緩存中即可。最具有代表性的像網站用到的js,css等這些靜態資源,用戶登錄之後生成的session信息等。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"說到數據很少變動,不得不提CDN這種服務了,很多大型網站都會利用CDN來加速一些不變資源的訪問速度,比如一些圖片,視頻等。由於用戶訪問這些資源的本源需要跨越多個主幹網,在速度上較慢,而CDN恰恰彌補了這個缺陷,所以這裏也可以把CDN看成是一種緩存的服務。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"link","attrs":{"href":"#熱點數據","title":null}},{"type":"text","text":"熱點數據"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這種數據是我們平時開發中要加緩存的主要原因數據,最有可能導致系統癱瘓的也是這種數據。它最大的特點是發生時間不確定,流量峯值不確定。大家可能還依稀記得微博因爲兩個明星出軌而掛掉的事件,雖然微博的系統架構後來經過改造可以同時抗住N個明星出軌,但是在不確定這個因素上依然無能爲力。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"熱點數據的緩存並不容易設計,因爲它帶有單點屬性,什麼意思呢?假設我們的緩存服務器有100個節點,這個時候發生了某個熱點新聞,而這個熱點新聞的緩存在0號節點,大量的請求會被路由到0號節點,很有可能會導致0號節點垮掉,如果0號節點垮掉,基於故障轉移策略,流量瞬間會轉移到另外一個節點,然後這個節點會垮掉,以此類推.....緩存雖然提高了系統的整體吞吐量,但是在應對有針對性的流量高峯的時候需要單獨針對。這其實也是分佈式系統要解決的問題,既然一個節點扛不住流量高峯,系統可以設計多個節點一起來抗,至於以上的熱點數據場景,最簡單粗暴的方式就是緩存副本,一份緩存數據會存在多份副本,類似於MySQL的讀寫分離方案,多份副本同時提供讀取操作。除此之外,這種場景下我推薦使用進程內緩存代替分佈式緩存,因爲進程內緩存在訪問速度上要比需要跨越網絡的分佈式緩存要快很多,具體可以查看之前的推文:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s/6YL3SnSriKEnpCyB5qkk0g","title":null},"content":[{"type":"text","text":"高併發下爲什麼更喜歡進程內緩存"}]}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"link","attrs":{"href":"#耗時操作","title":null}},{"type":"text","text":"耗時操作"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"某些計算代價或者獲取代價很大的數據在特定的條件下也適合進行緩存。爲什麼要加特定條件呢?如果系統對這些數據的一致性有着嚴格的要求,而且會頻繁的變動,雖然獲取數據代價比較大,但是你也要充分考慮緩存帶來的副作用。像我們最常用的報表服務,一般生成報表都比較耗時,如果報表的數據是相對穩定的,那我們就可以考慮用緩存來提高系統的性能。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"link","attrs":{"href":"#緩存的淘汰","title":null}},{"type":"text","text":"緩存的淘汰"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"存儲緩存的設備限制了緩存是有大小限制的,如果以16G內存來存儲緩存,那緩存的上限理論上就是16G(但是實際上要小的多),而且緩存帶有時效性,所以當要緩存的數據大於介質容量的時候就需要一種淘汰數據的策略來保證新數據能正常被緩存。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最好的淘汰策略就是把系統不用的數據淘汰出去,但是什麼數據是無用數據,這是策略的難點所在,基於用戶行爲的不確定性,這種數據所以很難用程序去預測。鑑於系統的常規理論,現在主流的有以下幾種淘汰策略:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"LFU(Least Frequently Used):緩存系統會記住每條緩存數據被訪問的頻率,會優先淘汰最不常用的數據。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"LRU(Least Recently Used):緩存系統會記住每條數據最後的訪問時間,會優先淘汰長時間未被訪問的數據"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ARC(Adaptive Replacement Cache):這個緩存算法同時跟蹤記錄LFU和LRU,以及驅逐緩存條目,來獲得可用緩存的最佳使用,它被認爲是性能最好的緩存算法之一,介於LRU和LFU之間,能夠記憶效果和自調,當然開發肯定會比較複雜。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"FIFO:基於隊列的原理的淘汰算法,先進先出。這種算法比較簡單,現實中使用比較少是因爲這種業務場景比較少。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"link","attrs":{"href":"#緩存實現方式","title":null}},{"type":"text","text":"緩存實現方式"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"系統中實現緩存的方式大體上可以分爲兩種:"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"link","attrs":{"href":"#進程內緩存","title":null}},{"type":"text","text":"進程內緩存"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"進程內緩存是指緩存和應用程序在同一個進程內,在獲取緩存數據的時候不需要跨越網絡,所以進程內緩存是訪問速度最快的一種方式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"進程內緩存一般用在單機或者小型系統中,但是,在整體架構實現了一致性的前提下,也可用於大型系統,什麼意思呢?舉個栗子:在多個服務器節點的情況下,假如用戶A的信息緩存在0號節點,如果有一種機制能保證用戶A的所有請求都只會到達0號節點,這個時候利用進程內緩存就完全沒有問題。最典型的像Actor模型應用,可以參見之前的文章"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s/eEiypRysw5jsC7iYUp_yAg","title":null},"content":[{"type":"text","text":"分佈式高併發下Actor模型如此優秀🤠"}]}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"link","attrs":{"href":"#進程外緩存","title":null}},{"type":"text","text":"進程外緩存"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"顧名思義,進程外緩存的意思是緩存數據和應用程序是隔離的,位於不同的進程內。當然這裏又可以把進程外緩存劃分爲單機版和分佈式版本,單機版本這裏就不多說了,會存在單機故障問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"進程外的分佈式版本通常被稱爲分佈式緩存,是基於分佈式理論的一種架構模式。它突破了單機緩存的容量限制和單機故障問題,雖然在訪問速度上比進程內緩存要慢很多,但是相比較磁盤IO操作要快的多,所以現在很多大型系統都喜歡用分佈式緩存來提高性能。像用的最多的Redis在3.0版本之後就提供了集羣方案。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"link","attrs":{"href":"#寫在最後","title":null}},{"type":"text","text":"寫在最後"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在面對緩存帶給系統的優勢之後,也要注意到緩存也會有一些不足。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存和數據源的一致性問題"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存命中問題"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存的雪崩穿透問題"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存的併發競爭問題"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存適合讀多寫少的系統"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"引入緩存組件會給系統設計帶來一定的複雜度"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存會加大運維的成功以及排查bug的成本"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"雖然緩存帶來了不少問題,但是相比較緩存帶給系統性能的提升是毋庸置疑的。我們在設計一個高併發系統的時候,緩存已經成爲了一種必備設計,在正確設計了緩存各種策略之後,才能最大發揮緩存的優勢"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"更多精彩文章"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1342955119549267969&__biz=MzIwNTc3OTAxOA==#wechat_redirect","title":null},"content":[{"type":"text","text":"分佈式大併發系列"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1342959003139227648&__biz=MzIwNTc3OTAxOA==#wechat_redirect","title":null},"content":[{"type":"text","text":"架構設計系列"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1342962375443529728&__biz=MzIwNTc3OTAxOA==#wechat_redirect","title":null},"content":[{"type":"text","text":"趣學算法和數據結構系列"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1342964237798391808&__biz=MzIwNTc3OTAxOA==#wechat_redirect","title":null},"content":[{"type":"text","text":"設計模式系列"}]}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f8/f8af5984765a267892bf1a1272272625.png","alt":"image","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章