iT邦幫忙

2021 iThome 鐵人賽

DAY 7
3
Security

從以卵擊石到堅若磐石之 Web API 安全性全攻略系列 第 7

Day07-流量限制(二)

前言

昨天介紹了在 Node.js 跟 Go 裡面要怎麼用 middleware 來做限流,雖然看似方便,但這樣做其實不是個好方法,因為限制流量並不是業務邏輯的一部分。而且如果同時開了多台機器跑 Node/Go server 做分流,因為預設情況下統計次數是儲存在各 process 自己的記憶體中,在不知道其他 process 的請求數量的情況下,就沒辦法做到真正的限流

load balancer

所以如果你不是寫個 side project 玩玩而已,而是真的要上 production,那比較好的方式是由前面的 load balancer 來做分流及限流,如果某個 IP 在時間內的流量已經超標了,那就不要再往後送到 API server,如此一來不只可以節省資源,後面的 API server 也不需要考慮流量有沒有超過,反正請求來了趕快處理便是

基本的 load balancer

在眾多用來做 reverse proxy 的工具中,nginx 應該是最多人在用的,所以這邊先示範一下怎麼用 nginx 做簡單的分流

一般來說我們要用 nginx 做分流時,會先宣告一個 upstream 叫 backend,並在裡面寫上可以把流量分配到哪些 server。緊接著再到 location /api 裡面把所有流量都用 proxy_pass 轉送到多台 API server,如此一來外來的請求就會被平均分散到各台 server 做處理

http {    
    # 告訴 nginx 有三台 API server 可以接受流量
    upstream backend {
        server 192.0.0.1:8000;
        server 192.0.0.2:8000;
        server 192.0.0.3:8000;
    }

    server {
        listen 80;
        
        location /api {
            # 把所有流量都轉送到 backend 的三台 server
            proxy_pass http://backend;
        }
    }
}

加上限流

有這個基本的分流之後,要怎麼在這個設定檔加上限流的功能呢?

首先要用 limit_req_zone 宣告一個新的 limiter,他這邊的參數有點複雜,我稍微解釋一下:

  • $binary_remote_addr 指的是 client 端的 IP,意思是我想要根據 client 端的 IP 進行限流
  • zone=limit:10m 的意思是我這個 limiter(zone) 要叫做 limit,並且最多可以使用 10MB 的 memory 來儲存每個 IP 的請求次數(10MB 可以存十幾萬個 IP,一定夠用的~)
  • rate=100r/m 還滿直觀的,就每分鐘一百個請求。但要注意的是 nginx 會幫你換算成多少毫秒可以接受一個新請求,譬如說每分鐘一百個,他就會幫你換算成 600 毫秒一個,因此如果你在 600 毫秒內同時發了十個請求,那就只有第一個會被接受,其他九個都會直接被拒絕掉

有了這個 limiter 之後,只要再到 location /api 裡面用 limit_req zone=limit 把他套用上去就可以了~

http {
    # 宣告一個 limiter(zone) 叫 limit,限制每分鐘最多 100 個請求
    limit_req_zone $binary_remote_addr zone=limit:10m rate=100r/m;
    
    # 拒絕請求時的 status code 用 429 Too Many Requests
    limit_req_status 429;

    server {
        location /api {
            # 把剛剛宣告好的 limit 套用到 /api 開頭的請求上
            limit_req zone=limit;
            proxy_pass http://backend;
        }
    }
}

如此一來,每當有 /api 開頭的請求進來時,nginx 就會根據你設定的上限幫你做限流,而後端的 API server 們也只需要認真處理請求,不用管前端有多少請求想要進來,非常完美的分工合作~

小結

今天介紹了如何在 nginx 裡面做分流及限流,因為大部分的服務在 production 上通常不會只有一台機器,所以直接在 nginx 把這些事情做好會讓程式寫起來更簡單,也是業界很常用的做法哦~

關於今天的內容有問題歡迎在下方留言,沒問題的話明天會繼續講一些更進階的限流方式,就這樣,明天見囉~


上一篇
Day06-流量限制(一)
下一篇
Day08-流量限制(三)
系列文
從以卵擊石到堅若磐石之 Web API 安全性全攻略30

尚未有邦友留言

立即登入留言