在早期的計算機領域,限流技術(time limiting)被用作控制網絡接口收發通信數據的速率。 可以用來優化性能,減少延遲和提高帶寬等。 現在在互聯網領域,也借鑒了這個概念, 用來為服務控制請求的速率, 如果雙十一的限流, 12306的搶票等。 即使在細粒度的軟件架構中,也有類似的概念。
兩種常用算法
令牌桶(Token Bucket)和漏桶(leaky bucket)是 最常用的兩種限流的算法。
漏桶算法
它的主要目的是控制數據注入到網絡的速率,平滑網絡上的突發流量。漏桶算法提供了一種機制,通過它,突發流量可以被整形以便為網絡提供一個穩定的流量。 漏桶可以看作是一個帶有常量服務時間的單服務器隊列,如果漏桶(包緩存)溢出,那么數據包會被丟棄。 用說人話的講:
漏桶算法思路很簡單,水(數據或者請求)先進入到漏桶里,漏桶以一定的速度出水,當水流入速度過大會直接溢出,可以看出漏桶算法能強行限制數據的傳輸速率。
在某些情況下,漏桶算法不能夠有效地使用網絡資源。因為漏桶的漏出速率是固定的參數,所以,即使網絡中不存在資源沖突(沒有發生擁塞),漏桶算法也不能使某一個單獨的流突發到端口速率。因此,漏桶算法對于存在突發特性的流量來說缺乏效率。而令牌桶算法則能夠滿足這些具有突發特性的流量。通常,漏桶算法與令牌桶算法可以結合起來為網絡流量提供更大的控制。
令牌桶算法
令牌桶算法的原理是系統會以一個恒定的速度往桶里放入令牌,而如果請求需要被處理,則需要先從桶里獲取一個令牌,當桶里沒有令牌可取時,則拒絕服務。 令牌桶的另外一個好處是可以方便的改變速度。 一旦需要提高速率,則按需提高放入桶中的令牌的速率。 一般會定時(比如100毫秒)往桶中增加一定數量的令牌, 有些變種算法則實時的計算應該增加的令牌的數量, 比如華為的專利"采用令牌漏桶進行報文限流的方法"(CN 1536815 A),提供了一種動態計算可用令牌數的方法, 相比其它定時增加令牌的方法, 它只在收到一個報文后,計算該報文與前一報文到來的時間間隔內向令牌漏桶內注入的令牌數, 并計算判斷桶內的令牌數是否滿足傳送該報文的要求。
從最終用戶訪問安全的角度看,設想有人想暴力碰撞網站的用戶密碼;或者有人攻擊某個很耗費資源的接口;或者有人想從某個接口大量抓取數據。大部分人都知道應該增加 Rate limiting,做請求頻率限制。從安全角度,這個可能也是大部分能想到,但不一定去做的薄弱環節。
從整個架構的穩定性角度看,一般 SOA 架構的每個接口的有限資源的情況下,所能提供的單位時間服務能力是有限的。假如超過服務能力,一般會造成整個接口服務停頓,或者應用 Crash,或者帶來連鎖反應,將延遲傳遞給服務調用方造成整個系統的服務能力喪失。有必要在服務能力超限的情況下 Fail Fast。
另外,根據排隊論,由于 API 接口服務具有延遲隨著請求量提升迅速提升的特點,為了保證 SLA 的低延遲,需要控制單位時間的請求量。這也是 Little’s law 所說的。
還有,公開 API 接口服務,Rate limiting 應該是一個必備的功能,否則公開的接口不知道哪一天就會被服務調用方有意無意的打垮。
所以,提供資源能夠支撐的服務,將過載請求快速拋棄對整個系統架構的穩定性非常重要。這就要求在應用層實現 Rate limiting 限制。
常見的 Rate limiting 的實現方式
Proxy 層的實現,針對部分 URL 或者 API 接口進行訪問頻率限制
Nginx 模塊
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s; server { location /search/ { limit_req zone=one burst=5; }
詳細參見: ngx_http_limit_req_module
Haproxy 提供的功能
詳細參見: Haproxy Rate limit 模塊
RateLimiters是令牌桶和漏桶在.NET 中實現。這些策略可用于速率限制請求不同的網站中,后端或 API 調用等場景。
ASP.NET Web API rate limiter for IIS and Owin hosting
基于 Redis 功能的實現
這個在 Redis 官方文檔有非常詳細的實現。一般適用于所有類型的應用,比如 PHP、Python 等等。Redis 的實現方式可以支持分布式服務的訪問頻率的集中控制。Redis 的頻率限制實現方式還適用于在應用中無法狀態保存狀態的場景。
網上有眾多關于這方面的文章,這里列出了本文參考的一些文檔。
- http://www.cnblogs.com/mushroom/p/4659200.html
- 電商課題I:集群環境下業務限流
文章列表