SREチームの金澤です。
PHP5.6→7.3バージョンアップが完了しました。
PHP5.3→5.6バージョンアップが完了してから約2カ月での移行となりました。
今回、その対応内容と結果を報告したいと思います。
バージョンアップ準備
PHP7化については、有用な記事が数多くありましたので、まずはそれらを参考にさせていただきました。
CakePHP2.10化
PHP5.6化後のライブラリアップデートのタイミングでCakePHP 2.8から2.10にバージョンアップしました。
CakePHP2.9のタイミングでObjectクラスが非推奨になったため、CakeObjectに名前変更しました。
※PHP7ではObjectが予約語になります。
廃止、非推奨となる関数の対応
対応が必要だったのは主に以下の関数です。
- __autoload
- ereg_*
- eregi
- each
- mysql_*
- split
※対応詳細はGithubにまとめました。
これらの関数は、幸いにもそれほど対応は難しくありませんでした。
mcrypt対応
今回、ここに最も時間がかかりました。
PHP7.2からmcryptはコアから削除されるため、使えなくなります。
PECLのmcryptを入れるという回避策もありましたが、この機会にすべてOpenSSLに移行しました。
※こちらも、詳細をGithubにまとめています。
移行の際は、互換性を維持するためにUTを拡張し、OpenSSL移行前、移行後で暗号化された文字列そのものが一致することを確認しながら進めました。
PEAR::Crypt_Blowfish(Blowfish ECB)対応
PEAR::Crypt_Blowfishは内部でmcrypt関数を使用しており、PHP7.3では利用できません。
今回移行した箇所のアルゴリズムはBlowfishのECBモードで、IVを必要としないはずですが、暗号化処理の過程でなぜかIVを生成していたため少々混乱しました。
mcrypt関数はブロック暗号の処理の過程で文字列を固定ブロック長に分解しますが、
最後のブロックの余った部分に0x00パディングを行います。
OpenSSLでこの処理をするオプションが見当たらず苦労しました。
結局、以下のサンプルソースを参考にし、自前で0x00パディングを実装したところ、UTの差分が消えました。
https://www.php.net/manual/ja/function.openssl-encrypt.php
Blowfish CBC対応
mcrypt関数で直接BlowfishのCBCモードで暗号化を行っている箇所があったので、そこもOpenSSLに移行しました。
これも同様に0x00パディングの処理を自前で実装しています。
CakePHP対応
PHP7.3に切り替えた当初、CakePHP側でmcryptのエラーが出てしまい、動作しませんでした。
以下の設定を入れることで対応できます。
Configure::write('Security.useOpenSsl', true);
※当初、PECLのmcryptをインストールして回避しようとしていましたが、
@chimpeiさんに教えてもらい、解決することができました。
大変感謝しております。
useOpenSsl オプションを指定すれば rjindael 以外は動くようにしたのですが、もしかして他にも動かない場所ありました?
— ちんぺい (@chinpei215) May 17, 2019
ありがとうございます!
useOpenSsl設定して確認中です。でも、最初に確認したときに
Warning (2): Use of undefined constant MCRYPT_RIJNDAEL_128 …
も出てたので、結局PECL mcrypt入れないとダメかもしれませんが。
— やきとり (@yakitori009) May 17, 2019
RIJNDAEL 128 なら AES 256 と互換性があるので大丈夫かもしれません。 RJINDAEL 256 は簡単にはできなそうだったので諦めましたが。
— ちんぺい (@chinpei215) May 17, 2019
※本件、英語ドキュメントには書かれていたのですが、日本語ドキュメントには書かれていていなかったため、追加するPRを出しておきました。
phpcc
事前準備で知っている範囲をすべて対応した上で、phpccでチェックを行いました。
(ctpファイルはチェックしないようなので注意が必要です)
このタイミングで、PHP4形式でコンストラクタを記述している箇所が見つかり、対応することができました。
PHP7.3コンテナの構築と切り替え
PHP5.6化のときと同様、開発用コンテナのPHP7.3化から始めました。
ランサーズの開発環境はDockerを利用しており、docker-compose.ymlには以下のように記述しております。
version: '2' services: app: image: xxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/lancers_app:latest hostname: app networks: lancers: ipv4_address: 10.100.6.11 extra_hosts: - "dev.lancers.jp:10.100.50.11" … container_name: app-6-11 volumes: - ~/www:/var/www
PHP5.6環境とPHP7.3環境をすぐに切り替えられるようにしました。
構築したPHP7.3のコンテナはタグ名を7.3とし、docker-compose.override.ymlを以下のように記述します。
version: '2' services: app: image: xxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/lancers_app:7.3
PHP7.3で稼働させたい場合は、このdocker-compose.override.ymlを配置して
$ docker-compose up -d
とすれば、PHP7.3コンテナにすぐに切り替わります。
PHP5.6コンテナに戻したい場合は、imageの行を#でコメントアウトし、再度
$ docker-compose up -d
とすれば戻ります。
PHP7.3対応
検証環境を先んじてPHP7.3に移行し、動作確認を進めました。
PHP-FPMのエラーログを確認しながら非互換を調査。
このフェーズで、主に以下の対応を行いました。
- static宣言していない関数のstatic呼び出し対応
- 引数の数が一致しない関数呼び出しの対応
- スコープの厳密化に伴う対応
PHP7.3化後のパフォーマンス
サーバーレスポンス
移行前に150ms前後であったものが90ms前後に改善。
PHP5.3→5.6のときは約20msほど改善しましたが、その3倍のパフォーマンスアップとなりました。
CPU使用率
CPU使用率はほぼ半減しました。
以下のグラフは1台のみPHP7.3に切り替えたタイミングですが、PHP5.6のサーバーが35%前後なのに対し、PHP7.3のサーバーは15%前後の使用率となっています。
さすがにサーバーを持て余すようになりました。
メモリにも余裕があったので、PHP-FPMのプロセス数はそのままで、サーバーをc5.2xlargeからc5.xlargeにスケールダウンして現在は運用しています。
今後の予定とお知らせ
バージョンアップフェーズについて
ランサーズのPHP、CakePHPバージョンアップは、以下のフェーズに分けて取り組んできました。
Apache + mod_php + PHP 5.3 + CakePHP 1.3
↓(第1フェーズ)約2か月
Nginx + PHP-FPM + PHP 5.3 + CakePHP 1.3
↓(第2フェーズ)約1年超
Nginx + PHP-FPM + PHP 5.3 + CakePHP 2.8
↓(第3フェーズ)約2か月
Nginx + PHP-FPM + PHP 5.6 + CakePHP 2.8
↓(第4フェーズ)約1日
Nginx + PHP-FPM + PHP 5.6 + CakePHP 2.10
↓(第5フェーズ)約2カ月
Nginx + PHP-FPM + PHP 7.3 + CakePHP 2.10
バージョンアップ決断時の
PHP 5.3 + CakePHP 1.3
という構成から、約2年かけて
PHP 7.3 + CakePHP 2.10
までバージョンアップすることができました。
PHP7化は、バージョンアップを決断したときの大きな目標でした。
今回は1つの大きな区切りとなります。
CakeFest2019に登壇します
2019/11/7 – 2019/11/10にCakeFestが東京で開催されます。
CakeFestはCakePHPの世界的なイベントで、2019年は日本で開催されることになりました。
※ランサーズは前回の2017年に続き、2019年もスポンサーになっています。
今回、提出したCFPのうち、「CakePHP3への滑らかな移行を考える」というテーマが採択されました。
CakePHP2から3へのアップグレードは世界的にも大きなテーマであると感じました。
ランサーズでは、CakePHP1.3から2へコントローラー単位で徐々に移行してきましたが、1年以上かかりました。
CakePHP2→3へのアップグレード難易度はそれより高く、かつ普段の開発を止めずに移行することが求められます。
まずはCakeFestに向け、CakePHP3へのアップグレード方法について試行錯誤をしていきたいと思います。