この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
WebサーバとRDSでシステムを構成する際、冗長性を考慮し、以下のような構成にすることが多いかと思います。
- WebサーバをEC2複数台で構築し、複数AZに分散配置。ELBでロードバランシングする。
- RDSをMulti-AZで構築し、複数AZに分散配置。
これで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」として指定しています。
スクリプト
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パラメータのチューニングが最適解ですが、システムの変更が困難な場合、このような対策も有効かと思います。