EL&JSTL
快取雪崩
對於系統 A,假設每天高峰期每秒 5000 個請求,本來快取在高峰期可以扛住每秒 4000 個請求,但是快取機器意外發生了全盤宕機。快取掛了,此時 1 秒 5000 個請求全部落資料庫,資料庫必然扛不住,它會報一下警,然後就掛了。此時,如果沒有采用什麼特別的方案來處理這個故障,DBA 很著急,重啟資料庫,但是資料庫立馬又被新的流量給打死了,這就是快取雪崩。
快取雪崩的事前事中事後的解決方案如下:
- 事前:redis 高可用,主從+哨兵,redis cluster,避免全盤崩潰。
- 事中:本地 ehcache 快取 + hystrix 限流&降級,避免 MySQL 被打死。
- 事後:redis 持久化,一旦重啟,自動從磁碟上載入資料,快速恢復快取資料。
使用者傳送一個請求,系統 A 收到請求後,先查本地 ehcache 快取,如果沒查到再查 redis。如果 ehcache 和 redis 都沒有,再查資料庫,將資料庫中的結果,寫入 ehcache 和 redis 中。
限流元件,可以設定每秒的請求,有多少能通過元件,剩餘的未通過的請求,怎麼辦?走降級!可以返回一些預設的值,或者友情提示,或者空白的值。
好處:
- 資料庫絕對不會死,限流元件確保了每秒只有多少個請求能通過。
- 只要資料庫不死,就是說,對使用者來說,2/5 的請求都是可以被處理的。
- 只要有 2/5 的請求可以被處理,就意味著你的系統沒死,對使用者來說,可能就是點選幾次刷不出來頁面,但是多點幾次,就可以刷出來一次。
快取穿透
對於系統A,假設一秒 5000 個請求,結果其中 4000 個請求是黑客發出的惡意攻擊。
黑客發出的那 4000 個攻擊,快取中查不到,每次你去資料庫裡查,也查不到。
舉個例子。資料庫 id 是從 1 開始的,結果黑客發過來的請求 id 全部都是負數。這樣的話,快取中不會有,請求每次都“視緩存於無物”,直接查詢資料庫。這種惡意攻擊場景的快取穿透就會直接把資料庫給打死。
解決方式很簡單,每次系統 A 從資料庫中只要沒查到,就寫一個空值到快取裡去,比如 set -999 UNKNOWN
。然後設定一個過期時間,這樣的話,下次有相同的 key 來訪問的時候,在快取失效之前,都可以直接從快取中取資料。
快取擊穿
快取擊穿,就是說某個 key 非常熱點,訪問非常頻繁,處於集中式高併發訪問的情況,當這個 key 在失效的瞬間,大量的請求就擊穿了快取,直接請求資料庫,就像是在一道屏障上鑿開了一個洞。
解決方式也很簡單,可以將熱點資料設定為永遠不過期;或者基於 redis or zookeeper 實現互斥鎖,等待第一個請求構建完快取之後,再釋放鎖,進而其它請求才能通過該 key 訪問資料。
Hystrix 是一個幫助解決分散式系統互動時超時處理和容錯的類庫, 它同樣擁有保護系統的能力.
Hystrix的設計原則包括:資源隔離、熔斷器、命令模式。
資源隔離
貨船為了進行防止漏水和火災的擴散,會將貨倉分隔為多個,這種資源隔離減少風險的方式被稱為:Bulkheads(艙壁隔離模式)。
Hystrix將同樣的模式運用到了服務呼叫者上,在一個高度服務化的系統中,一個業務邏輯通常會依賴多個服務,比如:商品詳情展示服務會依賴商品服務,價格服務,商品評論服務。呼叫三個依賴服務會共享商品詳情服務的執行緒池。如果其中的商品評論服務不可用,就會出現執行緒池裡所有執行緒都因等待響應而被阻塞,從而造成服務雪崩。Hystrix通過將每個依賴服務分配獨立的執行緒池進行資源隔離,從而避免服務雪崩。
熔斷器模式
熔斷器模式定義了熔斷器開關相互轉換的邏輯。
服務的健康狀況 = 請求失敗數 / 請求總數。熔斷器開關由關閉到開啟的狀態轉換是通過當前服務健康狀況和設定閾值比較決定的。
當熔斷器開關關閉時,請求被允許通過熔斷器。 如果當前健康狀況高於設定閾值,開關繼續保持關閉。如果當前健康狀況低於設定閾值,開關則切換為開啟狀態。當熔斷器開關開啟時,請求被禁止通過。當熔斷器開關處於開啟狀態,經過一段時間後,熔斷器會自動進入半開狀態,這時熔斷器只允許一個請求通過。當該請求呼叫成功時,熔斷器恢復到關閉狀態。若該請求失敗,熔斷器繼續保持開啟狀態,接下來的請求被禁止通過。
熔斷器的開關能保證服務呼叫者在呼叫異常服務時,快速返回結果,避免大量的同步等待,並且熔斷器能在一段時間後繼續偵測請求執行結果,提供恢復服務呼叫的可能。
命令模式
Hystrix使用命令模式(繼承HystrixCommand類)來包裹具體的服務呼叫邏輯(run方法),並在命令模式中添加了服務呼叫失敗後的降級邏輯(getFallback)。
同時在Command的構造方法中可以定義當前服務執行緒池和熔斷器的相關引數。因此在使用了Command模式構建了服務物件之後,服務便擁有了熔斷器和執行緒池的功能。