今天在演練這樣一個情境——假如所有快取服務器都宕機,而且不能很快恢複,並且假設資料庫伺服器能夠支撐,在代碼中如何應對這樣的情況?
之前的做法是在讀緩衝的地方捕獲異常並寫入日誌,然後直接從資料庫讀取資料;在寫緩衝的地方捕獲異常並寫入日誌,繼續後續處理。這樣看起來不錯,雖然快取服務器宕機,但程式可以繼續工作,雖然速度慢一些,但不會讓網站服務中斷,然後只要把快取服務器恢複即可。
但是如果快取服務器宕機時,訪問量很大,每一個操作緩衝的地方都拋異常、寫日誌,這是兩個開銷很大的操作,大量的這樣的操作會給Web伺服器帶來很大的壓力。有沒有更好的解決方案呢?
當操作緩衝時拋出了第一個異常,我們就已經知道快取服務器發生了故障。接下來對緩衝的任何操作不僅沒有必要,而且由此產生的異常會帶來額外的開銷、影響效能。只要我們通過一種方式在知道快取服務器發生故障的第一時間通知後續快取作業代碼不要進行快取作業,就能解決這個問題。
我們想到的一個解決方案是通過全域靜態變數,該全域靜態變數儲存快取服務器當前可用狀態,只要有一個操作緩衝的地方出現異常就將該變數置為不可用狀態,並寫日誌、發通知。每一個操作緩衝的地方在操作前先檢查一下這個全域靜態變數,一發現快取服務器不可用,就放棄操作緩衝,進入無緩衝情況下的操作流程。當我們得知快取服務器宕機後,先專心把快取服務器恢複正常運行,然後更新一下這個全域靜態變數即可。
這又是一個看起來不錯的解決方案。但是全域靜態變數只能在當前應用程式的當前進程中全域,無法在Web Farm(比如使用負載平衡,同一個應用程式運行於多台伺服器上)與Web Garden(同一個應用程式運行於同一台伺服器的多個進程中)的情境中全域。所以採用這個解決方案,快取服務器宕機時,每個進程都要進行捕獲異常、設定全域靜態變數的操作,雖然不是最佳解決方案,但總比異常滿天飛要好很多。還有一個更頭疼的問題,就是在快取服務器恢複正常後,如何將這些全域靜態變數恢複為可用狀態?無法代碼進入每一個進程中進行操作,目前我們只想到一個解決方案——重啟應用程式(如果是IIS,回收應用程式集區)。
有沒有更好的解決方案呢?繼續思考,也期待你的良計妙策。
【更新】
改進修改全域靜態變數的方式,通過定時執行的代碼檢查快取服務器的狀態。如果快取服務器不可用,將全域靜態變數置為不可用狀態;如果快取服務器可用,並且全域靜態變數的值為不可用狀態,則將全域靜態變數置為可用狀態。