大規模コンテンツ配信のテクニックとして、以前
- コンテンツのキャッシュ化
- ロードバランスでのアクセス負荷分散
を検証した
今回は、これらの2つを組み合わせてより負荷に耐えうる構成について検証したい
構成イメージ
流れは
- ロードバランサがアクセスの一次受けをして、配下のキャッシュサーバ群にリバースプロキシする
- キャッシュサーバは自身にキャッシュが残されていればそれを返し、ない場合はオリジンサーバ郡にリバースプロキシする(自身もロードバランサとして機能しているのでオリジンサーバに対するアクセスを負荷分散している)
- オリジンサーバはキャッシュサーバよりアクセスされた場合に対応するリソースを返す
となってる
この構成でキャッシュサーバのキャッシュがない場合にはオリジンサーバにアクセスされるが、そのアクセスもロードバランスによって負荷分散されているためオリジンサーバ一台にかかる負荷は大分抑えられるでしょうよ、と
構築
例に違わずDockerで構築したんで、ソースの細かい構成とかはこっちを参照してほしい(https://github.com/smithshiro/nginx_load_balancer_v2)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
$ tree . ├── README.md ├── docker │ ├── cache_nginx │ │ ├── Dockerfile │ │ └── default.conf │ ├── load_balancer_nginx │ │ └── default.conf │ └── origin_nginx │ └── default.conf ├── docker-compose.yaml └── src ├── css │ ├── main.css │ └── reset.css ├── image │ └── sample.jpg └── index.html |
まあ、フォルダ構成はこんなだけどさ
docker-compose.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
version: '3' services: load_balancer_nginx: image: nginx:latest volumes: - ./docker/load_balancer_nginx/default.conf:/etc/nginx/conf.d/default.conf ports: - 10088:80 depends_on: - cache1_nginx - cache2_nginx - cache3_nginx cache1_nginx: build: ./docker/cache_nginx volumes: - ./docker/cache_nginx/default.conf:/etc/nginx/conf.d/default.conf depends_on: - origin1_nginx - origin2_nginx - origin3_nginx cache2_nginx: build: ./docker/cache_nginx volumes: - ./docker/cache_nginx/default.conf:/etc/nginx/conf.d/default.conf depends_on: - origin1_nginx - origin2_nginx - origin3_nginx cache3_nginx: build: ./docker/cache_nginx volumes: - ./docker/cache_nginx/default.conf:/etc/nginx/conf.d/default.conf depends_on: - origin1_nginx - origin2_nginx - origin3_nginx origin1_nginx: image: nginx:latest volumes: - ./docker/origin_nginx/default.conf:/etc/nginx/conf.d/default.conf - ./src:/var/www/html origin2_nginx: image: nginx:latest volumes: - ./docker/origin_nginx/default.conf:/etc/nginx/conf.d/default.conf - ./src:/var/www/html origin3_nginx: image: nginx:latest volumes: - ./docker/origin_nginx/default.conf:/etc/nginx/conf.d/default.conf - ./src:/var/www/html |
load_balancer_nginxのdepends_onがcache*_nginxになってて
cache*_nginxのdepends_onがorigin*_nginxになってて
プロジェクトのソースコードはorigin*_nginxに入っているのがポイント
docker/load_balance_nginx/default.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
upstream caches { consistent_hash $scheme$proxy_host$request_uri; server cache1_nginx:80 weight=1; server cache2_nginx:80 weight=1; server cache3_nginx:80 weight=1; } server { listen 80; server_name localhost; access_log /var/log/nginx/access.log; location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Conection ""; proxy_set_header Host $http_host; proxy_http_version 1.1; proxy_pass http://caches; } } |
upstreamディレクティブでロードバランスを可能にして、そのグループがキャッシュサーバ郡になってる
consistent_hashディレクティブによって、同じアクセスURIは同じキャッシュサーバに向くらしいが、ちょっとよくわかってない
proxy_set_headerはオマジナイみたいなもの
docker/cache_nginx/default.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
upstream origins { server origin1_nginx:80 weight=1; server origin2_nginx:80 weight=1; server origin3_nginx:80 weight=1; } proxy_cache_path /var/lib/nginx/cache/nginx levels=1 keys_zone=cache:4M inactive=1d max_size=100M; proxy_temp_path /var/lib/nginx/cache/nginx_temp; server { listen 80; access_log /var/log/nginx/access.log; location / { proxy_cache cache; proxy_pass http://origins; proxy_cache_key "$scheme://$host$request_uri$is_args$args"; proxy_cache_valid 7d; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Conection ""; proxy_set_header Host $http_host; proxy_http_version 1.1; add_header X-Cache-Status $upstream_cache_status; } } |
proxy_cache_pathでキャッシュの保存場所を指定して、キャッシュがヒットすればそこに保存されてるキャッシュを返し、存在しなかったらupstreamで指定しているオリジンサーバ群にアクセスを分散して流すようにしている
proxy_cache_validでキャッシュを無効になるまでの期間を指定しているぞ
docker/origin_nginx/default.conf
1 2 3 4 5 6 7 8 9 10 |
server { listen 80; access_log /var/log/nginx/access.log; root /var/www/html; expires 7d; location / { index index.html; } } |
まあ、いつものやな
ここでのexpiresで指定された期間がブラウザのキャッシュの有効期間になるようだ
・・なんか今回むずいな
とりあえず、立ち上げてアクセスしてみよう
検証
curlコマンドで確かめるぜ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
$ curl -svo /dev/null http://localhost:10088 * Rebuilt URL to: http://localhost:10088/ * Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 10088 (#0) > GET / HTTP/1.1 > Host: localhost:10088 > User-Agent: curl/7.58.0 > Accept: */* > < HTTP/1.1 200 OK < Server: nginx/1.19.2 < Date: Sun, 22 Nov 2020 09:54:17 GMT < Content-Type: text/html < Content-Length: 585 < Connection: keep-alive < Last-Modified: Sun, 22 Nov 2020 07:41:49 GMT < ETag: "5fba163d-249" < Expires: Tue, 22 Dec 2020 09:54:17 GMT < Cache-Control: max-age=2592000 < X-Cache-Status: MISS < Accept-Ranges: bytes < { [585 bytes data] * Connection #0 to host localhost left intact |
キャッシュはMISS
1 2 3 4 |
$ docker-compose logs -f origin1_nginx_1 | 172.30.0.7 - - [22/Nov/2020:10:00:40 +0000] "GET / HTTP/1.1" 200 585 "-" "curl/7.58.0" load_balancer_nginx_1 | 172.30.0.1 - - [22/Nov/2020:10:00:40 +0000] "GET / HTTP/1.1" 200 585 "-" "curl/7.58.0" cache1_nginx_1 | 172.30.0.8 - - [22/Nov/2020:10:00:40 +0000] "GET / HTTP/1.0" 200 585 "-" "curl/7.58.0" |
ロードバランスー>キャッシュサーバー>オリジンサーバってアクセスしてるっぽい
オリジンからリソースを取りに行っているのがわかるね
もう一回実行
1 2 3 4 5 6 |
origin1_nginx_1 | 172.30.0.7 - - [22/Nov/2020:10:00:40 +0000] "GET / HTTP/1.1" 200 585 "-" "curl/7.58.0" load_balancer_nginx_1 | 172.30.0.1 - - [22/Nov/2020:10:00:40 +0000] "GET / HTTP/1.1" 200 585 "-" "curl/7.58.0" cache1_nginx_1 | 172.30.0.8 - - [22/Nov/2020:10:00:40 +0000] "GET / HTTP/1.0" 200 585 "-" "curl/7.58.0" origin1_nginx_1 | 172.30.0.6 - - [22/Nov/2020:10:00:46 +0000] "GET / HTTP/1.1" 200 585 "-" "curl/7.58.0" cache2_nginx_1 | 172.30.0.8 - - [22/Nov/2020:10:00:46 +0000] "GET / HTTP/1.0" 200 585 "-" "curl/7.58.0" load_balancer_nginx_1 | 172.30.0.1 - - [22/Nov/2020:10:00:46 +0000] "GET / HTTP/1.1" 200 585 "-" "curl/7.58.0" |
うーん、cache1_nginxに行ってほしんだけどcache2_nginxに行ってしまっているね
当然、キャッシュヒットもMISS
もう一回実行したら今度はcache3_nginxに行った
4度目の正直
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
$ curl -svo dev/null http://localhost:10088 * Rebuilt URL to: http://localhost:10088/ * Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 10088 (#0) > GET / HTTP/1.1 > Host: localhost:10088 > User-Agent: curl/7.58.0 > Accept: */* > < HTTP/1.1 200 OK < Server: nginx/1.19.2 < Date: Sun, 22 Nov 2020 10:02:39 GMT < Content-Type: text/html < Content-Length: 585 < Connection: keep-alive < Last-Modified: Sun, 22 Nov 2020 07:41:49 GMT < ETag: "5fba163d-249" < Expires: Tue, 22 Dec 2020 10:00:40 GMT < Cache-Control: max-age=2592000 < X-Cache-Status: HIT < Accept-Ranges: bytes < { [585 bytes data] * Failed writing body (0 != 585) * stopped the pause stream! * Closing connection 0 |
Hit!!
1 2 3 4 5 6 7 8 9 10 11 |
origin1_nginx_1 | 172.30.0.7 - - [22/Nov/2020:10:00:40 +0000] "GET / HTTP/1.1" 200 585 "-" "curl/7.58.0" load_balancer_nginx_1 | 172.30.0.1 - - [22/Nov/2020:10:00:40 +0000] "GET / HTTP/1.1" 200 585 "-" "curl/7.58.0" cache1_nginx_1 | 172.30.0.8 - - [22/Nov/2020:10:00:40 +0000] "GET / HTTP/1.0" 200 585 "-" "curl/7.58.0" origin1_nginx_1 | 172.30.0.6 - - [22/Nov/2020:10:00:46 +0000] "GET / HTTP/1.1" 200 585 "-" "curl/7.58.0" cache2_nginx_1 | 172.30.0.8 - - [22/Nov/2020:10:00:46 +0000] "GET / HTTP/1.0" 200 585 "-" "curl/7.58.0" load_balancer_nginx_1 | 172.30.0.1 - - [22/Nov/2020:10:00:46 +0000] "GET / HTTP/1.1" 200 585 "-" "curl/7.58.0" origin1_nginx_1 | 172.30.0.5 - - [22/Nov/2020:10:02:31 +0000] "GET / HTTP/1.1" 200 585 "-" "curl/7.58.0" load_balancer_nginx_1 | 172.30.0.1 - - [22/Nov/2020:10:02:31 +0000] "GET / HTTP/1.1" 200 585 "-" "curl/7.58.0" cache3_nginx_1 | 172.30.0.8 - - [22/Nov/2020:10:02:31 +0000] "GET / HTTP/1.0" 200 585 "-" "curl/7.58.0" cache1_nginx_1 | 172.30.0.8 - - [22/Nov/2020:10:02:39 +0000] "GET / HTTP/1.0" 200 585 "-" "curl/7.58.0" load_balancer_nginx_1 | 172.30.0.1 - - [22/Nov/2020:10:02:39 +0000] "GET / HTTP/1.1" 200 585 "-" "curl/7.58.0" |
cache1_nginxでとどまってくれてるね
今のところは同じURLを叩いたらキャッシュサーバの数だけはオリジンにアクセスする感じだけど、ちゃんとコンテンツキャッシュとアクセス分散はできてそうだな
疲れた、これぐらいにしよう
まとめ
- Nginxでは大規模コンテンツ配信をコンテンツキャッシュやロードバランサを使って、オリジンサーバへの負荷を減らすことが可能である
- ロードバランスではupstream、コンテンツキャッシュではproxy_passを必ず使う(その他も色々必要だが)
nginxを現場で活用するための知識を、実践的なノウハウを交えて解説した書籍です。
nginxのインストール方法や基本的な設定方法からはじめ、nginxを利用した「静的コンテンツ配信サーバ」「HTTPSサーバ」「Webアプリケーションサーバ」「大規模コンテンツ配信システム」の構築方法をそれぞれ詳しく紹介しています。後半ではnginxサーバのモニタリングやログの収集、そして軽量スクリプト言語Luaでnginxを拡張する方法について解説しているので、nginxをこれから使う方はもちろん、さらに活用したい方にもお勧めです。