「什麼!服務受到DoS攻擊,資料庫無法負荷交易,服務癱瘓了!?」
一天早晨,聽說別部門服務受到DoS阻斷式攻擊,更蝦趴的是來源是內部IP,實際是因爲客戶端設置錯誤,造成頻繁請求,最終導致資料庫無法負荷交易,間接造成服務處理節點癱瘓失效。
這也造成了我開始接觸Apache APISIX的原因。
那幾天開始與不同部門的IT人員交流,討論該如何避免相似問題再度發生。恰恰那段時間之前,在學習了解微服務的概念,聽過朋友提到過斷路器/熔斷器。
不知道大家有沒有這樣的經驗:再使用高功率電器產品的時候,像是使用吹風機吹頭髮、開個烤箱烤土司、用微波爐加熱便當......然後就跳電了。
這時候需要先把高功率電子產品關閉,再去找到總電閘把電閘打開。
跳電,其實是一種保護機制。電線的電流壓力達到臨界,再增加可能引起電線走火、電器產品毀壞,更糟糕可能引起大型火災,人財兩失。跳電,是為了預防更大的危險。而電閘跳開的機構,就叫做「斷路器」,跳開形成斷路/電流無法形成迴路,電器產品便無法使用。
更早以前家庭使用的斷路器,同時也是熔斷器。熔斷器我在一些產品上還有看過,像是旅用萬國轉接頭。其原理是透過一根低熔點的金屬細絲形成整體迴路,也因此叫做「保險絲」。當電流增加,金屬絲溫度也上升,最後達到金屬絲融化的極限溫度,金屬融化也就無法形成迴路。「保險絲」犧牲自己,用斷路保護後面的家庭與電器。
(圖片來源: https://i.sstatic.net/NrcnJ.jpg 、 https://electronics.stackexchange.com/questions/227432/glass-fuse-selection-rule)
微服務,軟體的「斷路器」也是同樣目的。目的是為了保護上游服務節點,特別是軟體服務經常有自我恢復性,有可能在一段時間休息後就自我恢復。因此「斷路器」的作用,就是為了提供這一段空白的休息時間。
具有斷路器能力的反向代理工具,並不是只有Apache APISIX,Kong Gateway、Tyk也都有相關功能。會採用Apache APISIX的原因其實很單純:選擇上是第一個嘗試的,並且符合需求,也就沒有在嘗試其他工具。
難怪商業課上會討論「先行者優勢」🤔
其實像學習OAuth 2.0時,會使用「Keycloak」一樣,Apache APISIX最初也是個人私下學習為目的的。因此更多的不算是考量其商業價值,而是其原始碼授權和免費資源豐富性為考慮。Apache APISIX已經是Apache基金會下的頂級項目(Top-Level Project),使用友善Apache授權。貢獻至Apache前,項目有華人發起,當時相對豐富的中文資源。並且部落格還有一篇「有了NGINX和Kong,爲什麼還需要Apache APISIX - 韓飛」和BilBil研討會影片。
api-breaker
斷路器pluginAPISIX的api-breaker Plugin大致邏輯如下:
「當上游端點回覆狀態碼是不健康的,並達到斷路觸發次數,則引發斷路時間。斷路時間由2秒、4秒、8秒方式倍增,直至斷路時間允許最大值(如300秒),提供上游恢復的休息時間。而當上游標記為不健康狀態,但回覆狀態碼是健康的,並達到回復成迴路的次數,則恢復轉發請求。」
因此需要考慮幾個部分的設定:
接下來的DEMO會更為清楚以上結果。
1. 建立httpbin服務
為了收到「不健康的回覆狀態碼」,並不能像是「新竹百貨公司」的例子,簡單使用http-server
。因此我們需要換一個上游,換成httpbin這個服務。你可以直接透過 https://httpbin.org/ 玩玩看,也可在本地透過docker建立起本地服務:
docker run -p 8085:80 kennethreitz/httpbin
或是同樣建立docker-compose.yaml
檔案,並用docker compose up
啓動服務:
services:
httpbin01:
image: kennethreitz/httpbin
ports:
- 8085:80
2. 設定APISIX路由
建立一個名稱為「httpbin」的路由。這次直接在路由設定上游節點內容:https://httpbin.org:443
。你也可以添加/換成自架的httpbin服務http://localhost:8085
另外特別注意超時設定,可以維持預設的6秒
即可。這次LAB會透過超時機制實現。
3. 設定api-breakder
plugin
參數 | 值 | 備註 |
---|---|---|
什麼是不健康的回覆狀態碼? | 504 |
Gateway回復上游超時 |
不健康臨界次數 | 3次 | |
最大斷路時間 | 300秒 | |
什麼是健康的回覆狀態碼? | 200 |
|
視作健康臨界次數 | 3次 | |
當斷路形成時,回覆給客戶端的狀態碼與內容是什麼? | 回覆503 狀態 |
內容「斷路器」 |
要在Dashboard設定斷路器,需要在
apisix_dashboard_config/config.yaml
中plugins
區段添加api-breaker
。
像是:plugins: # plugin list (sorted in alphabetical order) - api-breaker
4. Delay API
這次LAB會利用httpbin的/delay/{delay}
API來完成實驗。簡單來說瀏覽 http://localhost:9080/delay/2
後,會等待2秒才收到回覆。
Apache APISIX同樣有一個plugin可以模擬超時行爲--fault-injection可以設定
delay.duration
另外注意2秒的延遲情況,狀態碼是200
。相對來說,如果延遲超過6秒,也就會觸發APISIX的Gateway超時,並且恢復狀態碼是504
。
5. 觸發「斷路器api-breaker」plugin
現在來試試延遲10秒4次看看: http://localhost:9080/delay/10
。會發現回覆狀態碼變成了503
,並且內容顯示「斷路器」。再看使用時間,幾乎是秒回。如果回去看APISIX的記錄,會發現它直接回覆,而不將請求轉發給上游處理。
可能要再過個5分鐘(300秒),才會恢復到504
的超時狀態。
「斷路器」做法在上游節點已經發生問題時,才會發揮作用。如果對於平常流量使用有了解,知道正常使用情況如何,DoS攻擊又如何,那麼可以設定限流。
在「高乘載管制」已經見過以請求數量限制流量的方式,APISIX還可以依照「請求數量」、「連線數量」進行限制。這節僅針對「高乘載管制」中「請求數量限制」進一步說明。設定的參數如下:
count: 1
time_window: 60
key_type: var
key: remote_addr
rejected_code: 429
rejected_msg: 高乘載管制
show_limit_quota_header: true
首先看到key_type
和key
的設定,表示針對remote_addr
,也就是客戶端請求IP個別限制。如果192.168.56.9
被限制流量了,192.168.56.10
並不會因此受到影響。
接著看看rejected_code
和rejected_msg
,這兩個參數顯示當請求數量超過後,APISIX回覆給客戶端的狀態碼和內容。
show_limit_quota_header
則允許限制狀態恢復給客戶端了解。
最後是計算的時間窗格time_window
和在時間窗格內允許的數量。方便實驗,設置成了60秒的時間窗格和僅1次的數量。
可以同樣對「httpbin」路由套用「高乘載管制」的服務,然後請求 http://localhost:9080/get
一次看看
curl -s -v http://127.0.0.1:9080/get
第一次收到的狀態碼應該是200
,並且在回覆的HEADER內可以看到限速狀態訊息。如果在60秒內再發送一次請求,則會收到429
的狀態碼,而回覆內容是{"error_msg":"高乘載管制"}
。
本章節介紹了兩種上游節點的保護方式:「斷路」和「限流」。不過其實更挑戰的是,應該怎麼設定兩者才是適合的?這可能需要知道平常的使用情況,服務水平或垂直擴展的能力等等。也歡迎有人和我分享適合的做法~