Ashigaruコンピューター道

ソフトウェアの話とか、キャリアの話とか

nginxによるアクセス制御に関して調べてみた

業務でアクセス制御する必要があったので、どのような解決策があるかを調べてみた。


要件

ある外部システムをWebAPIで叩いて連携する必要があるが、そのシステムはURLごとに2req/sしか叩かれないように制御したい。

例えば
/searchと/user はそれぞれに2req/sになるように制御したい。

この要件を聞いてみて使えそうかな?とおもったnginx調べてみた。

nginx

http limit req moduleでいけるか調べてみる。
ある$keyごとに1req/secondなど柔軟に処理できそうなので、URLごとにリクエストを制御できるかテストしてみる。

検証環境はmac
index.htmlを / と /testの2つに用意
mkdir /usr/local/var/www/test
cp /usr/local/var/www/index.html /usr/local/var/www/test
そこに$uriごとにアクセス制限をかける以下を追加

http {
    limit_req_zone $uri zone=one:10m rate=2r/s;

    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/access.log  main;

    sendfile        on;

    keepalive_timeout  65;

    server {
        limit_req zone=one burst=5;
        listen       8080;
        server_name  localhost;

        location / {
            root   html;
            index  index.html index.htm;
        }

設定完了したので、nginx再起動。

sudo nginx -s reload

そしてアクセスログを見守りつつ、/ と /testにpararel 4,  request数12で飛ばす。
ab -n 12 -c 4 http://127.0.0.1:8080/index.html & ab -n 12 -c 4 http://127.0.0.1:8080/test/index.html
するとアクセスログは以下のように同じ秒間にはuriごとに2リクエストしかさばいてないので、nginxの方でよしなに遅延させて処理してくれた模様。
[01/May/2017:00:31:23 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:23 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:23 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:24 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:24 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:24 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:24 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:25 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:25 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:25 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:25 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" [01/May/2017:00:31:26 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:26 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:26 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:26 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:27 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:27 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:27 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:27 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:28 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:28 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:28 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:28 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
秒間をこえたリクエストを遅延して処理するかどうかはburstが決めているのでそれをいじってエラーにしてみる。

十分これで目的を達成できそうな気がするな。