AmazonWebServiceのELBは、とても簡単にサーバ分散化できる素晴らしいサービスなんだけど、ちょっとしたことに注意しないと、とんでもない目に遭う。というか、マニュアルとかにちゃんと書かれているから、読めよって話なんだけど。

AZ毎のEC2インスタンスは同じにする!

初めてELBを運用していた当初、どうもEC2インスタンスによってアクセスに偏りがあるな…と思ってたら、ELBはまず登録されているAZの数でトラフィックを分けて、その中から各EC2に振り分ける挙動だった。つまり、AZ_AにEC2が1個/AZ_BにEC2が10個あると、総トラフィックの約50%をAZ_AのEC2インスタンス1個が引き受けるという地獄に…。

マニュアルにも書かれています…。

着信トラフィックはロードバランサーで有効になっているすべてのアベイラビリティゾーン間で均等に負荷分散されるので、各ゾーンのインスタンス数をほぼ同等にすることが重要です。例えば、利用可能ゾーン us-east-1a に10個のインスタンス、利用可能ゾーン us-east-1b に2個のインスタンスがある場合でも、トラフィックは2つの利用可能ゾーン間で等分に分散されます。その結果、us-east-1b 内の2個のインスタンスは、us-east-1a 内の10個のインスタンスと同じ量のトラフィックを処理しなければならなくなります。ベストプラクティスとして、各利用可能ゾーンのインスタンス数を同等またはほぼ同等にすることをお勧めします。したがって、この例では、インスタンス数を us-east-1a で 10 個、us-east-1b で2個にする代わりに、各アベイラビリティゾーンのインスタンス数が 6 個になるようにインスタンスを分散します。

アベイラビリティーゾーンとリージョン

HTTPDサーバはKeepAlive + タイムアウト60秒以上にする

ELBは効率化のために、TCPセッションを使いまわして、各インスタンスとのコネクションを60秒維持するみたい。つまり、サーバ側で勝手に60秒以下でセッションを切ると、ELBは再接続を試みるという無駄が発生。なので、KeepAliveは有効にして、タイムアウトも60秒以上にすると良い。

HTTPS→HTTPでの場合、アプリケーションでSSL判定するにはX-Forwarded-Proto

SSLターミネーションを使っている場合「クライアント →(HTTPS)→ ELB →(HTTP)→ EC2」こんな形での接続ができる。

アプリケーション側で、HTTP接続かHTTPS接続かで挙動を変更する場合は結構あると思うが、この場合だとそれができない(PHPなら$_SERVER["HTTPS"]とかで見るが、HTTP接続になっているのでセットされない)。

でも、ELBは親切なのでX-Forwarded-Protoというヘッダを付けてくれる。これを見ればHTTPなのかHTTPSなのかが格納されているので判断することが可能になる。

EC2インスタンスのHTTPDサーバに記録されるクライアントIPはELBのIP

こちらは、ELBに限った話じゃないけど、ELB経由のアクセスは当然ながらELBのIPとして記録される。これらについては、別の記事で紹介済み。

nginx + ELBを使っていてアクセスログにELBのIPが記録されるのを防ぐ
ELBを使ってアクセス元のIPを取る方法