とあるIT企業のインフラエンジニア。プライベートでは開発もちょっとやります。
※本ブログの内容はすべて個人の見解であり、所属する企業とは関連ありません。
2023/09/30 暫く更新停止中m
生活・子育て(10)
FaaS(1)
働き方(2)
SaaS(2)
自作PC(6)
IT入門(1)
IaaS(13)
IDaaS(2)
ITIL(1)
PHP(2)
OS(6)
システム監視(1)
コミュニティ(1)
PCアプリ(10)
ストレージ(4)
ブログ(9)
ActiveDirectory(2)
デバイス(7)
旅行(10)
デザイン(3)
カンファレンス(5)
セキュリティ(9)
インフラ(19)
コーディング(11)
ゲーム(28)
インターネット(18)
未分類(8)
149 [今日]
534 [昨日]
【ブログ】EC2上のWebサーバをいまさらHTTP/2に移行した話
2021/07/23
ブログ
お疲れ様です。
しらせです。
先日、毎月恒例となっているEC2サーバ群のメンテナンスをしている時に、
以下のような警告がhttpdのerror_logにガッツリ出ていることに気づきました。
前はこんなの出てなかったような?
と、思いながら調べていると、どうやらhttdpdがMPM(*1)で動いてないなくて、HTTP/2に対応していないことを示すものでした。
そんな馬鹿な?
という事でChromeの開発者ツールで使っているプロトコルを見てみると、、、
確かにHTTP/1.1でした。。。
最近ではQUICの話も出てきていて、早く使いたいなぁなんでお思っていた矢先に。
てっきり、最近のhttpdはデフォでHTTP/2で動いているものだと思い込んでいたので自分の無知にショックでした。
ということで、
EC2上でhttpdとphp74/php80で動いているWebサーバをさっさとHTTP/2に変えようと(いまさら)頑張った話です。
(参考*1)マルチプロセッシングモジュール (MPM) - httpd.apache.org
https://httpd.apache.org/docs/2.2/ja/mpm.html
もくじ
現状確認
まずは現状をしっかり確認するところから。
Chromeの開発者ツールで確認しても確かにHTTP1.1で動いているようです。
本番サーバも自宅の検証用マシンも全て同じ結果でした。
対応方法を調べる
設定で簡単に修正できれるならさっさと直しちゃおうと思っていました。
ところが調べてみるとちょっとすぐには直せなそうな感じでした。(私の知識不足的な意味で)
ざっと調べた限りでは、主な考慮点は以下の通りでした。
- nghttp2かmod_http2が必要
- mod_phpからphp-fpmへの変更が必要
- httpd.confを修正する必要がある
検証環境でテスト
手っ取り早くテストしたいならHyper-V。
CentOS7で適当にマシンを作って、本番で動いているEC2インスタンスから必要な情報を物故抜いて動かします。
AWSのEC2インスタンスに慣れてしまうと、1から環境を作るのが億劫になりますね。
epel、remi、ius入れて、、依存関係を解決して、remiからphp系の各種パッケージをインストール。
iusからhttpdを入れて、、、面倒だ。
この後詳説しますが、Chromeの開発者ツールから接続時のプロトコルをチェックできるのですが、HTTP/2にするためにはいろいろと条件があるみたいです。
最終的にはProtocolが"h2"になるように目指します。
※画像は実施後のもの。
手元の検証環境はの通りです。
- OS
CentOS Linux release 7.9.2009 (Core) - Web
httpd24u 2.4.46 @ius - PHP
7.4.21 @remi-php74
検証環境の構築
epel , remi , ius インストール
# yum -y install "http://rpms.famillecollet.com/enterprise/remi-release-7.rpm"
# yum install -y "https://repo.ius.io/ius-release-el7.rpm"
Nghttp2(HTTP/2コアエンジン)のインストール
mime.typesとBrotli(ブロートリ)のインストール
# yum --enablerepo=epel -y install brotli
(参考)【Linuxサーバー構築(CentOS 7)】最新バージョンのApacheのインストールと設定 (HTTP/2 & SSL対応) 2019年12月現在 - iwatani.tv
https://iwatani.tv/linux-server/centos7-apache/
httpdとmod_sslインストール
# yum --disablerepo=base,epel,extras,updates --enablerepo=ius install mod_ssl
# systemctl enable httpd
その他不足しているパッケージのインストール
※とりあえず動かしたくて適当に入れたので実際のコマンドとは異なります。
phpインストール
php-fpmインストール
php-fpm自動起動
# systemctl enable php-fpm
mpmの有効化とprefork無効化
---
#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so #←コメントアウト
LoadModule mpm_event_module modules/mod_mpm_event.so #←コメント外す ↓最下行に以下を追加
StartServers 3
MinSpareThreads 24
MaxSpareThreads 48
ThreadsPerChild 64
MaxRequestWorkers 128
MaxConnectionsPerChild 0
SetHandler "proxy:fcgi://127.0.0.1:9000"
---
(参考)CentOS7 環境設定 (Apache2.4 EventMPM + php-fpm + php7.4) - qiita.com
https://qiita.com/daichi_pd/items/1d9b4c8bef2579abc670
preforkモジュール無効化
※中身を全てコメントアウトした
php-fpmの拡張子変更
---
security.limit_extensions = .php .html .htm
※.htmlとか.htmとかでもphpを動かしたいので。
httpdとphp-fpmの相互依存関係の設定
---
[Unit]
Description=The Apache HTTP Server
After=network.target remote-fs.target nss-lookup.target
Requires=php-fpm.service #←追加
---
# vi /etc/systemd/system/multi-user.target.wants/php-fpm.service
---
[Unit]
Description=The PHP FastCGI Process Manager
After=syslog.target network.target
Requires=httpd.service #←追加
---
あと、Chroemの開発者ツールで"h2"にするためには暗号化通信が必須になります。
80/TCPでアクセスしてもh2にはならずHTTP/1.1の状態のままになってしまいます。
httpd.confを弄ってh2cとHTTP/1.1を消してh2だけにしてもダメです。
そのためサーバの証明書が必要なんですが検証用に用意するのが面倒なので自己署名証明書で代用しました。
動きました。
Chromeで確認すると全ての通信がh2になっています。
EC2インスタンスを直す
だいたい要領を掴めたのでAWSの本番環境であるEC2インスタンスのほうを修正します。
本番環境はいくつかありますが主に以下の通りです。
php本体をremi-safeから持ってきてしまっている点ご了承ください。
- OS
Amazon Linux 2 - Web
httpd 2.4.48 @amzn2-core - PHP
7.4.21 @remi-safe
- OS
Amazon Linux 2 - Web
httpd 2.4.48 @amzn2-core - PHP
8.0.8 @remi-safe
事前準備
いきなりEC2インスタンスを弄ってぶっ壊しても嫌なので、スナップショットを作成の上、事前にセキュリティグループを修正して自宅回線からのみアクセスを許可としておきます。
中途半端に変な状態で公開されても嫌なので。。
現状確認
httpd
httpdはamzn2-coreから2.4.48が入っています。
あとnghttp2の代わりにmod_http2がすでに入っていますね。素晴らしい。
現在のhttpdの動作も確かにpreforkになっています。
generic-logos-httpd.noarch 18.0.0-4.amzn2 @amzn2-core
httpd.x86_64 2.4.48-2.amzn2 @amzn2-core
httpd-filesystem.noarch 2.4.48-2.amzn2 @amzn2-core
httpd-tools.x86_64 2.4.48-2.amzn2 @amzn2-core
libnghttp2.x86_64 1.41.0-1.amzn2 installed
mod_http2.x86_64 1.15.19-1.amzn2.0.1 @amzn2-core
python-ndg_httpsclient.noarch 0.3.2-1.el7 @epel
$ httpd -V
~~~割愛~~~
Server MPM: prefork
threaded: no
forked: yes (variable process count)
~~~割愛~~~
php
phpはremi-safeから8.0.8が入っていました。
同じようにphp-fpmもインストールしておきました。
oniguruma5php.x86_64 6.9.7.1-1.el7.remi @remi-safe
php80-php.x86_64 8.0.8-1.el7.remi @remi-safe
php80-php-cli.x86_64 8.0.8-1.el7.remi @remi-safe
php80-php-common.x86_64 8.0.8-1.el7.remi @remi-safe
php80-php-devel.x86_64 8.0.8-1.el7.remi @remi-safe
php80-php-fpm.x86_64 8.0.8-1.el7.remi @remi-safe ←php-fpm
php80-php-mbstring.x86_64 8.0.8-1.el7.remi @remi-safe
php80-php-pdo.x86_64 8.0.8-1.el7.remi @remi-safe
php80-php-pear.noarch 1:1.10.12-7.el7.remi @remi-safe
php80-php-process.x86_64 8.0.8-1.el7.remi @remi-safe
php80-php-sodium.x86_64 8.0.8-1.el7.remi @remi-safe
php80-php-xml.x86_64 8.0.8-1.el7.remi @remi-safe
php80-runtime.x86_64 1.0-3.el7.remi @remi-safe
httpdもphpも設定だけで動作できそうです。
設定変更
php80-php-fpmの自動起動
# sudo systemctl enable php80-php-fpm
mpmの有効化とprefork無効化
---
#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so #コメントアウト
LoadModule mpm_event_module modules/mod_mpm_event.so #←コメント外す ↓最下行に以下を追加
StartServers 3
MinSpareThreads 24
MaxSpareThreads 48
ThreadsPerChild 64
MaxRequestWorkers 128
MaxConnectionsPerChild 0
SetHandler "proxy:fcgi://127.0.0.1:9000"
php-fpmの拡張子変更
---
security.limit_extensions = .php .html .htm
php-fpmチューニング
---
pm.max_children = 15
pm.max_spare_servers = 15
pm.max_requests = 512
私の環境とはOSのバージョンが異なりますが、EC2インスタンスがt2.microのためメモリへの労りが必要です。
(参考)CentOS 6.5:nginx,php-fpm環境が「重い」と感じる場合の対応 - blog.offline-net.com
https://blog.offline-net.com/2015/05/09/centos-65-nginx-php-fp%EF%BD%8D-memory-tunables/
依存関係
---
[Unit]
Description=The Apache HTTP Server
After=network.target remote-fs.target nss-lookup.target
Requires=php-fpm.service #←追加
---
# sudo vi /etc/systemd/system/multi-user.target.wants/php80-php-fpm.service
---
[Unit]
Description=The PHP FastCGI Process Manager
After=syslog.target network.target
Requires=httpd.service #←追加
---
動作テストとリリース
設定は以上で完了です。
systemctl restart httpdやphp80-php-fpmを実行して、エラーが出なければ動作しているはずです。
httpdの動作モードも変わっていることが確認できます。
~~~割愛~~~
Server MPM: event
threaded: yes (fixed thread count)
forked: yes (variable process count)
~~~割愛~~~
この時何度リロードしてもHTTP/1.1から変わらない場合は、ブラウザのキャッシュが効いている可能性があります。
ブラウザをシークレットモードで開くなどすると変わります。
変更前と変更後のtopの結果です。
左がHTTP/1.1の以前のもので、右がHTTP/2に変更した直後です。1.1の方はしばらく再起動していなかったので比較としてはNGですね。
最後に/var/logを確認したり細かい動作も見ましたが、大きな問題はなさそうなのでリリースします。
最後にセキュリティグループを戻して公開です。
正直、早くなったかどうかは微妙です。
それでもやっとHTTP/1.1から脱却できたことに達成感がありますね。
その他、参考にさせて頂いたサイトを共有させていただきます。
(参考)
【図解/apache】MPM prefork/worker /event (イベント駆動)の違い~CPUコアの使い方~ - milestone-of-se.nesuke.com
https://milestone-of-se.nesuke.com/sv-basic/linux-basic/apache-mpm-prefork-worker-event/
(参考)CentOS 7.4 で手軽になった HTTP/2 対応 Apache のインストールメモ - blog.apar.jp
https://blog.apar.jp/linux/8339/#toc7
以上
おつかれさまでした。