昨天有講到怎麼運用 nginx 來做基本的分流、限流,但因為昨天舉的例子比較簡單,真實世界的應用可能會更複雜,所以今天要針對限流的部分講一些真實世界可能會遇到的例子~
就如前天提到的,既然每個 API endpoint 要做的事情不一樣,所需要的資源(CPU、時間、$$$)也會不同,所以針對所有 API 都做相同的流量限制顯然不太合理,應該要針對高成本的 API(如發手機驗證簡訊、重設密碼等等)做更嚴格的流量限制
那具體而言要怎麼做呢?首先是你可以一次宣告多個 zone,譬如說用來限制「發送手機驗證簡訊」的 limit_verifyPhone
、限制「重設密碼」 limit_resetPassword
等等,接著根據他們的 API 路徑把套用上去
http {
limit_req_zone $binary_remote_addr zone=limit_verifyPhone:10m rate=2r/m;
limit_req_zone $binary_remote_addr zone=limit_resetPassword:10m rate=1r/m;
server {
location /api/verifyPhone {
limit_req zone=limit_verifyPhone;
proxy_pass http://backend;
}
location /api/resetPassword {
limit_req zone=limit_resetPassword;
proxy_pass http://backend;
}
}
}
因為 nginx 會從最長的路徑開始匹配(路徑越長優先權越高),因此如果有 /api/resetPassword
或 /api/verifyPhone
的請求進來,就會直接被對應的 location
抓走,也就會受到 limit_resetPassword
或 limit_verifyPhone
的限制。反之如果不是這兩個路徑,那才會被優先權最低的 location /api
給撿走,沒有經過任何流量限制就直接轉發到後端伺服器
了解怎麼對不同 endpoint 做限制後,接著我們來探討另外一個問題:你希望過量的請求是先被 queue 起來待會再處理?還是直接拒絕掉?
這問題其實沒有標準答案,端看你的需求。如果你希望所有請求最後都能成功被處理,就算多等一下也無所謂,那就可以先 queue 起來;反之如果你擔心一下子來太多請求會無法在短時間內處理完,那就可以先把過量的請求拒絕掉,讓 client 端知道他發太多請求了。不過不管你想要的是哪一種處理方式,nginx 都可以幫你做到,只不過沒特別設定的話 nginx 預設行為是把過量的請求直接拒絕掉。
那如果想要把過量的請求 queue 起來的話,應該要怎麼設定呢?很簡單,只要在 limit_req
的結尾加上 burst=<queue size>
就可以了。假如你設定的限流是「每分鐘最多 100 個請求」,而且設定 burst=200
,在這情況下一分鐘內突然來了 300 個請求,那 nginx 就會把前 200 個請求以「平均每分鐘一百個的速度」慢慢推送給 API server,至於那多出來的 100 個過量請求就直接跟他們 say goodbye
http {
limit_req_zone $binary_remote_addr zone=limit_verifyPhone:10m rate=3r/m;
limit_req_zone $binary_remote_addr zone=limit_resetPassword:10m rate=1r/m;
server {
location /api/verifyPhone {
# 如果一下子來太多電話認證的請求,就先 queue 起來慢慢處理,避免一下子發出太多簡訊
limit_req zone=limit_verifyPhone burst=5;
proxy_pass http://backend;
}
location /api/resetPassword {
limit_req zone=limit_resetPassword;
proxy_pass http://backend;
}
}
}
而根據使用情境不同,你也可以只挑部分 API 設定 burst,像上面的例子就只有在 /api/verifyPhone
設定 burst=5
,如果來的是大量 /api/resetPassword
的請求,那還是會直接被回絕掉
今天對於 nginx 限流的部分講了一些更複雜的例子,相信大家看到這邊應該都更了解怎麼在 nginx 做限流了,但關於 nginx burst 的部分還沒完全講完,明天還會做一些小補充。如果對於今天的內容有什麼問題歡迎在下方留言,都沒問題的話就明天見囉~