ランサーズ(Lancers)エンジニアブログ > PHP > CakePHP > PHP5.6→7.3移行が完了しました

PHP5.6→7.3移行が完了しました

kanazawa|2019年05月30日
CakePHP

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さんに教えてもらい、解決することができました。
大変感謝しております。

※本件、英語ドキュメントには書かれていたのですが、日本語ドキュメントには書かれていていなかったため、追加する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へのアップグレード方法について試行錯誤をしていきたいと思います。