Yuki's Tech Blog

仕事で得た知見や勉強した技術を書きます。

【AWS:ゼロから実践するAmazon Web Services。手を動かしながらインフラの基礎を習得】セクション9: 【ELB】Webレイヤを冗長化しようで知らなかったことをざっくりまとめてみた

目次

概要

Webサーバーを2台にして、何か異常があってももう一台で捌けるように、Webサーバーを冗長化します。ELBというAWSのサービスを利用してそのような構成にしていきます。

稼働率とは

稼働率とは、 一定期間内で故障が発生しない確率のことです。 可用性(システムが継続して稼働できる能力)を評価する具体的な指標が、稼働率です。稼働率は、障害発生間隔と平均復旧時間の2つから構成されています。

稼働率を上げるための基本的な考え方

稼働率は、 障害発生間隔と平均復旧時間の2つから構成されています。 そのため、稼働率を上げるためには、障害発生間隔を長くする(つまり、障害が発生しないようにする)と、平均復旧時間を短くする(つまり、障害が発生してから復旧するまでの時間を短くする)ことです。

これらの2点の向上を実現するために、冗長化という手法を使用します。冗長化とは、 システム構成要素を多重化することです。 ある構成要素で障害が発生したとしても処理を引き継げるように、システムを構成します。そうすることで、平均復旧時間を短くしたり0にすることができます。

単一障害点をなくす

ここで重要なのは単一障害点(SPOF)をなくすということです。これはシステム構成要素で多重化されていない要素のことです。多重化されていないので、そこに障害が発生すると、システム全体が停止してしまいます。そのため、SPOFがあったら、できる限り冗長化して、SPOFをなくすようにします。

稼働率を上げる具体的な3つの方法

  1. 要素単体の稼働率を高くする
    オンプレミスだとパーツを二重化したりできるが、AWSだと難しいです。また、要素単体の稼働率を上げるのは限界があるので、方法2と方法3をAWSで実践します。
  2. 要素を組み合わせて、全体の稼働率を高くする
    要素を組み合わせて、冗長化します。冗長化には冗長化したどちらも使用可能なActive-Activeと冗長化した片方は利用できないActive-Standbyがあります。Active-StandbyはHot Standby、Warm Standby、Cold Standbyの3つに分かれます。 Ho Standbyは、スタンバイ側は普段から起動していてすぐに利用可能です。Warm Standbyは、スタンバイ側は普段から起動しているが、利用するのに準備が必要です。Cold Standbyはスタンバイ側は普段は停止しています。技術的に可能であれば、Active-Activeが一番稼働率が高くなります。データを持たなくて状態に依存しない要素であれば、Active-Activeを実現しやすいです。具体的にはWebサーバーの冗長化はActive-Activeにすることが多いです。データベースなどデータを持つものでは、Active-Activeにすると、データの整合性を取るために同期が必要になって動作が遅くなるので、その場合はActive-Standbyにします。
  3. 負荷を適切なプロビジョニングで回避する
    プロビジョニングとは、 アクセス数を予測して適切にリソースを準備することです。 それによって、負荷を捌けるようにします。負荷に対応するためにはスケールアップ(サーバーなどの個々の要素の性能を向上させる)とスケールアウト(サーバーなどの個々の要素の数を増やす)があります。スケールアップはコスパがいいですが、一定の範囲を超えると、スケールアウトにも取り組んでいく必要があります。負荷の観点で最低限用意しておきたいのが、N + 1構成です。サービス提供に必要な台数をNとして、それに1台を追加した構成です。N + 2構成までやるとかなり安心できます。

Webサービスにおけるサーバー構成のベストプラクティス

サービスの稼働率を上げるを上げるためにどうのようなサーバー構成にすれば良いのかを考えます。サーバー構成には典型的なパターンがあります。

一番最小限な構成

一番最小限な構成は1台のサーバーにWebサーバーソフトウェアとDBMSを入れた構成です。1台のサーバーがWebサーバーとDBサーバーの役割を担っています。この構成をどのような構成にしたら稼働率が上がるのかを考えていきます。

パターン1: Webサーバー1台、DBサーバー1台構成

サーバー1台でサーバーのスペックが足りなくなった時にこの構成を採用することが多いです。DBの機能だけ別のサーバーに切り出すことを意味しています。サーバーのスペックを使い切らず分散できるので良いですが、セキュリティの面でもこの構成は優れています。理由はDBサーバーはインターネットからアクセスできない場所に置くのが安全だからです。

パターン2: Webサーバー2台、DBサーバー1台構成

Webサービスはユーザー数に応じて処理が増えるため、その分Webサーバーの負荷が増えます。そのため、Webサーバーの性能が足りない時にWebサーバーを複数台使うことで、Webサーバーを冗長化させて負荷分散ができます。

パターン3: Webサーバー2台、DBサーバー2台構成

DBをマスタースレーブ方式にすることで、DBの冗長化をおこなっているパターンです。親のDBサーバーをマスターサーバー、マスターサーバーをレプリケーションしたものをスレーブと言います。基本的にはWebサーバーからの通信はマスターの方に来ます。しかし、マスターの方に何らかの障害があってスレーブの方に切り替えて使うのがマスタースレーブ方式になります。マルチAZ構成と同じです。AWSではマルチAZ構成、一般的にはマスタースレーブ方式と呼びます。DBサーバーに何か障害があっても冗長化して対応できるようにしています。

ロードバランサーとは何か

ロードバランサーとは、 各サーバーにアクセスを振り分けて、負荷を分散させる装置のことです。 クライアントからのアクセスをまずはロードバランサーが受けて、そのアクセスをWebサーバーに分散させて送ります。ロードバランサーはハードウェアのものが多かったが、最近ではソフトウェアのものが主流だそうです。

ELB(Elastic Load Balancing)とは何か

ELBとは、 AWSクラウド上のロードバランサーです。 複数のEC2インスタンスに負荷分散させることができます。また、複数のアベイラビリティゾーンにある複数のEC2インスタンスの中から正常なターゲットにのみ振り分けます(ヘルスチェック)。それによって高い可用性をキープしています。

ELBの5つの特徴

  1. スケーラブル
    ELBはEC2インスタンスに負荷分散できるだけではなく、ELB自身も負荷に応じて自動でスケールアウトやスケールイン(サーバーの台数を減らすこと)ができます。このスケールアウトやスケールインは特に何も設定しなくてもELBで自動で行ってくれます。
  2. アベイラビリティゾーンにまたがる構成
    ELBは一つのリージョンに対して設置します。 そのリージョン内のアベイラビリティゾーンにまたがるように構成できます。
  3. 名前解決
    ELBにはDNS名が割り当てられています。ELBにはDNSが割り当てられているので、ELBへの接続ポイントへのアクセスにはDNSを使用します。DNS名を使うと、ELB自体が負荷に応じてスケールアウトやスケールインするのも自動でできるようになります。
  4. 安価な従量課金
    使用した分だけしかお金がかかりません。
  5. マネージドサービス
    運用が楽です。

既存のEC2インスタンスからAMIを作成して、AMIからEC2インスタンスを作成する

既存のEC2インスタンスからAMIを作成して、AMIからEC2インスタンスを作成すると、既存のEC2インスタンスと同じEC2インスタンスを作成することができます。

作業手順

手順1:
VPCの画面からサブネットを作成します。アベイラビリティゾーンはap-northeast-1c、CIDRブロックは10.0.11.0/24にします。 Image from Gyazo

手順2:
作成したサブネットにルートテーブルを関連付けて、サブネットとインターネットゲートウェイを紐付けます。「ルートテーブル」→「サブネットの関連づけを編集」→「関連づけを保存」をクリックでOKです。これでパブリックサブネットの作成は完了です。 Image from Gyazo

手順3:
AMIの作成をします。EC2のダッシュボードを開きます。その後、「インスタンス」→「AMIを作りたいインスタンスを選択してアクション」→「イメージとテンプレート」→「イメージを作成」をクリックします。イメージ名はEC2インスタンスの名前_日付にします。今回はblog-test-web-server_20221107にしました。イメージの説明もイメージ名と同じにしておきます。インスタンスボリュームはこのままで大丈夫です。その後、「イメージを作成」をクリックします。これで既存のEC2インスタンスのAMIを作成できました。

手順4:
作成したAMIからEC2インスタンスを作成していきます。EC2のダッシュボードから「AMI」→AMIを選択して「AMIからインスタンスを起動」をクリックします。以下のブログを参考にしつつ、EC2インスタンスを作成していきます。プライマリIPは10.0.11.10にします。先ほど作成したサブネットの中に収まっていれば大丈夫です。セキュリティグループは既存のセキュリティグループを使います。キーペアは既存のキーペアを使います。blog-test-web-server-1という名前にしました。

【AWS:ゼロから実践するAmazon Web Services。手を動かしながらインフラの基礎を習得】セクション4: 【EC2】Webサーバーを構築しようで知らなかったことをざっくりまとめてみた - Yuki's Tech Blog

手順5:
負荷分散されているかを分かりやすくするためにWordPressの内容を書き換えておきます。AZが1aのEC2インスタンスSSH接続します。その後、cdコマンドで /var/www/html/に移動します。index.phpがトップページで表示されるファイルなので、このファイルをsudo vimで編集していきます。以下の行を追加します。

echo '<p>sample 1a</p>';

AZが1cの方でも同様のことをします。

ELBで負荷分散してみる

作業手順

手順1:
EC2のダッシュボードの「ロードバランサー」→「ロードバランサーの作成」をクリックします。3種類のロードバランサーからどれかを選択します。Application Load Balancerは通常のロードバランサーであり、Webサービスを作るときはこちらを選択します。クライアント → ロードバランサー → Webサーバーの流れで、Webサーバーから返すときはWebサーバー → ロードバランサー → クライアントの流れです。Network Load Balancerの場合、行きの経路は同じですが帰りがWebサーバーから直接クライアントに返します。そのため、遅延を少なくしてレスポンスを返すことができます。しかし、通信を返すときにロードバランサーを通してないので、パケットがちゃんとクライアントに渡ったのかを実装する必要があります。Gateway Load Balancerはあまりよく分かっていないので使用する時に調べます。今回はWebサービスを作るので、Application Load Balancerを選択します。createをクリックします。

Image from Gyazo

手順2:
ロードバランサーの名前を入力します。Application Load Balancerなので、blog-test-albという名前にしました。Schemeは インターネットからの通信に対応するためにロードバランサーを置くので、Internet-facingを選択します。IP address typeはIPv4を選択します。 Network mappingではロードバランサーを置くVPCを選択して負荷分散させたいEC2インスタンスがいるアベイラビリティゾーンとパブリックサブネットを選択します。次にELB用の新しいセキュリティグループを作成します。セキュリティグループ名はblog-test-alb、説明も同じものを入力します。VPCを選択した後に、HTTPならどんなアクセスもOKというインバウンドルールを作ります。デフォルトルート(0.0.0.0/0)を指定すればOKです。 Image from Gyazo

セキュリティグループを作成した後、ELBの設定画面で先ほど作成したセキュリティグループを選択します。

手順3:
Listeners and routingの項目を設定していきます。ここではどちらのEC2にルーティングをしていくかを決めます。Create target Groupをクリックして、各項目を入力していきます。ターゲットの種類はEC2インスタンスをターゲットにしたいので、インスタンスを指定します。ターゲットグループはblog-test-tgにします。プロトコルはHTTP、ポートは80にします。次にヘルスチェックを設定します。ヘルスチェックではどこのパスでヘルスチェックを行うかを設定します。ELBは、指定したパスでリクエストを出してヘルスチェックがOKかどうかを確認します。WordPressの場合、/はトップページです。今回はヘルスチェックの失敗を確認したいので、Healthy thresholdを2にします。ヘルスチェックの間隔も10秒おきにチェックするように変更します。実際のサービスだったらこの部分は変えなくて大丈夫です。次に「Next」をクリックします。 Image from Gyazo

(※) ターゲットグループでターゲットをちゃんと登録できていなくて沼ったので、ちゃんとターゲットが登録できているか確認しましょう。

手順4:
Register targetsでELBで負荷分散するEC2インスタンスのターゲットを選択します。次に「Create target group」をクリックします。その後、Listeners and routingで先ほど作ったtarget groupを選択して、Create Load Blancerをクリックします。これでALBが作成できました。 Image from Gyazo

手順5:
次にELB経由でWebサイトにアクセスできるようにします。ELBを選択して、DNS名をコピーします。このDNS名でELBにアクセスできます。確かに、リロードすると、サーバーへのリクエストを振り分けて分散させているのが分かります。

Image from Gyazo

今の状態で独自ドメインでWebサイトにアクセスしようとすると、EC2インスタンスにリクエストが行われるので、Route53で独自ドメインにアクセスが来たらELBにアクセスが行くように設定します。現在Route53のホストゾーンにはドメインに対応するAレコードが登録されています。ターゲットにEC2インスタンスのパブリックIPアドレスが入っているので、そこにELBのDNSを入力します。Route53のダッシュボードから「ホストゾーン」→ ドメイン名をクリックしてAレコードを編集します。エイリアスを選択した後、リージョンと作成したELBを選択します。最後に「保存」をクリックします。

実際にドメインでWebサイトにアクセスすると、ちゃんとELBでアクセスが振り分けられているのが確認できました。 Image from Gyazo

(※)ELBのターゲットにEC2インスタンスを指定する場合、ELBが動的にアドレスを解決できるので、パブリックIPがあればElastic IPアドレスを割り当てる必要はないです。そのため、ELBを使う場合、Elastic IPアドレスの関連づけを解除して解放しておきます(そもそもElastic IPアドレスを確保してEC2インスタンスに関連付けてた理由は、Aレコードに登録するパブリックIPアドレスを変動させたくないためです。EC2インスタンスは停止させて起動させたときに割り当てられるパブリックIPアドレスが変動するので、Elastic IPアドレスを割り当てない場合、ドメインでWebサイトにアクセスできなくなってしまいます)。

ELBのヘルスチェックの機能を確認してみる

AZが1aのEC2インスタンスApacheを停止させます。その後、ヘルスチェックがちゃんと機能しているかを確認します。

ssh -i ./blog-test-ec2.pem ec2-user@54.250.26.39
sudo systemctl stop httpd.service

ブラウザでリクエストを出してみると、AZが1aのEC2インスタンスのヘルスチェックが失敗しているので、AZが1cのEC2インスタンスにしかアクセスされていないことが分かりました。 Image from Gyazo

EC2ダッシュボードでインスタンスを見るとヘルスチェックが失敗してunhealthyになっていることが確認できました。 ELBはヘルスチェックを行なって、unhealthyのサーバーには通信を送らないようにしています。

Image from Gyazo

ELBを運用する2つのポイント

  1. サーバーをアベイラビリティゾーンをまたがって配置する
    アベイラビリティゾーンで災害が発生しても、別のアベイラビリティゾーンのサーバーでサービスを稼働できる。
  2. Webサーバーをステートレスに構築する
    データを同期させなければならなくなってしまうので、データはDBサーバー、ファイルならS3に保持して、データをWebサーバーで持たないようにします。

ELBに登録済みのEC2インスタンスを停止させる場合

ELBに登録済みのEC2インスタンスを停止させる場合、ターゲットグループで、登録しているWebサーバーをDeregisterにします。その後、EC2インスタンスを終了すれば大丈夫です。

インフラ構成図

前回のインフラ構成図に、ELBを追加しました。 Image from Gyazo

参考記事

AWS:ゼロから実践するAmazon Web Services。手を動かしながらインフラの基礎を習得 | Udemy

稼働率

スケールイン

AWS のアーキテクチャ図を描きたい ! でもどうすれば良いの ?