參考文章:
https://juejin.im/post/5ec1dd5f5188256d77633faf?utm_source=gold_browser_extension
1.限流分類
- 合法性驗證限流:比如驗證碼、IP 黑名單等,這些手段可以有效的防止惡意攻擊和爬蟲採集;
- 容器限流:比如 Tomcat、Nginx 等限流手段,其中 Tomcat 可以設置最大線程數(maxThreads),當併發超過最大線程數會排隊等待執行;而 Nginx 提供了兩種限流手段:一是控制速率,二是控制併發連接數;
- 服務端限流:比如我們在服務器端通過限流算法實現限流,此項也是我們本文介紹的重點。
合法性驗證限流爲最常規的業務代碼,就是普通的驗證碼和 IP 黑名單系統,本文就不做過多的敘述了,我們重點來看下後兩種限流的實現方案:容器限流和服務端限流。
tomcat限流:
Tomcat 8.5 版本的最大線程數在 conf/server.xml 配置中,如下所示:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
maxThreads="150"
redirectPort="8443" />
其中 maxThreads 就是 Tomcat 的最大線程數,當請求的併發大於此值(maxThreads)時,請求就會排隊執行,這樣就完成了限流的目的。
小貼士:maxThreads 的值可以適當的調大一些,此值默認爲 150(Tomcat 版本 8.5.42),但這個值也不是越大越好,要看具體的硬件配置,需要注意的是每開啓一個線程需要耗用 1MB 的 JVM 內存空間用於作爲線程棧之用,並且線程越多 GC 的負擔也越重。最後需要注意一下,操作系統對於進程中的線程數有一定的限制,Windows 每個進程中的線程數不允許超過 2000,Linux 每個進程中的線程數不允許超過 1000。
Nginx 提供了兩種限流手段:一是控制速率,二是控制併發連接數。
控制速率
我們需要使用 limit_req_zone 用來限制單位時間內的請求數,即速率限制,示例配置如下:
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=2r/s;
server {
location / {
limit_req zone=mylimit;
}
}
以上配置表示,限制每個 IP 訪問的速度爲 2r/s,因爲 Nginx 的限流統計是基於毫秒的,我們設置的速度是 2r/s,轉換一下就是 500ms 內單個 IP 只允許通過 1 個請求,從 501ms 開始才允許通過第 2 個請求。
速率限制升級版
上面的速率控制雖然很精準但是應用於真實環境未免太苛刻了,真實情況下我們應該控制一個 IP 單位總時間內的總訪問次數,而不是像上面那麼精確但毫秒,我們可以使用 burst 關鍵字開啓此設置,示例配置如下:
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=2r/s;
server {
location / {
limit_req zone=mylimit burst=4;
}
}
控制併發數
利用 limit_conn_zone 和 limit_conn 兩個指令即可控制併發數,示例配置如下:
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;
server {
...
limit_conn perip 10;
limit_conn perserver 100;
}
其中 limit_conn perip 10 表示限制單個 IP 同時最多能持有 10 個連接;limit_conn perserver 100 表示 server 同時能處理併發連接的總數爲 100 個。
只有當 request header 被後端處理後,這個連接才進行計數。
服務端限流
服務端限流需要配合限流的算法來執行,而算法相當於執行限流的“大腦”,用於指導限制方案的實現。
有人看到「算法」兩個字可能就暈了,覺得很深奧,其實並不是。算法就相當於操作某個事務的具體實現步驟彙總,其實並不難懂,不要被它的表象給嚇到哦~
限流的常見算法有以下三種:
- 時間窗口算法
- 漏桶算法
- 令牌算法