はじめに
前回 ELB を構築した際に「ありゃ?」と思ったのが AZ 間でバランシングが偏っているような現象が見られたので改めて検証してみることにする。ちなみに、涙の自腹アカウントで検証する。*1
とりあえず構築
構成図
以下のような構成。

ELB の構築
ELB の構築は下記のコマンドで一発。
aws elb create-load-balancer \ --load-balancer-name hugahuga \ --listeners Protocol=HTTP,LoadBalancerPort=80,InstanceProtocol=HTTP,InstancePort=8080 \ --subnets "subnet-123456a" "subnet-123456b" \ --security-groups sg-123456
インスタンスの構築
以下のようなシェルスクリプトで一発作成。
#!/bin/bash SUBNETS=(subnet1 subnet2) USERDATA="file://path/to/file" KEY="Your Key" AMI="AMI id" SECURITY_GROUP="Your Security Key" for i in `seq 1 2` do for SUBNET in ${SUBNETS[@]} do id=`aws ec2 run-instances \ --image-id ${AMI} \ --count 1 \ --instance-type t1.micro \ --key-name ${KEY} \ --security-group-ids ${SECURITY_GROUP} \ --subnet-id ${SUBNET} \ --associate-public-ip-address \ --user-data ${USERDATA} | jq '.Instances[]|.InstanceId' | sed 's/"//g'` # regist to tag aws ec2 create-tags --resources $id --tags Key=Name,Value=param${i} echo ${id} done done
このスクリプトで VPC 内の AZ にそれぞれ 2 台ずつインスタンスが構築される。
インスタンスを ELB に登録する
aws elb register-instances-with-load-balancer \ --load-balancer-name hugahuga \ --instances i-123456a i-123456b i-123456c i-123456d
とりあえずこれで ELB の環境は構築だん。暫く時間を置くと以下のようにしてアクセスするとインスタンスのホスト名が返ってくるようになる。
curl "http://hugahuga-123456789.ap-northeast-1.elb.amazonaws.com/"
ELB 配下に 4 インスタンスがいるのでランダムに 4 インスタンス分が返ってくるはず...。

なんだかおかしい...。
調査と結果
調査
あらかじめインスタンスのホスト名と AZ を控えておいて、以下のようなスクリプトを書いて、まずは OS X Mavericks 上で実験。
#!/bin/bash a=`curl -sv "http://hugahuga-209690661.ap-northeast-1.elb.amazonaws.com/"` case $a in ip-10-0-0-38 ) echo "ap-northeast-1a" ;; ip-10-0-1-66 ) echo "ap-northeast-1c" ;; ip-10-0-0-136 ) echo "ap-northeast-1a" ;; ip-10-0-1-114 ) echo "ap-northeast-1c" ;; esac
実行すると以下のように出力される。
* Adding handle: conn: 0x7f8349004000
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x7f8349004000) send_pipe: 1, recv_pipe: 0
* About to connect() to hugahuga-12345678900.ap-northeast-1.elb.amazonaws.com port 80 (#0)
* Trying 54.250.131.xxx...
* Connected to hugahuga-12345678900.ap-northeast-1.elb.amazonaws.com (54.250.131.xxx) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.30.0
> Host: hugahuga-12345678900.ap-northeast-1.elb.amazonaws.com
> Accept: */*
>
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Content-Type: text/html
< Date: Sat, 11 Jan 2014 04:29:23 GMT
< ETag: "52d0ad03-e"
< Last-Modified: Sat, 11 Jan 2014 02:31:31 GMT
* Server nginx/1.4.3 is not blacklisted
< Server: nginx/1.4.3
< Content-Length: 14
< Connection: keep-alive
<
{ [data not shown]
* Connection #0 to host hugahuga-12345678900.ap-northeast-1.elb.amazonaws.com left intact
ap-northeast-1c
何度実行しても ap-northeast-1c が返ってくる。次に AWS 上の ELB 配下ではないインスタンスから同じスクリプトを実行すると...
< 略 >
* About to connect() to hugahuga-12345678900.ap-northeast-1.elb.amazonaws.com port 80 (#0)
* Trying 54.250.161.yyy...
* Connected to hugahuga-12345678900.ap-northeast-1.elb.amazonaws.com (54.250.161.57) port 80 (#0)
< 略 >
{ [data not shown]
* Connection #0 to host hugahuga-12345678900.ap-northeast-1.elb.amazonaws.com left intact
ap-northeast-1a
< 略 >
* About to connect() to hugahuga-12345678900.ap-northeast-1.elb.amazonaws.com port 80 (#0)
* Trying 54.250.131.xxx...
* Connected to hugahuga-12345678900.ap-northeast-1.elb.amazonaws.com (54.250.131.173) port 80 (#0)
< 略 >
{ [data not shown]
* Connection #0 to host hugahuga-12345678900.ap-northeast-1.elb.amazonaws.com left intact
ap-northeast-1c
上記のように期待した通りに AZ 間でバランシング出来ているように見える。よく見ると hugahuga-12345678900.ap-northeast-1.elb.amazonaws.com の IP が複数返ってきている...ということは ELB を作成した際に生成される DNS Name は DNS ラウンドロビンされているようだ。ということは手元の環境(OS X Mavericks)でアクセスが偏ったように見えているのは単に DNS のキャッシュが原因であることが濃厚。
ということで
後始末
以下のように ELB を削除してインスタンスも削除する。
aws elb delete-load-balancer --load-balancer-name hogehuga
インスタンスも Terminate する。
aws ec2 describe-instances --filters "Name=tag-value,Values=elb*" | jq '.Reservations[].Instances[]|.InstanceId'
上記のようにインスタンスの id を確認して...
aws ec2 terminate-instances --instance-ids ${インスタンス ID}
として Terminate していく。Terminate すると...
{ "TerminatingInstances": [ { "InstanceId": "i-123456a", "CurrentState": { "Code": 32, "Name": "shutting-down" }, "PreviousState": { "Code": 16, "Name": "running" } } ] }
上記のようなレスポンスが返ってくる。
課金の結果...
