今天這個話題,我相信對於做網際網路業務的朋友不會陌生,特別是電商或者互金領域。一碰到做大規模促銷活動,訪問量會有十倍乃至百倍的增加,比如現在正在做的618。做技術的童鞋都知道,每次在做大型活動前,我們都會整備物資,查漏補缺,拉標語打口號,各種活動演練,期待打一個大勝仗。但是實際上,除了‘鵝貓狗餓’這樣的大廠,其他小廠的軟硬體都是容易吃緊的。那麼真遇到流量吃不消了,就要考慮流量控制了,硬撐的結果,只會帶來更大的系統性風險。
什麼是流量控制?
流量控制就是監控當前系統的流量,如果超過預設的值或者當前系統的最大承受能力,則需要拒絕掉部分請求,以實現對系統的保護。最大承受能力的值來源於平時的壓力或者效能測試的結果。
流量控制的策略
流量控制一般有兩種策略方案:
1. 基於流量閾值的流控:流量閾值是每臺主機的流量上限,流量超過該閾值主機將進入不穩定狀態。閾值提前進行設定,如果主機當前流量超過閾值,則拒絕掉一部分流量,使得實際被處理流量始終低於閾值。
基於閾值的流控是最常見的一種方案,大多數的流控也是基於此,閾值一般通過壓力測試確定。但是需要提前設定閾值,而且由於現在的系統多采用分散式的方案,需要有同步的機制,保證閾值能有效的同步。
2. 基於主機狀態的流控:每個接受每個請求之前先判斷當前主機狀態,如果主機狀況不佳,則拒絕當前請求。基於主機狀態的流控的好處是省去了人為控制,不過難點在於需要制定一個穩定性的標準。而且還需要大量的實驗來證明標準是否足夠全面,否則不會觸發流量控制。所以,如果對服務的狀態沒有足夠的瞭解下,設定閾值的流控是最穩妥的辦法。
流量控制的執行方案
按照服務端外部和內部的流量進行分類,有兩種執行方案:
1. 外部HTTP訪問流控
通過Nginx或者Tengine反向代理實現,基於各種策略進行流量控制。
例如,
(1). 限制每秒請求數
涉及模組:ngx_http_limit_req_module
通過漏桶原理來限制單位時間內的請求數,一旦單位時間內請求數超過限制,就會返回 503 錯誤。
範例:
http { limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
...
server {
...
location ~ \.php$ { limit_req zone=one burst=5 nodelay;
}
}
}複製程式碼
(2).白名單設定
http_limit_conn 和 http_limit_req 模組限制了單 IP 單位時間內的連線和請求數,但是如果 Nginx 前面有 lvs 或者 haproxy 之類的負載均衡或者反向代理,nginx 獲取的都是來自負載均衡的連線或請求,這時不應該限制負載均衡的連線和請求,就需要 geo 和 map 模組設定白名單:
geo $whiteiplist {
default 1; 10.11.15.1610;
}
map $whiteiplist$limit { 1$binary_remote_addr; 0"";
}limit_req_zone $limit zone=one:10m rate=10r/s;limit_conn_zone $limit zone=addr:10m;
複製程式碼
2. 內部流量控制
對於內部服務的流量控制,可以考慮系統資源的使用情況,當系統資源成為瓶頸時,內部服務框架需要對消費者做限流,啟動流控保護機制。對於內部流控檢測的資源包括但不侷限於以下系統:
當我們有明確的指標後,我們就需要制定對應的級別。不同級別拒掉的訊息比例不同,這取決於資源的負載使用情況。例如當發生一級流控時,拒絕掉1/4的訊息;發生二級流控時,拒絕掉1/2訊息;發生三級流控時,所有的訊息都被流控掉。
不同的級別有不同的流控閾值,系統上線後會提供預設的流控閾值,不同流控因子的流控閾值不同,業務上線之後通常會根據現場的實際情況做閾值調優,因此流控閾值需要支援線上修改和動態生效。
Dubbo服務框架提供服務呼叫入口的攔截點和切面介面,由業務實現自定義流控。也可以提供基礎的流控框架,供業務實現流控條件判斷、流控執行策略等,簡化業務的定製工作量。
最後,講個人的經驗提示:當因為流控而拒絕請求時,務必在返回的資料中帶上一個友好的提示資訊,一方面能讓終端使用者感覺更友好,另外一方面,從技術端,我們也能明確使用者之所以不能正常訪問,是因為流控的原因,而不是客戶端或者服務端的BUG,這是一個很大的坑。
掃描二維碼或手動搜尋微信公眾號【架構棧】: ForestNotes
歡迎轉載,帶上以下二維碼即可