今日から GW だし,今まで試したことの無かった HAProxy に入門してみた.今回は複数台ある nginx に対してリクエストを分散させるだけで,初歩的な動作確認になっている.
環境
今さら Vagrant 環境を構築するのも面倒で,今回は Docker を使おうと思ったのと,せっかくなら Alpine Linux をベースにしたコンテナイメージにしてみようと思って haproxy:1.6.4-alpine
と nginx:stable-alpine
を選んだ.
kakakakakku/docker-haproxy-nginx
今回試したコードを GitHub に push しておいたー!
ドキュメント
- HAProxy - The Reliable, High Performance TCP/HTTP Load Balancer
- HAProxy Technologies | #1 Open Source Software Load Balancer and ADC
- HAProxy version 1.6.6 - Configuration Manual
docker-compose.yml
Docker Compose で4コンテナを起動して,HAProxy コンテナは :8080 で叩けるようにしている.各 Dockerfile は GitHub 参照でー.
version: '2' services: haproxy: build: ./haproxy/. ports: - '8080:8080' nginx1: build: ./nginx1/. nginx2: build: ./nginx2/. nginx3: build: ./nginx3/.
haproxy.cfg
特にチューニングなどはしてなく,シンプルな設定に留めている.Docker Compose で起動している nginx コンテナは nginx1 / nginx2 / nginx3 で参照できて,計3台に均等に負荷分散するようになっている.
global quiet defaults mode http maxconn 5000 timeout connect 5s timeout client 20s timeout server 20s frontend public bind *:8080 default_backend apps backend apps server nginx1 nginx1:80 check server nginx2 nginx2:80 check server nginx3 nginx3:80 check
リクエストを投げてみる
20回リクエストを投げるだけのサンプルスクリプト requests.sh
を用意してるので,実行してみると,ちゃんと負荷分散されていることがわかる.
$ sh ./requests.sh From nginx1 From nginx2 From nginx3 From nginx1 From nginx2 From nginx3 From nginx1 From nginx2 From nginx3 From nginx1 From nginx2 From nginx3 From nginx1 From nginx2 From nginx3 From nginx1 From nginx2 From nginx3 From nginx1 From nginx2
nginx ごとに重みを変えてみる
weight
オプションを付けることで負荷分散の重みを指定することができる.
backend apps server nginx1 nginx1:80 check weight 5 server nginx2 nginx2:80 check weight 2 server nginx3 nginx3:80 check weight 1
ただし,この weight は % ではなくあくまで相対的な回数の差と表現できる.ようするに上記の例だと,計8リクエストを受けると「5リクエスト / 2リクエスト / 1リクエスト」に分散される.
The "weight" parameter is used to adjust the server's weight relative to other servers. All servers will receive a load proportional to their weight relative to the sum of all weights, so the higher the weight, the higher the load. The default weight is 1, and the maximal value is 256. A value of 0 means the server will not participate in load-balancing but will still accept persistent connections. If this parameter is used to distribute the load according to server's capacity, it is recommended to start with values which can both grow and shrink, for instance between 10 and 100 to leave enough room above and below for later adjustments.
実際に試してみると確かにそうなっているし,さらに「1 / 1 / 2 / 1 / 1 / 3 / 1 / 2」という順番も維持されていることがわかる.
$ sh ./requests.sh From nginx1 From nginx1 From nginx2 From nginx1 From nginx1 From nginx3 From nginx1 From nginx2 From nginx1 From nginx1 From nginx2 From nginx1 From nginx1 From nginx3 From nginx1 From nginx2 From nginx1 From nginx1 From nginx2 From nginx1
nginx を1台落としてみる
weight
の設定を均等な負荷分散に戻した状態で,次は nginx3 を意図的に落としてからもう1度リクエストを投げてみる.
$ docker ps
$ docker kill 1fc13b25040a
ちゃんと nginx1 と nginx2 に負荷分散できていることがわかる.
$ sh ./requests.sh From nginx1 From nginx2 From nginx1 From nginx2 From nginx1 From nginx2 From nginx1 From nginx2 From nginx1 From nginx2 From nginx1 From nginx2 From nginx1 From nginx2 From nginx1 From nginx2 From nginx1 From nginx2 From nginx1 From nginx2
ちなみにこの check
オプションは重要で,定期的にヘルスチェックをして,もしコンテナが落ちたら自動的に負荷分散の対象から外してくれる.check
を付けないとリクエストを伝搬するときにコンテナが落ちてることに気付くため,スループットが落ちてしまう.
backend apps server nginx1 nginx1:80 check server nginx2 nginx2:80 check server nginx3 nginx3:80 check
まとめ
HAProxy を使うと簡単に ELB のようなロードバランサが立てられて便利だった.次のステップとしては haproxy.cfg
の設定を細かくチューニングしてみたり,MySQL Slave の負荷分散を試してみたり,HAProxy が SPOF にならないように冗長化してみたりを試していこうと思っている.
Alpine Linux を使ったメモ
nginx コンテナに直接 docker exec
で入って,nginx の動作確認をするときに curl すら入ってないことに気付いて,apk でインストールした.
/ # curl http://localhost /bin/sh: curl: not found / # apk --update add curl fetch http://dl-cdn.alpinelinux.org/alpine/v3.3/main/x86_64/APKINDEX.tar.gz fetch http://dl-cdn.alpinelinux.org/alpine/v3.3/community/x86_64/APKINDEX.tar.gz (1/4) Installing openssl (1.0.2g-r0) (2/4) Installing ca-certificates (20160104-r2) (3/4) Installing libssh2 (1.6.0-r1) (4/4) Installing curl (7.47.0-r0) Executing busybox-1.24.1-r7.trigger Executing ca-certificates-20160104-r2.trigger OK: 20 MiB in 26 packages / # curl http://localhost From nginx2
コンテナイメージのサイズも本当に小さくて流石 Alpine Linux だ!という感じだった.
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE dockerhaproxynginx_haproxy latest eacfa54ad6eb 44 minutes ago 10.65 MB dockerhaproxynginx_nginx1 latest a66698b79bc8 44 minutes ago 15.47 MB dockerhaproxynginx_nginx2 latest d788e5bc105a 44 minutes ago 15.47 MB dockerhaproxynginx_nginx3 latest 96872d46a7d8 44 minutes ago 15.47 MB