Virtual Hostで1つのEC2インスタンスで複数Webサイトをホスティングさせているけど、各Webサイトごとのアクセス数を確認したい
こんにちは、のんピ(@non____97)です。
皆さんはVirtual Hostで1つのEC2インスタンスで複数Webサイトをホスティングさせている環境で各Webサイトごとのアクセス数を確認したいと思ったことはありますか? 私はあります。
ALBにはActiveConnectionCount
やNewConnectionCount
、RequestCount
など接続数やリクエスト数のメトリクスが存在しています。
これらのメトリクスやALBやターゲットグループ単位のメトリクスになるので、Virtual HostでWebサイトを稼働させているとどのWebサイトへのアクセス数が多いのか把握することが難しいです。
「WebサーバーやALBのアクセスログを確認すればいいじゃん」と思われるかもしれませんが、グラフか何かで推移を簡単に確認したいところです。
そこで「Virtual Hostのホスト毎にターゲットグループを作成すれば良いんじゃないか」という理論で検証してみました。
いきなりまとめ
- ホストごとにターゲットグループを作成すれば、各ホストごとのアクセス数をCloudWatchメトリクス
RequestCount
で確認できるRequestCount
はIPv4 および IPv6 経由で正常に処理されたリクエスト数
- 細かいパフォーマンスを確認したいのであれば、ALBごと分割することになる
- ヘルスチェックをしているホストの巻き込み事故を回避したいなら、Virtual Host自体を避けた方が良い
検証環境
検証環境は以下のとおりです。
Apache HTTP ServerのVirtual Hostでhoge.web.non-97.net
とfuga.web.non-97.net
を稼働させています。
検証環境はAWS CDKでデプロイしました。使用したコードは以下リポジトリに保存しています。
デプロイ後、Route 53 Public Hosted ZoneのNSレコードを私のネームサーバーサービスに登録すると、以下のようにhoge.web.non-97.net
とfuga.web.non-97.net
にアクセスできるようになりました。
> curl hoge.web.non-97.net
hoge
> curl fuga.web.non-97.net
fuga
各ドメインに対して何回かアクセスした後、ActiveConnectionCount
やNewConnectionCount
、RequestCount
を確認してみます。
はい、ALBもターゲットグループも同じなので、どちらのドメインに対して何回アクセスしたのか読み取れません。
試しに3分ほどhoge.web.non-97.net
に0.5秒間隔でアクセスしてみます。
> while true; do
curl -s hoge.web.non-97.net > /dev/null
sleep 0.5
done
CloudWatchメトリクスは以下のとおりです。
このように大量のアクセスが来ているのにも関わらず、どのドメインに対してのアクセスなのか分からないと、どちらのドメインで対応が必要なのかの判断に困りそうですね。
ターゲットグループを分けてみる
それではドメイン毎にターゲットグループを分けてみます。
リスナールールで各ホストヘッダーに対応したターゲットグループに転送するようにしてあげます。
AWS CDKのコードは以下のとおりです。
./lib/constructs/alb.ts
const listener = this.alb.addListener("Listener", {
port: 80,
protocol: cdk.aws_elasticloadbalancingv2.ApplicationProtocol.HTTP,
defaultTargetGroups: [targetGroup],
});
listener.addTargets("TargetsHoge", {
priority: 1,
conditions: [
cdk.aws_elasticloadbalancingv2.ListenerCondition.hostHeaders([
"hoge.web.non-97.net",
]),
],
targets: [props.asg],
port: 80,
});
listener.addTargets("TargetsFuga", {
priority: 2,
conditions: [
cdk.aws_elasticloadbalancingv2.ListenerCondition.hostHeaders([
"fuga.web.non-97.net",
]),
],
targets: [props.asg],
port: 80,
});
※ どちらかのリスナールールのターゲットはlistener.addTargetGroups()
でも良いです
デプロイ後のリスナールールを確認します。
HTTPホストヘッダーで転送先のターゲットグループが異なることが分かります。
Auto Scaling Groupを確認すると、複数のターゲットグループが選択されていることが分かります。
それでは、タイミングをずらして各ドメインに対してアクセスします。
CloudWatchメトリクスを確認すると以下のようになっていました。
ターゲットグループが分かれているので、ターゲットグループのRequestCount
でアクセス数が判断できますね。
では、ターゲットグループを分けまくれば良いのかというとそうではありません。
ターゲットが増えれば増えるほどヘルスチェックのリクエスト数が増大します。また、ターゲットグループで確認できるメトリクスは少ないです。細かいパフォーマンスを確認したいのであれば、ALBごと分割することになると考えます。
そのため、ターゲットグループで要件満たせるか評価すると良いでしょう。
そもそも、Virtual Hostの場合を避けた方が良いと個人的には思います。理由はヘルスチェックをしているホストの巻き込み事故を回避するためです。
ALBからのヘルスチェックの際にホストを指定できません。ヘルスチェックはデフォルトのホストに対して行われます。そのため、コンテンツ更新などでデフォルトのホストのコンテンツが一時的にステータスコード200を返さなくなると、そのターゲット自体にリクエストを振り分けなくなります。特にAuto ScalingでヘルスチェックにELBを使用している場合は、EC2インスタンスが削除されてしまいます。
特別にVirtual Hostにする必要がある背景がないのであれば、ホストごとにEC2インスタンスは分離させた方が良いと考えます。
実際に試してみましょう。
hoge.web.non-97.net
のindex.html
を削除して、ヘルスチェックに失敗するようにします。
$ sudo rm -rf /var/www/html/hoge/index.html
$ sudo tail -f /var/log/httpd/hoge_access_log
10.10.10.36 - - [21/Aug/2023:06:23:41 +0000] "GET / HTTP/1.1" 200 5 "-" "ELB-HealthChecker/2.0"
10.10.10.36 - - [21/Aug/2023:06:23:41 +0000] "GET / HTTP/1.1" 200 5 "-" "ELB-HealthChecker/2.0"
10.10.10.26 - - [21/Aug/2023:06:23:41 +0000] "GET / HTTP/1.1" 200 5 "-" "ELB-HealthChecker/2.0"
10.10.10.26 - - [21/Aug/2023:06:23:41 +0000] "GET / HTTP/1.1" 200 5 "-" "ELB-HealthChecker/2.0"
10.10.10.26 - - [21/Aug/2023:06:23:56 +0000] "GET / HTTP/1.1" 200 5 "-" "ELB-HealthChecker/2.0"
10.10.10.36 - - [21/Aug/2023:06:23:56 +0000] "GET / HTTP/1.1" 200 5 "-" "ELB-HealthChecker/2.0"
10.10.10.36 - - [21/Aug/2023:06:24:11 +0000] "GET / HTTP/1.1" 403 45 "-" "ELB-HealthChecker/2.0"
10.10.10.36 - - [21/Aug/2023:06:24:11 +0000] "GET / HTTP/1.1" 403 45 "-" "ELB-HealthChecker/2.0"
10.10.10.26 - - [21/Aug/2023:06:24:11 +0000] "GET / HTTP/1.1" 403 45 "-" "ELB-HealthChecker/2.0"
10.10.10.26 - - [21/Aug/2023:06:24:11 +0000] "GET / HTTP/1.1" 403 45 "-" "ELB-HealthChecker/2.0"
10.10.10.26 - - [21/Aug/2023:06:24:26 +0000] "GET / HTTP/1.1" 403 45 "-" "ELB-HealthChecker/2.0"
10.10.10.36 - - [21/Aug/2023:06:24:26 +0000] "GET / HTTP/1.1" 403 45 "-" "ELB-HealthChecker/2.0"
ALBからのヘルスチェックに403を返すようになっていますね。
ターゲットグループ上からもunhealthy
になりました。
しばらくすると、新しいEC2インスタンスの起動とunhealthy
のEC2インスタンスの削除が始まりました。
Auto Scaling Group上のインスタンス管理
でもunhealthy
となっていますね。
最終的には以下のようにunhealthy
のEC2インスタンスは削除されました。
ターゲットグループを分割した場合の影響範囲とアクセス数を確認する目的や精度などを考慮した上で分割しよう
ALBでVirtual Hostごとのアクセス数を確認したい場合はVirtual Hostごとでターゲットグループを分割すると良いかもしれないというお話をしました。
ターゲットグループを分割した場合の影響範囲ととアクセス数を確認する目的や精度などを考慮した上で分割しましょう。確認頻度が高くないのであれば必要になったタイミングでALBのアクセスログをAthenaで集計する方法でも良いかもしれません。
この記事が誰かの助けになれば幸いです。
以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!