ちょっと話題の記事

NLBでプライベートなEC2やRDSの負荷分散が可能に!

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

ウィスキー、シガー、パイプをこよなく愛する大栗です。

先日ALBでIPアドレスをターゲットとしてオンプレミスのリソースなどに対して負荷分散ができるようになりました。先日NLBでもIPアドレスをターゲットとして設定できるようになったためご紹介します。

Elastic Load Balancing: Network Load Balancer now supports load balancing to IP addresses as targets for AWS and on-premises resources

IPアドレスターゲット

NLBが負荷分散するターゲットをインスタンスIDではなくIPアドレスを指定することが可能な機能です。ALBでも同様の機能がありますが、一部異なる部分があります。

[新機能] ALBのターゲットにIPアドレスを指定可能になりました

指定可能なIPアドレス

サポートされているIPアドレスは、以下の範囲です。

  • ターゲットグループが配置されたVPCのCIDR
  • 10.0.0.0/8(RFC 1918)
  • 100.64.0.0/10(RFC 6598)
  • 172.16.0.0/12(RFC 1918)
  • 192.168.0.0/16(RFC 1918)

登録可能なリソース

サポートされているCIDRブロックの範囲で、ClassicLinkインスタンス、IPアドレスとポートを指定できるAWSリソース、Direct ConnectやソフトウェアVPNコネクションで接続したオンプレミスのリソースをターゲットグループに登録できます。残念ながらALBとは異なり、VPC PeeringやハードウェアVPNコネクション(VPCのVPNコネクション)の先は登録できないので注意が必要です。

また、登録できるリソースで『IPアドレスとポートを指定できるAWSリソース』という点が非常に重要になります。IPアドレスとポートが指定できれば、EC2以外のリソースも登録ができる訳です!!!RDSやElastiCacheなどのVPC内のリソースの負荷分散が可能になっています。今までソフトウェアロードバランサを使用していた箇所をマネージドサービスで代替できるということです。

ネットワーク構成

NLBのバックエンドサーバとして登録するEC2は、クライアントへのネットワーク到達性(IGWやNAT GWへのルート)が必要です。しかし、IPアドレスターゲットの場合はNLBへの到達性があればクライアントへのネットワーク到達性が不要になっています。オンプレミスのリソースを登録するために動作が変わっていると思われますが、VPC内のリソースもIPアドレスターゲットであれば同様の動作をします。

今までは、以下の2パターンの構成でNLBを構築できました。

  1. EC2がパブリックサブネットでグローバルIPを持っているパターン
  2. NAT Gateway経由でインターネットに出られるパターン

EC2がパブリックサブネットでグローバルIPを持っているパターン

  1. Internet GatewayからNLBへ通信
  2. NLBからEC2へ通信
  3. EC2からInternet Gatewayへ通信

注意: 3.の部分で、VPC Flow LogsではEC2 -> NLB -> Internet Gatewayのように見える。また外部への通信はNLBのElastic IPを使用する。

NLB1

NAT Gateway経由でインターネットに出られるパターン

  1. Internet GatewayからNLBへ通信
  2. NLBからEC2へ通信
  3. EC2からNAT Gatewayへ通信
  4. NAT GatewayからInternet Gatewayへ通信

注意: 3.と4.の部分で、VPC Flow LogsではEC2 -> NLB -> Internet Gatewayのように見える。また外部への通信はNLBのElastic IPを使用する。

NLB2

IPターゲットのパターン

IPターゲットの場合は、EC2のサブネットからインターネットへ出られないルートであってもNLBを経由して出ていくように見える動作となります。

  1. Internet GatewayからNLBへ通信
  2. NLBからEC2へ通信
  3. EC2からNLBへ通信
  4. NLBからInternet Gatewayへ通信

この動作により完全なプライベートサブネットのリソースに対してもNLBを利用することができます。

NLB3

やってみる

EC2インスタンスとRDSの負荷分散をやってみます。

EC2インスタンスのIPターゲット登録

まずは普通にEC2の負荷分散を行います。

ここでは、以下の前提とします。

リージョン:東京リージョン OS:amzn-ami-hvm-2017.03.1.20170812-x86_64-gp2 (ami-4af5022c)を元にhttpdをインストール済みのものを使用

また、ネットワーク構成は以下の図のようになります。

  • フロントエンドサブネット(Internet Gatewayにルーティングしている)
  • Frontend Subnet1:10.20.0.0/24
  • Frontend Subnet2:10.20.1.0/24
  • アプリケーションサブネット(VPC内のみにルーティングしてる)
  • Application Subnet1:10.20.100.0/24
  • Application Subnet2:10.20.101.0/24
  • データストアサブネット(VPC内のみにルーティングしてる)
  • Datastore Subnet1:10.20.200.0/24
  • Datastore Subnet2:10.20.201.0/24

VPC

EC2の起動

構成図のようにアプリケーションサブネットにEC2を起動します。EC2では事前にhttpdを導入したものを使用します。UserDataで以下を設定して、インスタンスIDを/index.htmlに設定します。セキュリティグループはフロントエンドサブネット(10.20.0.0/24、10.20.0.0/24)とアクセス元IPアドレスに対してポート80を許可した物を使用します。

UserData

#!/bin/bash
curl -s http://169.254.169.254/latest/meta-data/instance-id | tee /var/www/html/index.html > /dev/null
sudo service httpd start

ターゲットグループの作成

次にターゲットグループを作成します。

  • ターゲットグループ名:EC2-IP(任意で設定してください)
  • プロトコル:TCP(NLBの場合はTCPのみです)
  • ポート:80(HTTPのため)
  • ターゲットの種類:ip
  • VPC:対象のVPCを選択してください

EC2_Management_Console

ヘルスチェックの設定を以下のように実施しました。

  • ヘルスチェックの設定
  • プロトコル:TCP
  • ヘルスチェックの詳細設定
  • ポート:トラフィックポート
  • 正常のしきい値:3
  • 非正常のしきい値:3(変更不能)
  • タイムアウト:10(変更不能)
  • 間隔:10秒

ヘルスチェックのプロトコルはHTTPを使用せずにTCPにしています。NLBのヘルスチェックは分散型で行われているためヘルスチェクのアクセスが多いので、負荷を下げるためにTCPにしています。自分の計測結果ですが、間隔を10秒にした時で180回/分以上、間隔を30秒にした時で120回/分以上のヘルスチェックが来る模様です。

EC2_Management_Console

ターゲットの登録

作成したターゲットグループのターゲットを登録します。ターゲットタブの編集をクリックします。上部メニューのをクリックします。ネットワークに対象のVPCを選択し、IPにEC2のIPアドレスを設定してリストに追加をクリックします。2台のEC2を追加して登録をクリックしてと登録します。

EC2_Management_Console

ロードバランサーの作成

次にNLBを作成します。

  • 名前:EC2-IP
  • スキーマ:インターネット向け
  • リスナー
  • ロードバランサーのプロトコル:TCP(変更不能)
  • ロードバランサーのポート:80
  • アベイラビリティーゾーン
  • アベイラビリティー:ap-northeast-1a(Frontend Subnet1)
  • アベイラビリティー:ap-northeast-1c(Frontend Subnet2)

EC2_Management_Console

以下のようにルーティングの設定を行います。

  • ターゲットグループ
  • ターゲットグループ:既存のターゲットグループ
  • 名前:EC2-IP(作成したターゲットグループを選択します)
  • プロトコル:TCP(変更不能)
  • ポート:80(変更不能)
  • ターゲットの種類:ip(変更不能)
  • ヘルスチェック
  • プロトコル:TCP (変更不能)

EC2_Management_Console

ターゲットのEC2を確認します。

EC2_Management_Console

ロードバランサーの詳細を確認して作成をクリックします。

しばらく経つとターゲットがhealthyになります。

EC2_Management_Console

パブリックIPが無くインターネット値のアクセスもできないEC2に対してNLBで負荷分散が行なえます。

ec2-ip-aaaaaaaaaaaaaaa_elb_ap-northeast-1_amazonaws_com_index_html

ec2-ip-aaaaaaaaaaaaaaa_elb_ap-northeast-1_amazonaws_com_index_html

RDSのIPターゲット登録

次にRDSの負荷分散を行います。

ここではAuroraで、Writer1台、ReaderをAZごとに2台ずつの計4台で起動して、以下のように構成します。VPCのネットワークは「EC2インスタンスのIPターゲット登録」と同じものです。

VPC2

DBサブネットグループの作成

まずはDBサブネットグループを作成します。ここではデータストアサブネットの2個のサブネットを登録します。

RDS_·_AWS_Console

DBパラメータグループの作成

次に専用のDBパラメータグループを作成します。

RDS_·_AWS_Console

作成したDBパラメータグループのmax_connect_errorsを編集します。ここで最大値の18446744073709547520を入力します。これはNLBがヘルスチェックを行うと不正接続と判定されるため、アクセスを拒否しないための設定となります。

RDS_·_AWS_Console

セキュリティグループの作成

セキュリテイグループも作成します。

インバウンドのルールはアプリケーションサブネットのCIDRを許可します。NLBのヘルスチェックはIPアドレスでしか許可できないためです。

VPC_Management_Console

Auroraの起動

Auroraを起動します。

これまでに作成した、Dbサブネットグループ、DBパラメータグループ、セキュリティグループを設定します。配置するAZ(サブネット)は、以下の通りです。

  • Writer(writer-11):ap-northeast-1a(Datastore Subnet1)
  • Reader11(target-11):ap-northeast-1a(Datastore Subnet1)
  • Reader12(target-12):ap-northeast-1a(Datastore Subnet1)
  • Reader31(target-31):ap-northeast-1c(Datastore Subnet2)
  • Reader32(target-31):ap-northeast-1c(Datastore Subnet2)

ターゲットグループの作成

RDS用のターゲットグループを作成します。

  • ターゲットグループ名:RDS-IP(任意で設定してください)
  • プロトコル:TCP(NLBの場合はTCPのみです)
  • ポート:3306(MySQLのため)
  • ターゲットの種類:ip
  • VPC:対象のVPCを選択してください

ヘルスチェックの設定を以下のように設定します。

  • ヘルスチェックの設定
  • プロトコル:TCP
  • ヘルスチェックの詳細設定
  • ポート:トラフィックポート
  • 正常のしきい値:3
  • 非正常のしきい値:3(変更不能)
  • タイムアウト:10(変更不能)
  • 間隔:10秒

ターゲットの登録

ターゲットグループを作成したらターゲットを登録します。ここで注意が必要です。各々のDBインスタンスのインスタンスエンドポイントに対して名前解決をして、IPアドレスを確認します。確認したIPアドレスをターゲットグループに登録します。

  • Reader11(target-11):10.20.200.146
  • Reader12(target-12):10.20.200.254
  • Reader31(target-31):10.20.201.23
  • Reader32(target-31):10.20.201.142

EC2_Management_Console

ロードバランサーの作成

次にNLBを作成します。

  • 名前:aurora-nlb
  • スキーマ:内部
  • リスナー
  • ロードバランサーのプロトコル:TCP(変更不能)
  • ロードバランサーのポート:3306
  • アベイラビリティーゾーン
  • アベイラビリティー:ap-northeast-1a(Application Subnet1)
  • アベイラビリティー:ap-northeast-1c(Application Subnet2)

以下のようにルーティングの設定を行います。

  • ターゲットグループ
  • ターゲットグループ:既存のターゲットグループ
  • 名前:RDS-IP(作成したターゲットグループを選択します)
  • プロトコル:TCP(変更不能)
  • ポート:3306(変更不能)
  • ターゲットの種類:ip(変更不能)
  • ヘルスチェック
  • プロトコル:TCP (変更不能)

ターゲットのRDSのIPアドレスをを確認して、ロードバランサーの詳細を確認してロードバランサーを作成します。

しばらく経つとターゲットがhealthyになります。

アプリケーションサブネットのEC2からNLB経由でAuroraにアクセスしてみます。普通にログイン可能です。

$ mysql -uawsuser -pmypassword -h aurora-nlb-a1b2c3d4e5f6g7h8.elb.ap-northeast-1.amazonaws.com
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 60667
Server version: 5.6.10 MySQL Community Server (GPL)

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

何度かアクセスして、Auroraのhostnameを確認してみます。1000回確認してみました。地道にやるのは面倒なので、少しシェル芸を使います、

$ for i in `seq 1 1000`; do   echo "show variables like 'hostname';" | mysql -uawsuser -pmypassword -h aurora-nlb-a1b2c3d4e5f6g7h8.elb.ap-northeast-1.amazonaws.com -N; done | sort | uniq -c
    240 hostname	ip-172-23-1-228
    259 hostname	ip-172-23-1-55
    256 hostname	ip-172-23-2-123
    245 hostname	ip-172-23-2-124

かなり綺麗に分散されています。

比較のために読み込みエンドポイントで同様に確認してみます。

$ for i in `seq 1 1000`; do   echo "show variables like 'hostname';" | mysql -uawsuser -pmypassword -h target-cluster-01.cluster-ro-a1b2c3d4e5f6.ap-northeast-1.rds.amazonaws.com -N; done | sort | uniq -c
    157 hostname	ip-172-23-1-228
    611 hostname	ip-172-23-1-55
     59 hostname	ip-172-23-2-123
    173 hostname	ip-172-23-2-124

読み込みエンドポイントの場合は偏りが大きくなってしまいます。これは読み込みエンドポイントのTTLが5秒に設定されていることに起因します。

NLBでReaderの負荷分散を行うことで理想的に分けられることが確認できました。

さいごに

自分でNLBの紹介ブログを書いていてなんなんですが、SSL/TLSが使用できなかったり、バックエンドEC2のセキュリティグループを外部公開する必要があったり、正直NLBを使う場面は極めて限定的でALBとくらべてほとんど出番が無いと考えていました。

しかし、今回IPアドレスのターゲット登録ができるようになりEC2以外のリソースも負荷分散できるようになりました。大規模システムなどではDBの負荷分散が偏ると、負荷で順々に落ちていきサービスの全面ダウンが発生するようなことがあります。Auroraで読み込みエンドポイントを使用すると負荷の偏りが発生することがありましたが、NLBを使用するとほぼ理想的な分散となります。CLBやALB1ではEC2に対してしか負荷分散を行えませんでしたが、NLBではVPC内のリソースに対して自由にターゲット登録を行えます。今まで自分でソフトウェアロードバランサを使用していた部分でもマネージドサービスで運用する事ができることが期待できますね。


  1. ドキュメントによるとALBでもIPアドレスとポートを指定できるAWSリソースをターゲットに登録できる記載があるのですが、EC2以外でhttpでアクセスできるVPC内のリソースが思い当たりません。。。 http://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-target-groups.html#target-type