這個話題的來源於,2年前折騰Redis Cluster過程中,遇到的各種坑後積累出的一些想法,加上過去一年在梳理搖旺的快取系統中遇到的問題後,有必要集中寫寫這一塊,算做一個階段性總結。
在開始往下講之前,或許部分同學會問,快取如果掛了,把快取重啟或者啟動起來不就可以了嗎?沒錯,快取掛了,確實需要儘快將快取恢復回來,但是如果認為快取掛了,就直接重啟快取就完事了,那就將問題看得過於簡單化了。對於一個大型網際網路系統而言,這時服務呼叫方是無法對快取進行存取操作,只能將流量完全打到服務方系統,服務方系統面對服務過載在劫難逃。接下來就不是快取當機那麼簡單了,而是系統不可用,乃至對外服務徹底癱瘓掉。反過來說,快取啟動後,快取裡的資料已經還在初始化中,快取查詢還是無法進行,所有的流量還是會繼續打到服務方系統上。
所以如果出現快取當機,我們需要考慮兩方面的問題:
快取恢復前,如何保證系統能繼續正常有序的工作
快取恢復後,如何保證快取在K/V恢復前,對應的服務不會過載。
以上這兩個問題,才是本文真正想討論的問題。以下部分,會針對以上兩個問題分別進行討論。
快取當機後,並且未恢復前,呼叫方系統請求通過呼叫Cache,發現Cache系統狀態不可用,則轉向請求服務方系統(通過介面從資料庫訪問資料),我們可選的方案如下:
A. 發現快取不可用,不進一步呼叫服務提供方系統,直接返回預先設定的系統預設值。
B. 發現快取不可用,呼叫方系統按照一定的比率或者概率,決定讓部分請求呼叫服務提供方。
C. 呼叫服務方之前,根據服務方反饋的狀態,動態決定請求是否呼叫服務方,或者直接返回預設值。
方案A 實施起來最容易,如果呼叫方知道直接呼叫服務提供方系統可能扛不住自己的全部流量,索性不請求服務方,等待快取恢復後在繼續訪問。但這個方案的侷限性在於,如果有寫需求,這個方案就行不通了,因為很難簡單的設定預設值, 並且,如果快取缺乏持久化的話,資料快取的更新是需要一次次呼叫來初始化的。
方案B的方案的優點在於,讓一部分執行緒請求服務方系統,保證資料能及時更新的同時,快取也能持續初始化,至於讓多少比例的流量直接呼叫服務,保守的做法就是保證呼叫方的併發不大於服務方的最大吞吐量。所以,在採用B方案之前,一定要做好效能或者壓力測試。
方案C的做法,實際上類似於上篇我寫的Hystrix的Circuit-breaker機制,如果服務方系統執行正常,執行請求;如果服務方系統過載,則拒絕服務,保護服務提供方的同時,最大限度挖掘服務方效能。可以參考的效能引數有CPU負載、記憶體使用率、GC頻率、介面響應時間等。
總結一下,方案C應該是系統應對快取當機的改進方向,但是如果時間有限的前提下,可以先利用短平快的方案B實施起來。
接下來,我們來討論一下第二個問題,Cache已經從當機過程恢復過來了,如果快取KEY的數量較少,那麼自然不用擔心,很快快取將預熱成功,也不會有引起服務過載的情況出現。但是如果快取的量或者當前前端過來的流量不好估計的時候,是不建議貿然將流量直接切過來的。
為了保證系統能順利恢復正常,我們應該採用流控的方法,循序漸進的放開流量,讓快取逐步預熱。流量控制剛開始可以為20%,然後50%,然後80%,最後全量,在放開一部分,需要實時觀察系統的狀態,根據前端流量的變化和後端的承受能力,制定放開的節奏。除此之外,強烈推薦後端系統製作專門的工具對Cache進行主動性預熱,加快系統恢復的速度,特別是快取沒有做必要的持續化的時候。
點選“閱讀原文”,所有【架構棧】近期的架構文章彙總
↓↓↓
掃描二維碼或手動搜尋微信公眾號【架構棧】: ForestNotes
歡迎轉載,帶上以下二維碼即可