架構(gòu)必備:Rate limiting 的作用和常見方式
Rate limiting 在 Web 架構(gòu)中非常重要,是互聯(lián)網(wǎng)架構(gòu)可靠性保證重要的一個方面。
從最終用戶訪問安全的角度看,設(shè)想有人想暴力碰撞網(wǎng)站的用戶密碼;或者有人攻擊某個很耗費(fèi)資源的接口;或者有人想從某個接口大量抓取數(shù)據(jù)。大部分人 都知道應(yīng)該增加 Rate limiting,做請求頻率限制。從安全角度,這個可能也是大部分能想到,但不一定去做的薄弱環(huán)節(jié)。
從整個架構(gòu)的穩(wěn)定性角度看,一般 SOA 架構(gòu)的每個接口的有限資源的情況下,所能提供的單位時間服務(wù)能力是有限的。假如超過服務(wù)能力,一般會造成整個接口服務(wù)停頓,或者應(yīng)用 Crash,或者帶來連鎖反應(yīng),將延遲傳遞給服務(wù)調(diào)用方造成整個系統(tǒng)的服務(wù)能力喪失。有必要在服務(wù)能力超限的情況下 Fail Fast。
另外,根據(jù)排隊論,由于 API 接口服務(wù)具有延遲隨著請求量提升迅速提升的特點(diǎn),為了保證 SLA 的低延遲,需要控制單位時間的請求量。這也是 Little’s law 所說的。
還有,公開 API 接口服務(wù),Rate limiting 應(yīng)該是一個必備的功能,否則公開的接口不知道哪一天就會被服務(wù)調(diào)用方有意無意的打垮。
所以,提供資源能夠支撐的服務(wù),將過載請求快速拋棄對整個系統(tǒng)架構(gòu)的穩(wěn)定性非常重要。這就要求在應(yīng)用層實現(xiàn) Rate limiting 限制。
常見的 Rate limiting 的實現(xiàn)方式
Proxy 層的實現(xiàn),針對部分 URL 或者 API 接口進(jìn)行訪問頻率限制
Nginx 模塊
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {
location /search/ {
limit_req zone=one burst=5;
}
詳細(xì)參見:ngx_http_limit_req_module
Haproxy 提供的功能
詳細(xì)參見:Haproxy Rate limit 模塊
Java、Scala JVM 系應(yīng)用層實現(xiàn)
Google Guava 提供了一個 RateLimiter 實現(xiàn)。使用方式簡單明了,在自己的應(yīng)用中簡單封裝即可,放到 HTTP 服務(wù)或者其他邏輯接口調(diào)用的前端。
final RateLimiter rateLimiter = RateLimiter.create(2.0); // rate is "2 permits per second" void submitTasks(List<Runnable> tasks, Executor executor) { for (Runnable task : tasks) { rateLimiter.acquire(); // may wait executor.execute(task); } }
詳細(xì)參見:Google Guava RateLimiter
基于 Redis 功能的實現(xiàn)
這個在 Redis 官方文檔有非常詳細(xì)的實現(xiàn)。一般適用于所有類型的應(yīng)用,比如 PHP、Python 等等。Redis 的實現(xiàn)方式可以支持分布式服務(wù)的訪問頻率的集中控制。Redis 的頻率限制實現(xiàn)方式還適用于在應(yīng)用中無法狀態(tài)保存狀態(tài)的場景。