話題の記事

もっとELB(Elastic Load Balancing)を活用する

2015.02.04

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

みんな大好きElastic Load Balancing(以下ELB)は利用にあたっては細かい仕様に注意する必要があります。 2014年ELBにお世話になった人もそうでない人も2015年はもっとELBを活用するために、改めてELBの仕様や活用方法を振り返ってみましょう。

※本稿の内容の多くは一度でもELBを使ったことがある方を想定しています。

ELBが得意なところ

ELBはコスト効果良く高い可用性と拡張性をもつロードバランサーをサービスとして提供してくれるので、最初に利用するロードバランサーとしても、長く使うロードバランサーとしても優秀です。 ELBを活用するためのドキュメントがAWSから公開されています。未読の方は必ず目を通しておきましょう。

Best Practices in Evaluating Elastic Load Balancing

ELBが苦手なところ

ELBを利用する上で気をつけなければならない点は2012年からさほど変わっていないので改めて確認します。 以下のブログがよくまとまっているので、こちらをベースにお話します。

Dissecting Amazon ELB : 18 things you should know

2015年2月現在でELBが苦手なことは以下のとおりです。

  • サイトキャッシュ
  • スパイク(フラッシュ)トラフィックへの対応
  • 固定IP
  • Multi-Regionロードバランス
  • L7ベースロードバランス

逆に対応された内容は以下のとおりです。

  • 任意のコネクションタイムアウト
  • アクセスログ
  • Graceful connection termiante

ELBがいわゆるアプライアンス型のロードバランサーやHAProxyなどと明確に異なるのは、単純なロードバランス機能のみを提供している点です。 キャッシュやより細やかなロードバランスは別のコンポーネント(例えばVarnish、Nginx、BIG-IP等)に任せる必要があります。 また、ELBはゆるやかにトラフィックが変化するシステム向けにデザインされていますので、ピークトラフィックがスパイク傾向にあるシステムでは後述のスケーラビリティ、pre-warmを参照ください。

価格

東京リージョン(ap-northeast-1)の場合、価格は以下のとおりです。※2015年2月現在

Elastic Load Balancing Pricing

  • $0.027 per Elastic Load Balancer-hour (or partial hour)
  • $0.008 per GB of data processed by an Elastic Load Balancer

ELBの規模によらず、ELB1つ1時間あたり$0.027なので、1ヶ月間(仮に732時間とします)使い続けると、$19.764/月です。 AWSアカウントがアクティブになってから最初の1年間は毎月750時間分のELB無料枠があるので、ELB経由のトラフィックがクライアント向けの配信メインの場合は使わない理由はありません。 EC2とELBの間の通信はPrivateIPを用いている場合は無料なので、VPC環境であればELBを利用した場合の通信費用はIN/OUTの合計転送データ量(GB) x $0.008/GBとなります。

スケーラビリティ

ELBはEC2ベースの分散システム(後述のIPアドレスレンジがEC2のものになっています)で、負荷状況に応じて動的に規模が変化します。具体的にはELBインスタンスの数や性能が変化します。 また、ELBはDNSベースの分散システムでもあるので、ELBインスタンスの追加や変更はDNSのTTLの影響を受けます。ELBのレコードTTLは60秒ですので、ELBのキャパシティ変化がCloudWatchに依存するものだと仮定すると、DNSTTL60秒+CloudWatchのメトリクス取得で0~120秒程度必要になることになります。

Internet-facingなELBインスタンスはそれぞれがPublicIPを持ちますが、割り当てられる可能性があるIPアドレスは以下で公開されています。

AWS General Reference (Version 1.0)

東京リージョンに割り当てられているELB用の(EC2用ですが)IPアドレス一覧は以下のようなコマンドで確認できます。

$ curl -s https://ip-ranges.amazonaws.com/ip-ranges.json | \
  jq '.prefixes[] | select(.service == "EC2" and .region == "ap-northeast-1") | .ip_prefix'

肝心のELBの最大規模ですが、筆者が確認した範囲では実運用環境で10Gbps 200kHTTPreq/secでも問題なく動作しますので、実際にはより多くのキャパシティを持つものと考えられます。

AZ間遅延

ELBはMulti-AZで配備することが可能ですが、Cross-Zone Load Balancingオプションを有効にした場合、ELBに着信したトラフィックが全てのバックエンドAZに分散されます。現在の東京リージョンではAZ間のRTTが2msec程度なので、ELB EC2でAZをまたぐ場合にこのRTTを考慮する必要があります。Multi-AZ構成のシステムでELB、EC2、RDSを組み合わせるケースではEC2からRDSマスターへの書き込みでもAZをまたぐ通信が発生しますので、ELBでCross-Zone Load Balancingを有効にした場合4msecのRTTを考慮する必要があります。

pre-warm

ELBを任意の規模にしたい場合自分で負荷をかけてスケールアップ/アウトさせることも可能ですが、相当な手間と通信費用が必要になりますので、お手軽にELBの規模を変更したい場合にはBusiness以上のSupport契約で可能なpre-warmを利用しましょう。

AWSは顧客からの申請に応じてELBのスケールアップ/アウトを行いますが、実際のトラフィックを流した負荷試験は顧客側で行う必要があります。厳密なプロビジョニングを行う必要がある場合は必ずpre-warm後に負荷試験を行いましょう。なお、ELBがpre-warmされたことを正確に確認するには負荷試験を行なう他ありませんが、簡易な2つの方法を紹介します。

名前解決による確認

ELBのエンドポイント名(DNS Name)を名前解決することでELBインスタンス数を確認することが出来ます。ELBは最小で割り当てたAZ数×1のインスタンスで構成されるので、ELBが2AZに割り当てられているシステムで、pre-warm後にELBインスタンスが2つだった場合はインスタンス数がスケールアップしたかどうかの判断が難しい場合があります。また、ELBは名前解決要求に対して最大で8つのIPv4アドレスを返答するのでELBインスタンスが9つ以上の場合もまたインスタンス数を正確に把握することは難しいです。

$ dig [ELB DNS Name] +short @elb-nameserver +norec | egrep -vc "elb\.amazonaws\.com\.$"

ENIの数による確認

ENIの数からELBのインスタンス数を確認することが出来ます。ELBインスタンスの数が多い場合は名前解決による確認よりこちらのほうが精度の高い確認ができます。

$ aws ec2 describe-network-interfaces | \
  jq '.NetworkInterfaces[] | select(.PrivateIpAddresses[].Association.IpOwnerId=="amazon-elb") | select(.Description=="ELB [ELBName]")' | \
  grep -c NetworkInterfaceId

負荷試験

ELBに対して負荷試験を行う際にはAWSが公開している以下のエントリが参考になります。

Best Practices in Evaluating Elastic Load Balancing

負荷試験は目的によって方法が異なりますが、本エントリではELBにフォーカスした負荷試験を考察します。 まずゆるやかにトラフィックが変化する場合ですが、これはELBが得意とするパターンなので、特段の考慮事項は必要ありません。JMeter等のRamp-upが設定可能なツールを利用してシナリオ試験を行う事が多いでしょう。

対してピーク性の高いトラフィックを想定した負荷試験は、予めELBを最大規模に合わせてpre-warmしておく必要があります。筆者はELBの特性を考慮するとピーク時の性能をプロビジョニングし、pre-warm後にELBが完全にスケールアウトした状態のELBに対して負荷試験を行うほうが良いと考えます。 pre-warm後に負荷試験を行う場合、要件に応じてRPS(HTTPrec/sec)と帯域(bps)のいずれかもしくは両面で負荷試験を行ないます。

RPS(HTTPrec/sec)の負荷試験

要求性能に対して十分な性能を有するバックエンドを用意して、ELB経由で負荷をかけます。高RPSな負荷試験をEC2バックエンドに対して行う場合はSR-IOVが有効なインスタンスを利用したほうがよいでしょう。 全てのELBインスタンスに対して行なう方が負荷試験の精度が高いのですが、「ELB全体でプロビジョニングした性能÷ELBインスタンス数」のELBインスタンスあたりの想定性能を基に負荷試験を行なうことも可能。ですが、やはりELB全体を考慮した負荷試験を実施することが望ましいでしょう。

帯域(bps)の負荷試験

RPSの場合と同様に十分な性能を有するバックエンドを用意し、負荷試験を実施します。考慮事項もRPSの場合と同様です。

ログ集計

ELBのログ集計はRedshiftを利用すると便利です。プロビジョニングした(pre-warmした)ELBの性能に対して実際どの程度のトラフィックがあったのか効果測定をすることで、次回以降より精度の高いELBのプロビジョニングを行うことができますので、是非ログ集計を行っていただくことをおすすめします。

ここでは以下のエントリを参考に最大アクセス数/秒と最大トラフィック/秒を算出してみます。

Using Amazon Redshift to Analyze Your Elastic Load Balancer Traffic Logs

テーブル構造

S3からELBのログをロードする前に、以下のクエリでRedshiftにテーブルを作成しておきます。

CREATE TABLE Elb_Logs (
  RequestTime DateTime encode lzo,
  ELBName varchar(60) encode lzo,
  RequestIP_Port varchar(22) encode lzo,
  BackendIP_Port varchar(22) encode lzo,
  RequestProcessingTime FLOAT encode bytedict,
  BackendProcessingTime FLOAT encode bytedict,
  ClientResponseTime FLOAT encode bytedict,
  ELBResponseCode varchar(3) encode lzo,
  BackendResponseCode varchar(3) encode lzo,
  ReceivedBytes BIGINT encode lzo,
  SentBytes BIGINT encode lzo,
  Verb varchar(10) encode lzo,
  URL varchar(2083) encode lzo,
  HttpVersion varchar(10) encode lzo
) SORTKEY(RequestTime) ;

データロード

以下のクエリでS3からRedshiftにデータをロードします。

COPY
  Elb_Logs
FROM
  's3://YOURBUCKETNAME/PREFIX/AWSLogs/ACCOUNT_ID/elasticloadbalancing/REGION/YYYY/MM/DD'
COMPUPDATE OFF
REMOVEQUOTES
CREDENTIALS
  'aws_access_key_id=YOUR_ACCESS_KEY;aws_secret_access_key=YOUR_ACCESS_SECRET'
DELIMITER ' '
TIMEFORMAT as 'auto'
ACCEPTINVCHARS
MAXERROR as 10

集計クエリ

以下のクエリで最大アクセス数/秒と最大トラフィック/秒を算出できます。

SELECT date_trunc('second', RequestProcessingTime), sum(SentBytes), count(*)<br />FROM<br /> Elb_Logs<br />WHERE<br /> RequestTime &lt; 'YYYY-MM-DD HH:MM:SS' and RequestTime &gt; 'YYYY-MM-DD HH:MM:SS'<br />GROUP BY date_trunc('second', RequestTime)

まとめ

ELBはロードバランサー単体としてみると足りないところもあったりしますが、特性をよく理解して活用するとサービス開発を効率化してくれる良いプロダクトです。特にログ集計はRedshiftと組み合わせると非常にお手軽なので、是非活用してみてください!