業務内容でAmazonLinuxがサポート切れるからWebサービスのコンテナをAmazonLinux2に移行したい&PHPのバージョンもアップデートしたいという話がありまして過去に対応していました。
色々あって、最初はAmazonLinux2でコンテナを立てていたのですが、Debianを採用することになりました。
それから数ヶ月かけていい感じに移行作業が進んでいたのですが、私が1週間のお休みをいただいている間に「Debianはダメだ!めちゃくちゃパフォーマンスが落ちる!!AmazonLinux2にしよう!!」という方向に話が進んでいたみたいです。
なんでもローカルでコンテナを動かすと問題ないのに、AWSのECS上で動かすとレスポンスが非常に遅くなるとのこと。
Dockerの強みは起動する環境が変わっても動作をほぼ保証してくれるところにあるのにそんなはずは・・・!?
と思って検証してみたのが今回のお話になります。
Dockerfileの準備
まずは検証のためにAmazonLinux2とDebianのそれぞれのDockerfileを作成します。
# AmazonLinux2 FROM amazonlinux:2 # Apache2.4のインストール RUN yum update -y RUN yum upgrade -y RUN yum install -y httpd EXPOSE 80 CMD ["httpd", "-DFOREGROUND"]
AmazonLinux2はRedhat系列のLinuxでCentOS7以降によく似ています。
今回はApacheを起動するだけの簡単なDockerfileです。
# Debian10 FROM debian:buster-20191014-slim # apache2.4のインストール RUN apt update RUN apt install -y apache2 # Apache2の必要モジュールを有効にする RUN a2enmod cache cache_disk cache_socache EXPOSE 80 CMD ["apache2ctl", "-DFOREGROUND"]
Debianはその名の通りDebian系列のLinuxです。
Ubuntuなどと同系列で、Apacheの設定ファイルの格納場所や実行コマンドなどがAmazonLinux2とはだいぶ異なります。
それぞれをdocker buildしてECRへプッシュするところまで作業を進めておきました。
ECSの準備
AmazonLinux2とDebian用にそれぞれ独立したALBとサービスを作成しておきました。
どちらもCPUの割り当ては0としてMemoryは64MBにしています。
また、この段階では省略していますがApacheの子プロセスの数やタイムアウトの時間など細かな設定はどちらも同じになるようにdocker buildのタイミングで編集してあります。
JMeterで負荷をかける
JMeterを使用して少し軽めの負荷をかけてみることにしました。
DebianではAverageは199となりました。
Debianの方がレスポンスがやや遅いように見えますが、実はアクセス先のページサイズがDebianの方が大きいためその差を考えるとむしろAmazonLinux2よりもやや早いようにも見えます。
今回はそこを合わせていなかったので正確にはわかりませんが、AmazonLinux2とDebianで立ち上げたApacheは設定が同じならパフォーマンスもほぼ同じだと言えると思います。
なぜDebianの方が遅いと言われたのか
AmazonLinux2とDebianで立ち上げたApacheがどちらも同等のパフォーマンスを維持できるのであれば、問題なくDebianのままプロジェクトは進行していたはずです。
しかし実務で使用している検証環境で立ち上げたWebサーバーではパフォーマンスが数倍~10倍近くまで差が出たと報告がありました。
また、「ローカル環境で立ち上げたDebianのコンテナはパフォーマンスに問題なかったが、AWS上で立ち上げた場合にパフォーマンスが劣化した。」との情報も書き込まれていました。
この時点で、1,Apacheの設定の問題 or 2,PHPバージョンアップに伴う問題 or 3,インフラ環境の問題(AWSの構築)に切り分けをすることができますが、ローカル環境での動作を考えると2,は問題なさそうでむしろ3っぽい雰囲気がします。
そこで静的ファイルに対する負荷試験を実施してもらったところ、静的なファイルに対するアクセスはパフォーマンスの劣化がほとんど発生しなかったことが分かりました。
ということでAWSの構築を疑いました。
仮説
仮説としては、おそらくアベイラビリティゾーンの違いによるものだと思います。
ECS用のEC2インスタンスのスペックはDebianのコンテナが立ち上がっている方が高かったのですが、Debianコンテナが立ち上がっているEC2インスタンスはAZ-aにあるものでした。
そして比較対象となっていたAmazonLinux2のコンテナが立ち上がっているEC2インスタンスはAZ-cに存在していました。
開発環境のためRDSやElastiCacheがマルチAZ構成になっておらず、RDSはリーダーがAZ-cに、ElastiCacheはAZ-cのみにノードが存在している状態でした。
仮説の検証
RDSのインスタンスがAZ-dにしかない状態を用意しました。
そこでDebianとAmazonLinux2でそれぞれ高負荷をかけてレスポンスタイムを測定します。
◆Debian編
AZ-dに立っているインスタンス上にDebianのコンテナが立っています。
この時のAverageは1072でした。
続いてAZ-cに立っているインスタンス上にDebianのコンテナを立て直しました。
すると3000リクエスト達成せずにJMeterが停止してしまい、Averageは2810となりました。
おそらく、最終的に処理が詰まってしまっています。
◆AmazonLinux2編
AZ-dに立っているインスタンス上にAmazonLinux2のコンテナが立っていますが、この時のAverageは1725でした。
続いてドレイニングを実行してAmazonLinux2のコンテナをAZ-aへ移動させました。
するとこちらも3000リクエストを達成せずに終了となり、Averageは3919となりました。
結論・・・?
Webサーバーとそれを取り巻く環境でアベイラビリティゾーンが異なる場合にはパフォーマンスへ影響することが分かりました。
これはマルチAZ構成にすることである程度の緩和ができるはずです。
この特性からデータベース系のサービスの場合では、マスターのインスタンスはどうしても単一AZになってしまうため書き込みのパフォーマンスのみAZごとに差が出てしまう可能性は高いです。
とりあえず、今回の件はきちんと対照実験されていなかったことに問題がありそうなので、負荷試験やパフォーマンス調査の時は比較対象のインフラ環境はきちんと合わせて行いたいですね。
これで解決とはいかない!
・・・と、このまま終われば良かったのですが、そうは問屋が卸さない!
なんと、業務での環境においてアベイラビリティゾーンを揃えて検証したところ、Debian環境の方がAmazonLinux2環境よりやや遅かったのです!!
いやいや、そんな筈は・・・???
と調べてみてもどちらの環境もApacheはpreforkeで動作しており、子プロセスの数もKeepAliveなどの設定も同じ。
読み込ませているモジュールはDebianの方が少なかったので、これをAmazonLinux2に合わせてみても結果は変わらず。
Debian系のApacheとRedhat系のApacheは設定方法が異なるため、何かしらで設定が漏れている可能性はありそうですが、現状ではそれを特定するに至りませんでした。
気が付いたことといえば両方の環境に同じ負荷を掛けてみると、AmazonLinux2はApacheの子プロセスを80個くらいRunにして捌いているのに対してDebianの方は20個くらいしか起動していませんでした。
※どちらも子プロセスは常に100個作成される設定で、Run状態ではないプロセスはSleepになっていました。
また、Apacheの子プロセスが起動した際に割り当てられる仮想メモリと実メモリもAmazonLinux2のものよりも少ない値になっていました。
この辺りがApacheのどの設定で制御されているのか不明ですが、DebianとAmazonLinux2での差分がありそうなところはカーネル設定やモジュールの導入先による差分くらいしか見当たりません。
静的ファイルに対してはレイテンシーが少ないことから、PHP側の影響もあるのかもしれません。
とりあえず、解決には至りませんでしたが、こういった現象があったので記事として共有いたします。
答えを知っている人がいたら是非とも教えてくださいね・・・!!!
コメントを残す