【AWS】ELB(Elastic Load Balancing)まとめ


どうも、iron千葉です。
ELBについて、ユーザガイドを見てポイントをまとめました。
ポイントだけ確認したい人、ざっと全体を見たい人におすすめです。

# ELBとは
* トラフィックを複数のインスタンスに分散する（オンプレでいうロードバランサー）
* ヘルスチェック機能を持っており、配下のインスタンスがヘルスチェックに失敗した場合、振り分けを停止する
* ヘルスチェックが回復した場合、振り分けを再開する
* 暗号化・復号化（SSL）機能を利用できる

# ELBのメリット
* 複数AZに対して分散を行える。１つのAZがオフラインになった場合でももう１つのAZで処理を続けられる
* 正常なインスタンスのみ振り分けを行える。異常なインスタンスには振り分けを停止する
* HTTPS/SSLを利用できる
* ユーザセッションを維持するスティッキーセッションをサポート
* セキュリティグループポリシーを適用でき、柔軟なセキュリティを実現できる

# ELBの仕組み
* ロードバランサーとコントローラーサービスの２つのコンポーネントで構成される
* インターネット経由で送信されたリクエストを処理
* 作成するロードバランサインスタンスに対して固有のDNS名を割り当てる（例：myLB-1234567890.us-east-1.elb.amazonaws.com）
* カスタムドメイン（www.example.comのような任意のドメイン）を利用できる。CNAMEでのエイリアスを利用
* DNSでドメイン名を解決すると、複数のグローバルIPアドレスが返される
* ELBが拡張されたり縮小すると応答するIPアドレスの数が変わる
* ELBではインスタンスに関連付けられたIPを利用してロードバランサに登録する
* ELBではヘルスチェックを行い、正常時：振り分けを行う、異常時：振り分けを行わない
* 同リージョンの、複数AZで負荷分散可能
* Auto Scalingを利用することにより、分散するEC2インスタンスをCPU等の閾値を超えた場合に、自動で増やすことができる

# ELBのコンポーネント

## ロードバランサー
* ユーザはロードバランサー宛にリクエストを発行する（ダイナミックなグローバルIPを持つ）
* ロードバランサは一意のDNS名を1つもつ
* 独自のドメイン名でユーザにアクセスさせたい場合は、DNSにCNAMEを登録する
* ロードバランサーが受け付けたリクエストは、EC2インスタンスへ分散する
* ロードバランサは、1つのリージョン内の複数AZに配置できる（複数AZに配置しても、DNS名は1つ）
* リージョン間でのリクエスト分散はできない
* ELBの前段で受け付けるプロトコル・ポート、後段へ転送するプロトコル・ポートはリスナーで設定する

## 複数AZに配置する場合の注意事項
* 可用性向上のため、EC2インスタンスを複数AZに配置する（AmazonのEC2のSLAは冗長構成が前提だったりする）
* 均等に分散するためには、各AZに同等のスペックのインスタンスとインスタンス数を配置する
* ↑の理由は、AZ間の振り分けはDNSラウンドロビンのため（AZ内での分散はリーストコネクション）

## ELBの分散方式
* AZ間はDNSラウンドロビン(クライアント側でDNSキャッシュを持っている場合、特定のAZにしかルーティングされなくなる可能性がある)
* AZ内はリーストコネクション※ただし、クロスゾーン負荷分散を有効にする場合は、AZ間でリーストコネクションでの分散ができる→各AZにインスタンスを均等に配置しなくても、均等に分散される
* ただし耐久性を高める（1つのAZが利用できなくなる場合を想定）には、各AZに均等にインスタンスを配置することを推奨
* まとめると：ユーザアクセス→DNS（ラウンドロビン）→ロードバランサ（リーストコネクション）→EC2

## EC2 インスタンスの負荷分散の設定
* インスタンスを作成したら、ロードバランサに登録する（プライベートIPアドレスを利用して登録される）※classic環境では、インスタンス停止・起動時にプライベートIPアドレスが変わるため、再度ELBに再登録する必要がある
* ELBはEC2インスタンスにヘルスチェック（httpリクエストの場合は200ok）をい、正常時に振り分けを実施する→ヘルスチェック用のURIを決めておく
* EC2インスタンスでキープアライブを有効にすることを推奨※TCPのハンドシェイクを省略できるので、サーバ・ネットワークの負荷低減
* キープアライブタイムアウトは、ELBの前段でのタイムアウト（デフォルト60秒）より長くする※ELB側で接続を閉じらるように

## ヘルスチェック
* EC2への定期的な正常性確認（正常時は振り分け、異常時は振り分けを実施しない）
* ヘルスチェック設定項目
	* ヘルスチェックプロトコル（TCP,HTTP,HTTPS,SSLから選択可能）
	* ポート接続（ポート番号）
	* HTTP/HTTPS選択時のURI（ヘルスチェックリクエストのパス）
	* 応答タイムアウト（応答が返ってくるまでの待ち時間）
	* ヘルスチェックの実施間隔
	* 異常時の閾値（何回連続で失敗した場合に異常とみなすか）
	* 正常時の閾値（何回連続で成功した場合に正常とみなすか）

## Connection Draining
* Connection Drainingを有効にした場合の挙動
	* ELBより、EC2インスタンスの切り離しを実施
	* 処理中のリクエストは処理を続ける
	* 新規リクエストは拒否する
	* 処理中のリクエストがタイムアウト時間待っても終了しない場合は、処理を破棄
	* 異常インスタンスへのonnection Drainingは適用されない（異常時はすぐ振り分けが中止される）

## アイドルタイムアウト
* クライアントがロードバランサにリクエストをした場合に、ロードバランサは2つの接続を持つ
	* 1つは、クライアントとロードバランサの接続
	* 2つは、ロードバランサとバックエンドの接続
* タイムアウトはデフォルト60秒
* 60秒の間にデータを受信しなかった場合、接続を閉じる

## スティッキーセッション
* スティッキーセッションを有効にすると、同じユーザからのリクエストを同じインスタンスに振り分けできる
* クッキーよりセッションを判別し、同じクッキーを持つユーザは同じインスタンスにルーティングされる
* アプリケーション独自のクッキーでのセッション維持、ELBでセットするクッキーによるセッション維持（期間ベース）の2パターンから選択できる

## ELBが受け付けるHTTPメソッド
* 標準（GET、POST、PUT、HEAD、OPTIONS）、標準外（PATCH、REPORT、MKCOL、PROPFIND、MOVE、LOCK）すべて受け付ける
* HTTPリクエスト受信時のELBの挙動
	* 誤った形式のリクエストがないかどうかをチェック
	* メソッドの長さをチェック

## HTTPSをサポート
* ELBに証明書(X.509)をアップロードすることで、リクエストの暗号化・複合化を実施できる
* IAMに証明書をアップロードし（証明書はIAMで管理）、利用する証明書を指定する

## Proxy Protocol
* バックエンドでアクセスログは、アクセス元はELBになる
* そのため、クライアントのIPアドレスはバックエンド側で取得できない
* Proxy Protocol を有効にすると、発信元 IP アドレス、送信先 IP アドレス、およびポート番号などの接続情報が含まれる、リクエストヘッダーが先頭に追加される
* バックエンドではヘッダーの先頭を解析することにより、クライアントの情報を取得できる

## X-Forwardedヘッダー
* ELBは標準以外のヘッダであるX-Forwardedをサポートする
* ELBはデフォルトで、X-Forwarded-ForにクライアントのIPアドレスを付加する

# インターネット向けロードバランサと内部向けロードバランサ
* VPCでELBを利用する場合、EIP付のELB（インターネットと通信可能）とEIP無のELB（VPC内のみで利用）を作成できる

# DNSフェイルオーバー
* DNSフェイルオーバーを利用し、リージョンレベルでのアプリケーションの冗長化ができる
* Route53にてステータスをチェックするELBを選び、フェイルオーバー先を選択する

# ELBのモニタリング
* CloudWatchメトリクスによりモニタリングできる
* ELBのアクセスログをS3へ保存するように設定できる（デフォルト無効）
* CloudTrailにて、ELBのAPI呼び出しを監査できる

# トラブルシューティング

## APIエラー
* 証明書作成直後は、リージョン伝達に時間がかかる→15分程度待ってから再度試行する

## ELBでのHTTPエラー
* HTTP 400: BAD_REQUEST→クライアントが無効なリクエストを送信
* HTTP 405: METHOD_NOT_ALLOWED→メソッドの長さが無効
* HTTP 408: Request Timeout→クライアントがリクエストをキャンセルしたか、リクエスト全体の送信に失敗
* HTTP 502: Bad Gateway→登録されたインスタンスから送信された応答をロードバランサーが解析できなかった
* HTTP 503: Service Unavailable または HTTP 504: Gateway Timeout→ロードバランサーまたは登録されたインスタンスが原因でエラー
	* ロードバランサがリクエストを処理する能力が不足している（ELBのスケールが追い付いていない→時間が経過するとおさまる）

# その他TIPS
* 有料AMIを利用時に、Amazon DevPayから起動された場合はELBを利用できない
* ELBは自動でスケールするが、急に負荷が高くなった場合はスケールが追い付かずエラーを返す場合がある
	* 事前に負荷をかけてスケールさせておく
	* または、Pre-warmingをAmazon側に申請する
	* 利用するAZの数を増やす