ELB+EC2+RDS(Multi-AZ)構成をあえてActive-Standbyにする

はじめに

WebサーバとRDSでシステムを構成する際、冗長性を考慮し、以下のような構成にすることが多いかと思います。

  • WebサーバをEC2複数台で構築し、複数AZに分散配置。ELBでロードバランシングする。
  • RDSをMulti-AZで構築し、複数AZに分散配置。

change01

これでAvailability Zoneレベルでの冗長性が確保されますので、例えばAvailability Zoneがメンテナンスや災害などで丸ごと停止した場合にもサービスを継続することが出来ます。

しかし、Availability Zoneレベルでの冗長性を確保したいが、Acitve-Activeな構成にはしたくない場合があります。例えば、Multi-AZ構成のRDSではプライマリDBインスタンスは常にどちらかのAZに存在しますが、AZを跨いだ通信はAZ内での通信よりレイテンシが大きくなります。DBとの通信がシビアなシステムでは、常にプライマリDBインスタンスと同じAvailability ZoneにいるEC2をActiveにしておきたい場合もあるでしょう。

そこで、ELBのヘルスチェックとAWS CLIを使って、ELB+EC2+RDS(Multi-AZ)構成をあえてActive-Standbyにするスクリプトを作ってみました。

ELBの設定

ELBでは以下のように、ヘルスチェックで確認するファイルを「ok.html」として指定しています。

change03

スクリプト

EC2上で動かしているスクリプトは以下の内容になります。これをcronで定期的に動作させることで、

  • プライマリDBインスタンスと同じAvailability ZoneにいるEC2でok.htmlが作成される
  • プライマリDBインスタンスと違うAvailability ZoneにいるEC2でok.htmlが削除される。但し全てのEC2がOutOfServiceにならないよう、対向のEC2でok.htmlがアクセス可能になっていることを確認してから実施する。
  • ELBから見て常に片方1台がinServiceとなる。

という動作になります。自EC2と対向EC2の区別は「Name」というtagによって判断しています。

#!/bin/bash

# 対向EC2のIPアドレスを取得
PARTNER_IPADDR=`aws ec2 describe-instances --filter Name=tag-key,Values=Name Name=tag-value,Values="web02" | grep "PRIVATEIPADDRESSES" | awk '{print $4}'`
# 自EC2のAvailability Zoneを取得
EC2AZ=`aws ec2 describe-instances --filter Name=tag-key,Values=Name Name=tag-value,Values="web01" | grep "PLACEMENT" | awk '{print $2}'`
# RDSの現在のAvailability Zoneを取得
DBAZ=`aws rds describe-db-instances | grep "DBINSTANCES" | awk '{print $4}'`

# 自EC2とRDSの現在のAvailability Zoneが一致する場合、ok.htmlを作成
if test $EC2AZ = $DBAZ ; then
  echo "match"
  echo "ok" > /var/www/html/ok.html
  
# 自EC2とRDSのAvailability Zoneが一致しない場合
else
  echo "unmatch"
  # 対向EC2がアップしていることを確認し、自EC2のok.htmlを削除
  STATUS=`curl -s http://$PARTNER_IPADDR/ok.html`
  if test $STATUS = "ok" ; then
    rm /var/www/html/ok.html
  
  # 自EC2とRDSのAvailability Zoneが一致しない場合でも
  # 対向のEC2がokで無ければ、ok.htmlを作成
  else
    echo "ok" > /var/www/html/ok.html
  fi
fi

まとめ

AZを跨ぐことによるネットワークのレイテンシにシビアなシステムに対する対処としてはSQLやRDSパラメータのチューニングが最適解ですが、システムの変更が困難な場合、このような対策も有効かと思います。