分布式緩存的25個優秀實踐與線上案例 done

楊彪,螞蟻金服技術專家,《分布式服務架構:原理、設計與實戰》和《可伸縮服務架構:框架與中間件》作者。近10年互聯網和游戲行業工作經驗。


本文節選自即將出版的《可伸縮服務架構:框架與中間件》一書,作者:李艷鵬、楊彪、李海亮、賈博巖、劉淏。



本文主要介紹使用分布式緩存的優秀實踐和線上案例。這些案例是筆者在多家互聯網公司里積累并形成的優秀實踐,能夠幫助大家在生產實踐中避免很多不必要的生產事故。


一、緩存設計的核心要素


我們在應用中決定使用緩存時,通常需要進行詳細的設計,因為設計緩存架構看似簡單,實則不然,里面蘊含了很多深奧的原理,如果使用不當,則會造成很多生產事故甚至是服務雪崩之類的嚴重問題。


筆者在做設計評審的過程中,總結了所有與緩存設計相關的設計點,這里列出來供大家參考。


1、容量規劃


  • 緩存內容的大小

  • 緩存內容的數量

  • 淘汰策略

  • 緩存的數據結構

  • 每秒的讀峰值

  • 每秒的寫峰值


2、性能優化


  • 線程模型

  • 預熱方法

  • 緩存分片

  • 冷熱數據的比例


3、高可用


  • 復制模型

  • 失效轉移

  • 持久策略

  • 緩存重建


4、緩存監控


  • 緩存服務監控

  • 緩存容量監控

  • 緩存請求監控

  • 緩存響應時間監控


5、注意事項


  • 是否有可能發生緩存穿透

  • 是否有大對象

  • 是否使用緩存實現分布式鎖

  • 是否使用緩存支持的腳本(Lua)

  • 是否避免了Race Condition


筆者在這里把這些設計點提供給讀者,請讀者在做緩存設計時把每一項作為一個思考的起點,思考我們在設計緩存時是否想到了這些點,以避免在設計的過程中因忽略某一項而導致嚴重的線上事故發生。


二、緩存設計的優秀實踐


筆者在做設計評審的過程中,總結了一些開發人員在設計緩存系統時的優秀實踐,如下所述:


優秀實踐1


緩存系統主要消耗的是服務器的內存,因此,在使用緩存時必須先對應用需要緩存的數據大小進行評估,包括緩存的數據結構、緩存大小、緩存數量、緩存的失效時間,然后根據業務情況自行推算在未來一定時間內的容量的使用情況,根據容量評估的結果來申請和分配緩存資源,否則會造成資源浪費或者緩存空間不夠。


優秀實踐2


建議將使用緩存的業務進行分離,核心業務和非核心業務使用不同的緩存實例,從物理上進行隔離,如果有條件,則請對每個業務使用單獨的實例或者集群,以減小應用之間互相影響的可能性。筆者就經常聽說有的公司應用了共享緩存,造成緩存數據被覆蓋以及緩存數據錯亂的線上事故


優秀實踐3


根據緩存實例提供的內存大小推算應用需要使用的緩存實例數量,一般在公司里會成立一個緩存管理的運維團隊,這個團隊會將緩存資源虛擬成多個相同內存大小的緩存實例。


例如一個實例有4GB內存,在應用申請時可以按需申請足夠的實例數量來使用,對這樣的應用需要進行分片,詳情請參考《可伸縮服務架構:框架與中間件》中4.4.3的內容。這里需要注意,如果我們使用了RDB備份機制,每個實例使用4GB內存,則我們的系統需要大于8GB內存,因為RDB備份時使用了 copy-on-write 機制,需要fork出一個子進程,并且復制一份內存,因此需要雙份的內存存儲大小。

關于redis兩種備份機制:https://www.cnblogs.com/rollenholt/p/3874443.html


優秀實踐4


緩存一般是用來加速數據庫的讀操作的,一般先訪問緩存后訪問數據庫,所以緩存的超時時間的設置是很重要的。筆者曾經在一家互聯網公司遇到過由于運維操作失誤導致緩存超時設置得較長,從而拖垮服務的線程池,最終導致服務雪崩的情況。


優秀實踐5


所有的緩存實例都需要添加監控,這是非常重要的,我們需要對慢查詢、大對象、內存使用情況做可靠的監控。


優秀實踐6


我們不推薦多個業務共享一個緩存實例,但是由于成本控制的原因,這種情況經常出現,我們需要通過規范來限制各個應用使用的key有唯一的前綴,并進行隔離設計,避免產生緩存互相覆蓋的問題。


優秀實踐7


任何緩存的key都必須設定緩存失效時間,且失效時間不能集中在某一點,否則會導致緩存占滿內存或者緩存雪崩


優秀實踐8


低頻訪問的數據不要放在緩存中,如我們前面所說的,我們使用緩存的主要目的是提高讀取性能。


曾經有個小伙伴設計了一套定時的批處理系統,由于批處理系統需要對一個大的數據模型進行計算,所以該小伙伴把這個數據模型保存在每個節點的本地緩存中,并通過消息隊列接收更新的消息來維護本地緩存中模型的實時性,但是這個模型每個月只用了一次,所以這樣使用緩存是很浪費的。


既然是批處理任務,就需要把任務進行分割,進行批量處理,采用分而治之、逐步計算的方法,得出最終的結果即可。


優秀實踐9


緩存的數據不易過大,尤其是Redis,因為Redis使用的是單線程模型,在單個緩存key的數據過大時,會阻塞其他請求的處理。


優秀實踐10


對于存儲較多value的key,盡量不要使用HGETALL等集合操作,該操作會造成請求阻塞,影響其他應用的訪問。


優秀實踐11


緩存一般用于在交易系統中加速查詢的場景,有大量的更新數據時,尤其是批量處理時,請使用批量模式,但是這種場景較少。


優秀實踐12


如果對性能的要求不是非常高,則盡量使用分布式緩存,而不要使用本地緩存,因為本地緩存在服務的各個節點之間復制,在某一時刻副本之間是不一致的,如果這個緩存代表的是開關,而且分布式系統中的請求有可能會重復,就會導致重復的請求走到兩個節點,一個節點的開關是開,一個節點的開關是關,如果請求處理沒有做到冪等,就會造成處理重復,在嚴重情況下會造成資金損失。


優秀實踐13


在寫緩存時一定要寫入完全正確的數據,如果緩存數據的一部分有效、一部分無效,則寧可放棄緩存,也不要把部分數據寫入緩存,否則會造成空指針、程序異常等。


優秀實踐14


在通常情況下,讀的順序是先緩存,后數據庫;寫的順序是先數據庫,后緩存


優秀實踐15


在使用本地緩存(如Ehcache)時,一定要嚴格控制緩存對象的個數及聲明周期。由于JVM的特性,過多的緩存對象會極大影響JVM的性能,甚至導致內存溢出等


優秀實踐16


在使用緩存時,一定要有降級處理,尤其是對關鍵的業務環節,緩存有問題或者失效時也要能回源到數據庫進行處理。


三、關于常見的緩存問題的線上案例


筆者在多家互聯網公司負責架構方案評審和線上事故復盤,這里列舉其中的一些典型案例,供大家參考和借鑒。


案例1


現象:某應用程序的數據庫負載瞬時升高。


原因:在應用程序中對使用的大量緩存key設置了同一個固定的失效時間,當緩存失效時,會造成在一段時間內同時訪問數據庫,造成數據庫的壓力較大。


總結:在使用緩存時需要進行緩存設計,要充分考慮如何避免常見的緩存穿透、緩存雪崩、緩存并發等問題,尤其是對于高并發的緩存使用,需要對key的過期時間進行隨機設置,例如,將過期時間設置為10秒+random(2),也就是將過期時間隨機設置成10~12秒。


案例2


現象:導致遷移前后兩個系統的核心操作重復。


原因:在遷移的過程中,重復的流量進入了不同的節點,由于使用了本地緩存存儲遷移開關,而遷移開關在開關打開的瞬間導致各個節點的開關狀態不一致,有的是開、有的是關,所以對于不同節點的流量的處理重復,一個走了開關開的邏輯,一個走了開關關的邏輯。


總結:避免使用本地緩存來存儲遷移開關,遷移開關應該在有狀態的訂單上標記。


案例3


現象:某模塊設計使用了緩存加速數據庫的讀操作的性能,但發現數據庫負載并沒有明顯下降。


原因:由于這個模塊的使用方查詢請求的數據在數據庫中不存在,是非法的數據,所以導致緩存沒有命中,每次都穿透到數據庫,且量級較大。


總結:在使用緩存時需要進行緩存設計,要充分考慮如何避免常見的緩存穿透、緩存雪崩、緩存并發等問題,尤其是對高并發的緩存使用,需要對無效的key進行緩存,以抵擋惡意的或者無意的對無效緩存查詢的攻擊或影響。


案例4


現象:監控系統報警,Redis中單個哈希鍵占用的空間巨大。


原因:應用系統使用了哈希鍵,哈希鍵本身有過期時間,但是哈希鍵里面的每個鍵值對沒有過期時間。


總結:在設計Redis的過程中,如果有大量的鍵值對要保存,則請使用字符串鍵的數據庫類型,并對每個鍵都設置過期時間,請不要在哈希鍵內部存儲一個沒有邊界的集合數據實際上,無論是對緩存、內存還是對數據庫的設計,如果使用任意一個集合的數據結構,則都要考慮為它設置最大限制,避免內存用光,最常見的是集合溢出導致的內存溢出的問題。


案例5


現象:某業務項目由于緩存宕機導致業務邏輯中斷,數據不一致。


原因:Redis進行主備切換,導致瞬間內應用連接Redis異常,應用并沒有對緩存做降級處理


總結:對于核心業務,在使用緩存時一定要有降級方案。常見的降級方案是在數據庫層次預留足夠的容量,在某一部分緩存出現問題時,可以讓應用暫時回源到數據庫繼續業務邏輯,而不應該中斷業務邏輯,但是這需要嚴格的容量評估,請參考《分布式服務架構:原理設計與實戰》第3章的內容。


案例6


現象:某應用系統負載升高,響應變慢,發現應用進行頻繁GC,甚至出現OutOfMemroyError: GC overhead limt exceed的錯誤日志。


原因:

因為這個項目是個歷史項目,使用了Hibernate ORM框架,在Hibernate中開啟了二級緩存,使用了Ehcache;但是在Ehcache中沒有控制緩存對象的個數,緩存對象增多,導致內存緊張,所以進行了頻繁的GC操作


總結:

使用本地緩存(如Ehcache、OSCache、應用內存)時,一定要嚴格控制緩存對象的個數及聲明周期


案例7


現象:某個正常運行的應用突然報警線程數過高,之后很快就出現了內存溢出


原因:由于緩存連接數達到最大限制,應用無法連接緩存,并且超時時間設置得較大,導致訪問緩存的服務都在等待緩存操作返回,由于緩存負載較高,處理不完所有的請求,但是這些服務都在等待緩存操作返回,服務這時在等待,并沒有超時,就不能降級并繼續訪問數據庫。這在BIO模式下線程池就會撐滿,使用方的線程池也都撐滿;在NIO模式下一樣會使服務的負載增加,服務響應變慢,甚至使服務被壓垮。


總結:在使用遠程緩存(如Redis、Memcached)時,一定要對操作超時時間進行設置,這是非常關鍵的,一般我們設計緩存作為加速數據庫讀取的手段,也會對緩存操作做降級處理,因此推薦使用更短的緩存超時時間,如果一定要給出一個數字,則希望是100毫秒以內


案例8


現象:某項目使用緩存存儲業務數據,上線后出現錯誤問題,開發人員束手無策。


原因:開發人員不知道如何發現、排查、定位和解決緩存問題。


總結:在設計緩存時要有降級方案,在遇到問題時首先使用降級方法,還要設計完善的監控和報警功能,幫助開發人員快速發現緩存問題,進而來定位和解決問題。


案例9


現象:某項目在使用緩存后,開發測試通過,到生產環境后,服務卻出現了不可預知的問題。


原因:該應用的緩存key與其他應用緩存 key沖突,導致互相覆蓋,出現邏輯錯誤。


總結:在使用緩存時一定要有隔離的設計,可以通過不同的緩存實例來做物理隔離,也可以通過各個應用的緩存key使用不同的前綴進行邏輯隔離

新書搶先看



本文節選自即將出版的《可伸縮服務架構:框架與中間件》一書,此書現已開放預售,可登錄網址:https://item.jd.com/12308233.html 搶先訂購。更多新書精華內容也將由DBAplus社群陸續呈現。





轉載于:https://www.cnblogs.com/silyvin/p/9106612.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/453039.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/453039.shtml
英文地址,請注明出處:http://en.pswp.cn/news/453039.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

服務器性能估算參考(硬件-應用服務器)

2019獨角獸企業重金招聘Python工程師標準>>> Environment(2013-05-24) two identical machines via a GB-Ethernet link a client machine generating HTTP requests with wrk as the load generator a server machine running the respective “benchmarkee”all …

產生死鎖的四個必要條件

(1)互斥條件:進程對所分配到的資源不允許其他進程進行訪問,若其他進程訪問該資源,只能等待,直至占有該資源的進程使用完成后釋放該資源 (2)請求和保持條件:進程獲得一定的…

下拉選擇_在管理Excel中實現聯動下拉選擇

在系統中常常出現這樣的情況:由于下拉選擇的數量太多了,難以高效選擇。為此管理Excel通過通過引入多級聯動選擇的方式來減少下拉選擇的困難度。先看下使用效果:聯動下拉選擇這個功能,在管理Excel中可以通過比較簡單的配置方法實現…

圖片預覽

// 預覽圖片yulanFn: function (e) {var arr [];var that this;//獲取當前圖片的下表var indexw e.currentTarget.dataset.indexw;var index e.currentTarget.dataset.index;//數據源var pictures this.data.banner[indexw].shoppingCarouselList;var picture "http…

風雨20年:我所積累的20條編程經驗

原文作者喬納森丹尼可(Jonathan Danylko)是一位自由職業的web架構師和程序員,編程經驗已超過20年,涉足領域有電子商務、生物技術、房地產、醫療、保險和公用事業。正如喬納 森在文中所言,本文適合剛畢業的大學生和剛入…

JS跨域(ajax跨域、iframe跨域)解決方法及原理詳解(jsonp)

這里說的js跨域是指通過js在不同的域之間進行數據傳輸或通信,比如用ajax向一個不同的域請求數據,或者通過js獲取頁面中不同域的框架中(iframe)的數據。只要協議、域名、端口有任何一個不同,都被當作是不同的域。 下表給出了相對 http://store…

xenserver 安裝新硬盤_給Xenserver添加新硬盤

首先我們進入到xenserver的Console界面.然后按下enter進入命令模式,接下來.咱們先看看硬盤有沒有存在輸入fdisk -l出現如下提示:Disk /dev/sda: 500.1 GB, 500107862016 bytes255 heads, 63 sectors/track, 60801 cylindersUnits cylinders of 16065 * 512 8225280 bytesDevi…

go-study

package (包) 一個目錄下面所有的.go文件的包名必須相同. 包名一般和目錄名相同(是約定, 不是強制), 包名都小寫main包是一個特殊的包名, 在main包中, 必須包含func main()函數導入包(import)的時候, 使用的是包所在目錄的路徑, 路徑中不用包含包的名字, 在使用包的時候,直接用…

什么是系統安全狀態

指系統能按某種順序如(P1,P2,...,Pn),來為每個進程分配所需要的資源,直至最大需求,使每個進程都可以順序完成。若系統不存在這樣一個安全序列,則稱系統處于不安全狀態。

SQL零基礎學習筆記(一)

真的不知道我寫了這么多不同的的學習筆記又沒用。。開始SQL零基礎學習筆記 百度百科:SQL(Structured Query Language)結構化查詢語言,是一種數據庫查詢和程序設計語言,用于存取數據以及查詢、更新和管理關系數據庫系統。同時也是數…

WPF 列表虛擬化時的滾動方式

ListBox的滾動方式 分為像素滾動和列表項滾動 通過ListBox的附加屬性ScrollViewer.CanContentScroll來設置。因此ListBox的默認模板中&#xff0c;含有ScrollViewer&#xff0c;ScrollViewer下存放列表內容 <ScrollViewer FocusVisualStyle"{x:Null}"><Item…

python爬蟲文獻綜述_基于Python下的爬蟲綜述及應用

98 Internet Application 互聯網 應用 引言&#xff1a;如今&#xff0c;大數據已經進入我們的各個領域&#xff0c;我們的工作及應用越來越需要獲取大量的數據。我們可以想象在一張蜘蛛網上沿著我們所需的方向爬取獵物(數據)的感覺。實際上爬蟲就是通過人為的模擬瀏覽器行為&…

HelloWorld新手常見問題

1.顯示錯誤&#xff1a; HelloWorld.java:1: 錯誤: 寫入HelloWorld時出錯: C:\HelloWorld.class public class HelloWorld { ^ 1 個錯誤 解決方法&#xff1a; 將文件轉移至D盤&#xff0c;然后編譯即可。不要放在C盤&#xff01; 2.顯示錯誤&#xff1a; 錯誤: 找不…

淺談HTTPS以及Fiddler抓取HTTPS協議

原文 淺談HTTPS以及Fiddler抓取HTTPS協議 最近想嘗試基于Fiddler的錄制功能做一些接口的獲取和處理工作&#xff0c;碰到的一個問題就是簡單連接Fiddler只能抓取HTTP協議&#xff0c;關鍵的登錄請求等HTTPS協議都沒有捕捉到&#xff0c;所以想讓Fiddler能夠同時抓取到HTTPS和HT…

關于.c和.h 和定義變量的問題

最初調試的時候是因為有個錯誤在wavplay.h文件中 于是我跳到了recorderl.h中:從圖中看到引用了main.h 出現這個問題的具體原因還是不太清楚: 不過我任務是因為: wavplay.h中定義了 __WaveHeader 變量 在main.h文件中引用了wavplay.h 而在wavplay.h中試圖引用main.h里的 __Wa…

halcon中面到面的距離_halcon學習筆記——(8)由標定板得到測量平面位姿-阿里云開發者社區...

如圖&#xff1a;由標定板位姿獲取測量板位姿1.pose_to_hom_mat3d( : : Pose : HomMat3D)把三維位姿轉化為齊次變換矩陣2.hom_mat3d_translate_local( : : HomMat3D, Tx, Ty, Tz : HomMat3DTranslate)相對于新坐標系的平移變換/ 1 0 0 \ / Tx \HomMat3DTranslate HomMat3D *…

進程同步與互斥的區別

并發進程的執行會產生相互制約的關系&#xff1a;一種是進程之間競爭使用臨界資源&#xff0c;只能讓他們逐個使用&#xff0c;這種現象稱為互斥&#xff0c;是一種競爭關系。另一種是進程之間協同完成任務&#xff0c;在關鍵點上等待另一進程發來的消息&#xff0c;以便協同一…

《軟件調試分析技術》學習筆記

《軟件調試分析技術》學習筆記&#xff08;一&#xff09; 今天開始寫寫一些心得體驗。 《軟件調試分析技術》是好友Monster的處女作品。作為一直以的好伙伴&#xff0c;他是我看著長大的&#xff0c;(*^__^*) 嘻嘻……之所以有今天這樣的成績&#xff0c;是與他的努力和天賦…