gokigenmaruのブログ

40から始めるクラウドエンジニア

CloudwatchAgentで取得したプロセス数からオートスケーリングを実施したい

前回、CloudwatchAgentでApacheのプロセス数を取得しました。
これが出来たことで少し欲が出てきました。Cloudwatchを使ってEC2のオートスケーリングを実施出来ないかという欲です。
実際にはここから紆余曲折ありましたが、なんとか実現できました。
今回はそのお話です。

構成

今回の簡単な構成図です。

構成図1

NetworkLoadBalancerの後ろにEC2を複数台配置、オートスケーリンググループを組んでいます。
当初、このオートスケーリンググループはEC2の起動する台数を固定化する(耐障害性などを考慮)ためのもので、オートスケーリングをする意図はありませんでした。
というのも、NLBでオートスケーリンググループを組む場合、CPU負荷などのEC2の負荷であれば簡単に作れますが、アクセス数に応じたオートスケーリングとなるとどうしても難しいところがありました。
ですが、オートスケーリンググループ内の各EC2でプロセス数が取得できるようになったことで、Cloudwatchアラームが使えるのではないかと考えました。
NLBから通信を受けるEC2はApacheでアクセスを処理しているので、Apacheのプロセス数である一定のプロセス数になったらオートスケーリングさせるというものでした。

Cloudwatchアラーム

まず考えたのが、Cloudwatchアラームで各EC2で取得したプロセスの平均を取ってオートスケーリングさせる方法です。
Cloudwatchアラームでアラームを作成してみると、以下のことがネックに。
・CloudwatchAgentで取得したApacheのプロセス数はEC2単位で出てくる。
Cloudwatchアラームはメトリクスを指定する必要があり、そのメトリクスはEC2単位のプロセス数のメトリクスとなります。今時点でCloudwatchで出てくるのがEC2単位でそれでCloudwatchアラームを作ってしまうと、オートスケーリングした後に新しく起動してきたEC2のプロセス数を取得するメトリクスがCloudwatchアラームに入らなくなってしまいます。
ということで、新しくEC2が起動してきても大丈夫なように、クエリを書くことにしました。

Cloudwatchアラームでクエリを書く

まずは以下のクエリを書いてCloudwatchアラームに設定。

SEARCH(' MetricName="procstat_lookup_pid_count" ', 'Average', 10)

「procstat_lookup_pid_count」に入っているEC2全部のアベレージを取ろうと思いましたが、失敗。
cloudwatchアラームに設定しようとしたら、SEARCHは使えないって怒られた…。

ということで、次の方法としてSEARCHが使えないので別の方法を考えて試してみました。

SELECT AVG(procstat_lookup_pid_count) FROM SCHEMA(CWAgent, exe,host,pid_finder) WHERE exe = 'httpd'

SEARCHがダメならSELECT ならよかろうと思いましたが、失敗。
そもそもアラート設定すらさせてもらえなかった…。

ここで行き詰りました。
どうやってもCloudwatchAgentで取得したApacheのプロセス数をCloudwatchアラームで検知してオートスケーリングを実現するということで出来そうにない…。

困っていたところ、ここでスペシャリストから絶妙なアドバイスが貰えました。

CloudwatchAgent側でメトリクスの集約を行う設定をする

dev.classmethod.jp

クラメソさんの技術ブログをリンクします。
このサイトで、オートスケーリンググループごとにメトリクスを集約してCloudwatchで見れるようにする方法が紹介されています。
これを試してみることに。

CloudwatchAgentの設定を前回のブログから以下の通りに変更。

    "metrics": {
        "append_dimensions": {
            "AutoScalingGroupName": "${aws:AutoScalingGroupName}",
            "ImageId": "${aws:ImageId}",
            "InstanceId": "${aws:InstanceId}",
            "InstanceType": "${aws:InstanceType}"
        },
        "aggregation_dimensions": [["AutoScalingGroupName"]],
        "metrics_collected": {
            "procstat": [
                {
                    "exe": "httpd",
                    "measurement": [
                        "pid_count"
                    ]
                }
            ]
        }
    },

試してみると、Cloudwatch側では以下の通りに。

CW1
CW2
CW3

オートスケーリンググループに所属する複数のEC2で動いているApacheのプロセスの平均値が1つのグラフとして出るようになりました。
これでようやくCloudwatchアラームで閾値設定して無事オートスケーリングの動的スケーリングポリシーの設定が組めるようになりました。

終わり

今回はApache(worker)を利用し、1プロセスあたりのスレッドを30程度としてプロセス数の上限を200とかにしているため、プロセス数からCloudwatchアラームで上限(スケールアウト用)、下限(スケールイン用)の検知設定をしてEC2のオートスケーリンググループの動的スケーリングポリシーで設定を実施しました。
Nginxだと1つのプロセスで1024スレッドとか動かす形になるので、今回のブログとはまた別の方法を取る必要があります。
やり方はわかっているのですが、今のところ試したことはないのできっとそのうち試したらブログに書くかもしれません。きっと1年後とか2年後とか…。