高併發快取架構實戰和最佳化

圣辉發表於2024-05-03

參考資料:

圖靈課堂-https://vip.tulingxueyuan.cn

中小公司Redis快取架構以及線上問題分析

直接寫入資料庫,然後更新redis;

正常低併發情況下,這種情況是暫時不會出現問題的,因為併發量並不高,不會出現各種各樣的併發問題。

大廠線上大規模商品快取資料冷熱分離實戰

使用快取,主要是為了令常用的資料放到快取中,不常用的資料最少放到快取中,儘量提升快取的空間利用率。

所以,就對快取資料加上一個過期時間,這樣可以讓冷資料過期了節省快取空間;同時針對查詢到的資料再進行過期時間續期,讓常用資料長時間停留在快取中。

實戰解決大規模快取擊穿導致線上資料庫壓力暴增

快取擊穿:快取中沒有,但是資料庫有;就是大量請求到redis,查詢不到資料,要落庫查詢,這樣可能會導致大量的請求訪問資料庫,令資料庫壓力增長,可能會讓資料庫崩潰。此時可以針對快取設定過期時間的時候,設定隨機過期時間,保證少量的請求去訪問資料庫。

快取穿透:快取中沒有,資料庫中也沒有。就是資料不存在,或者是從資料庫直接物理刪除,會導致查詢快取沒有,資料庫也沒有;或者是駭客使用不存在的資料進行攻擊。這樣會令資料庫壓力暴增,可能會導致資料庫崩潰。後端也可以限流,也可以設定一個IP黑名單。

或者快取一個空的字串,或者一個常量json串,儘量不要返回null。同時設定一個過期時間。但是這樣並不會徹底避免這樣的情況,同時也會讓redis和資料庫的請求壓力增加;所以針對這樣的情況可以使用布隆過濾器。

駭客攻擊導致快取穿透線上資料庫當機BUG

ddos攻擊,可以進行限流操作;但是更好的方案是再加上一個布隆過濾器。

一行程式碼解決線上快取穿透問題

返回一個空值,前端進行配合。

一次大V直播帶貨導致線上商品系統崩潰原因分析

冷門商品突然有大量的流量訪問,此時針對這個key來說,壓力很高;此時直接訪問資料庫,此時還有別的請求去訪問資料庫,可能會導致資料庫的崩潰。

這些小機率事件是必須要規避的。冷門資料突然變成熱點資料。

突發性熱點快取重建導致系統壓力暴增問題分析

加鎖。使用單例模式。雙重檢索機制。先查詢快取,沒有;加鎖,然後再查詢快取,如果沒有就一個請求去查詢資料庫,後續請求都阻塞;當其執行完畢之後,後續再來執行緒再試一下就有資料返回了,不用繼續執行後續操作。

但是這個還是有點問題,這個就在單節點中有用,如果每個伺服器節點都自己構建,那麼這樣也不行,還有就是鎖物件的問題,不能使用類鎖等;

所以可以使用分散式鎖解決這個問題。此時就重新構建一次。

基於DCL機制解決熱點快取併發重建問題實戰

注意:鎖的命名儘量要見名知意,不能隨便進行簡寫,除非是專案或者公司有預設的簡寫值才行。

程式碼是編寫完成功能之後,再去考慮進行最佳化。

使用DCL,先查快取,如果沒有;就加鎖,加鎖之後,再查快取一次,如果沒有再去查資料庫。

Redis分散式鎖解決快取與資料庫雙寫不一致問題實戰

更新資料庫和快取不是原子性的,導致資料庫和快取的資料不一致。可能多個執行緒併發執行,一個執行緒執行時間太長,導致資料不一致。

如果是先寫資料庫,然後刪除快取,正常情況下是沒有問題;但是如果中間卡頓了一下,就可能導致資料不一致。可以進一步最佳化使用延時雙刪,但是這個還不行,因為這個時間並不確定。

當然正常情況下是必須要考慮異常情況的。

所以可以使用分散式鎖來實現這個功能。這是另外一個鎖,鎖名稱要見名知意。

要解決這樣的小機率情況必須要使用這樣的程式碼,這樣會導致程式碼量增大,會令程式碼變得複雜。這樣會導致查詢路徑變得很深,但是這只是第一次會這樣;工作中百分之九十以上得場景查詢得都是熱資料,所以後續的請求很早就返回資料了。使用大量的程式碼是解決小機率事件的。然後絕大部分請求不會一直走全部的程式碼。

最佳化方案:

很多情況下都是讀多寫少的情況。這樣的情況可以使用讀寫鎖。讀讀共享,併發量升高;讀寫,寫寫是互斥要加鎖的。只有寫的時候才會有不一致的情況發生。

讀寫鎖在redisson中也是透過lua指令碼來實現的,加鎖的時候有一個標記,mode標識,是讀還是寫。讀的時候類似重入鎖,可以併發讀。解鎖的時候就是重入次數減一,直到減到0.

寫的時候是互斥的。鎖一定要是同一個。

加鎖時先判斷是讀鎖還是寫鎖,讀讀共享;讀寫就阻塞等待等。如果先是寫鎖,後續所有的執行緒都要進行等待。

如果是有讀還有寫,那麼使用這個讀寫鎖就不太合適了。具體場景具體分析。針對資料庫和快取來說,可以加讀寫鎖。多個執行緒併發執行才有併發安全的問題。

大促壓力暴增導致分散式鎖序列爭用問題最佳化實戰

還有就是多次高併發查詢,如果是有上萬的請求來,請求的步驟都一樣,查詢快取麼有值;然後就是加鎖,然後再查快取,有了值就返回,並且解鎖。這樣加鎖和解鎖也是比較耗時的。所以還是可以最佳化的,如果可以確認程式碼可以再1秒中執行完畢,或者是百分之九十九點九,就可以使用tryLock,這個加上一個過期時間,如果時間到了,就直接不等待了,直接去訪問快取。但是如果1秒無法執行完成,那麼就出現bug。

這個就是權衡。這就是架構思維。

一次微博明星熱點事件導致系統崩潰原因分析

快取雪崩,剛開始快取少量失效,但是如果請求量越來越大,那麼會導致錯誤放大,最終可能會導致系統崩潰;請求是越來越多,會導致連線沒空餘的,別的功能訪問就受阻,可能最後導致崩潰。

此時可以進行限流,前端進行了限流,後端也進行限流。

利用多級快取架構解決Redis線上叢集快取雪崩問題

此時可以使用多級快取,加上一個JVM級別的快取。

但是這個也是有問題的,熱點資料是變化的,這個要考慮;還有就是如果不同的節點資料更新,可能會導致不同節點JVM快取資料不一致,這個也是要避免的。

使用zk,或者MQ也是可以的,當一個節點的資料發生變化,發出訊息,令別的節點訂閱,進行修改;此時會有短時不一致的情況,此時就不要去考慮絕對一致性了,這樣就太複雜了,有些過度設計了。只要不是長時間不一致就是可以接受的。zk也不能絕對一致。

正常來說是不會這麼做的,因為增刪改查是很頻繁的,如果這樣就會導致訊息太多;不便維護;

可以再進行拆分,抽取出來一個熱點快取,監聽所有的請求,進行計算,判斷哪些是熱點快取,保證熱點快取的值儲存在快取中。可以使用實時計算。

相關文章