約10年ぶりにサービスで稼働しているPHPをバージョンアップした話

この記事は GMOインターネットグループ Advent Calendar 2024 13日目の記事です。

はじめに

皆様はじめまして!GMOペイメントゲートウェイの川原と申します。

普段はWebアプリケーションエンジニアとして決済代行サービスであるPGマルチペイメントサービス(以下「マルペイ」と記載)の開発・運用に従事しており、その中でも主に加盟店様にて取引の確認や設定変更を行っていただくための管理画面(以下「マルペイ管理画面」と記載)を担当しています。

私は数年前からマルペイ管理画面のPHPバージョンアップ対応を行っており、今年その一連の対応を完了させることができました。本記事では、このPHPバージョンアップ対応について共有したいと思います。

バージョンアップの概要

担当しているマルペイ管理画面は言語としてPHP、フレームワークはSymfonyを採用しており、オンプレミスの仮想サーバー上で稼働しています。今回PHPをこれまで使用してきた5.6から8.1へアップグレードし、同時にフレームワークとして使用しているSymfonyについても2.6から5.4へのアップグレードを行いました。

これまでWAFの設置による防御や第三者による定期的な脆弱性診断など、様々な措置によりセキュリティを担保しながらサービス提供を行ってきました。平行して言語のアップグレードも課題として検討してきましたが、各種案件との調整により今回約10年ぶりのバージョンアップ対応となりました。

そのため、PHPやフレームワーク、ライブラリ周りが全て変わっています。型システムの厳格化・大幅拡充などPHPerとしては大変喜ばしい変更点も多いのですが、変更点の多さから対応を進めて行くにあたり困難が予想されました。ライブラリについてはすでに開発終了となっているものもあり、それらの移行も課題となりました。

マルペイ管理画面のシステム概略図

また、クレジットカード業界の規制や社内の事情から、用途別に複数の管理画面が存在している状態となっており、それぞれが画面数の多い大きなシステムとなっています。これらが全て1つのサーバーで稼働していることにより、管理画面単位での段階的なPHPバージョンアップが実施できない状態でした。

そのため、今回は困難が伴いますが全システム一斉にバージョンアップを行う方針で進めました。

具体的な作業

上記の変更を踏まえ、マルペイ管理画面のバージョンアップ対応を進行していきました。全体的なスケジュールとしては、2022年の8月から開発を開始し、2023年7月に単体試験まで完了させました。

システムテストを実施後、同年9月に本番正系へのリリースを行いました。本番リリース後は新旧バージョンの並行稼働期間を設け、発見した不具合については順次修正作業を実施しました。

その後、並行稼働期間に発見した不具合の修正が落ち着いたため、2024年4月に本番副系にもリリースを実施し、PHP 8.1への移行を完了させることができました。

全体スケジュール

バージョンアップ

当初はPHP・Symfonyそれぞれのリリースノートから変更点を洗い出し、階段状にバージョンアップを行っていく方針で対応を進めていました。これは、5.6から8.1にいきなりバージョンを上げようとすると、変更点が多すぎて収集がつかなくなることを懸念してのことでした。

しかし、この方針では対応工数が膨大になることが判明したため、途中から最終的に目標しているバージョンに向けて一気にバージョンアップを行う方針へ変更しました。

バージョンアップ戦略のイメージ

実際のソースコードの修正については以下の方針で進行しました。人数・工数としては、単体試験で検知した不具合修正も含め、最大6人・約11ヶ月で実施しています。

  • PHPは静的解析ツールのPHPCompatibilityを使用し、改修が必須な箇所を洗い出し修正
  • Symfonyについてはリリースノートから大項目単位で修正箇所を洗い出し修正
  • ライブラリについては以下の3分類で対応を実施
     1. 開発継続中
      →バージョンアップ作業時点での最新安定版へバージョンアップ
     2. 後継ライブラリあり
      →後継ライブラリの最新安定版へ移行
     3. 開発終了
      →直接コードを改修して対応

また、PHPの設定値について、バージョンアップにより設定項目の追加や削除があるのはもちろん、既存の設定項目についてもデフォルト値が変更されているものが多いため、全項目について棚卸を実施しています。

  • 設定ファイル内の各項目について、設定値の確認
  • 設定ファイル内に定義が無く、デフォルト値が適用されている項目について、デフォルト値の確認
  • 新規追加された項目について、設定値の検討
  • 削除された項目について、代替項目があるかの確認

PHPの設定値はphp.ini上で定義する以外にも、Apacheやソースコード上から動的に設定値の書き換えができてしまうため、Apacheの設定ファイルやソースコード上から設定を行っている箇所についても、設定値の棚卸を実施しています。

テスト

今回はバージョンアップによりPHPやフレームワークなどの基盤が大きく変更されるため、デグレ確認のため全画面テストを行うことを前提としました。

ただし、ユニットテストやE2Eテストといったテスト自動化はこれまでこれまで行われていなかったため、全画面手動での打鍵テストを行うこととし以下の方針で進めることとしました。

  • まず全画面で実装担当者による単体試験を実施
    →実装担当者最大7人で約4ヶ月間実施(残部分の実装・単体試験の不具合修正と並行して実施)
  • 利用率の高い決済手段など重要度の高い画面のみレビュワーによるシステムテストを実施
    →レビュワー3人で約1ヶ月間実施
  • その他の画面についてはモンキーテストの期間を設け全員で打鍵テストを実施
    →最大6人で約1.5ヶ月間実施

リリース手順・フォールバックの検討

加盟店影響のあるバグはテスト段階で全て検出・修正されるのが理想ではあります。しかし、システムがかなり大きいことと、複数バージョン分の変更が一度に反映されることから、本番リリース後に不具合が発覚することも十分想定されました。

そのためリリースはBlue/Greenデプロイで行い、不具合が発見された際はフォールバックを行うことができるよう進めました。先述の通りマルペイ管理画面はオンプレミス上で稼働しているため、正系に新バージョン・副系に旧バージョンを配置することで、Blue/Greenデプロイを行えるよう工夫しています。

並行稼働期間中は正系にPHP 8.1対応済みのソースコード
副系にPHP 5.6のソースコードをリリースする
  • 検証・本番環境正系のみPHP 8.1へバージョンアップ
  • 検証・本番環境副系はバージョンを上げず並行稼働
  • 稼働に問題ないことを確認後、副系をPHP 8.1にバージョンアップし、全環境PHP 8系へ移行する

新旧バージョンを並行稼働させるにあたり、新規に開発した機能や改修を行った機能については、新旧両方のリポジトリにマージされている必要があります。そのため、バージョンアップ作業が完了後は原則として新バージョンのリポジトリにて各開発を行い、リリース前に旧バージョンリポジトリに対してマージし、旧バージョンで再度動作確認を行ってからリリースする流れとしました。

バージョンアップ起因の不具合が出てきた場合
旧バージョンの副系環境へ切り戻しを実施

新旧並行稼働させることによって、新バージョンの管理画面で何らかの不具合が発生した場合、旧バージョンが動いている副系へ切り戻しを行うことで、振る舞いをバージョンアップ前に戻し加盟店様への影響を最小限にとどめることができます。その後落ち着いて修正を進めていけるため、精神衛生上余裕を持って移行作業を進めていくことができました。

リリース

検証・本番環境でのリリースについては、事前に開発環境でリハーサルを行いながら手順を作成していたこともあり、特に問題なく当日のリリース作業については完了しました。しかし、かなり念入りに準備をして移行作業を行ったものの、それでも大小合わせて不具合を9件発生させてしまいました。

発生した不具合例としては、環境依存文字の含まれたCSVファイルをアップロードしようとすると、バリデーションで弾かれエラーとなってしまった件がありました。調査した結果mbstringの内部処理変更により発生したものであったため、それに合わせて処理を改修することで解決することができました。

  • マルチバイト処理の変更により、文字コードの変換を行った際に意図しない文字化けが発生し、バリデーションを通らないようになる
  • PHP 5.6下の挙動では、文字コード変換時に環境依存文字は「?」(半角クエスチョンマーク)に置換されていたため、その挙動に合うよう環境依存文字を直接「?」に置換する処理を追加し、文字コード変換時に文字化けが発生しないようにして力業で解決

この不具合は環境依存文字を含んだCSVをアップロードするテストを行っていれば事前に検知できた不具合であったため、リリース後に検知されたことが悔やまれる不具合でした。

プロジェクトを振り返って

成果

EOLによるリスクへの対応

マルペイ管理画面で使用していたPHP 5.6は2019年にEOLを迎えています。WAFなどの緩和策でセキュリティは担保していましたが、より本質的な形で解決することができました。

パフォーマンスの向上

開発環境での結果にはなりますが、バージョンアップ前後で比較してレスポンスタイムが2.5倍に向上しています。

開発環境にて実施した負荷試験の結果
Apache Benchを使用して同時接続数20・合計リクエスト数1万回のベンチマークを実施

このパフォーマンス向上はマルペイ管理画面として実装している処理のチューニングでは無く、PHPコアの改善によってもたらされたものになります。PHPはバージョンアップのたび性能が改善しており、5.6と比較して8.0はベンチマーク性能が2倍以上となっています。今回8.1にバージョンアップを実施したことにより、ベンチマーク通りに性能が上がっています。

PHPのベンチマーク結果の推移について
PHPの今とこれから2022 p.8より引用

開発者体験の向上

型システムの改善やシンタックスシュガーの追加など、言語レベルでの改善が進んでいます。定性的ではありますが私自身はかなり快適にコーディングができるようになったと感じています。

成功したポイント

静的解析ツールの活用

PHPCompatibilityを活用することで、PHPのバージョンアップにあたりソースコードの中で最低限修正すべき箇所を抽出することができ、ソースコードの修正を効率化することができました。

ソースコード全体で約150件程度が修正しないといけない箇所として上がってきましたが、そのうち修正が必須となる箇所は1/3の50件程度でした。要修正箇所と今回は修正しなくてもまだ大丈夫な箇所が分かることで、PHPの仕様変更に伴うコード修正を最小限に抑えることができました。

Blue/Greenデプロイによるフォールバックの計画

Blue/Greenデプロイによるフォールバックを取り入れたことで、不具合発見時の加盟店様影響を最小限に抑えることができました。

今回のバージョンアップ対応でも大小合わせて10件程度リリース後に不具合が出てきた中で、フォールバックですぐに旧環境へ戻せたことで、私自身も精神的にかなり助けられました。

反省点

リファクタリングの自動化

PHPの仕様変更部分についてはPHPCompatibilityを使用して作業の効率化ができましたが、Symfonyのアップグレード対応については人力での作業になってしまいました。

今回対応を行う過程で、バージョンアップに伴うリファクタリングを自動化できるRectorという静的解析ツールを知りました。このツールではPHPやフレームワークのアップグレードに伴うリファクタリングを自動化できるため、今後のバージョンアップではRectorの活用を検討していきたいと考えています。

テスト不足による不具合の発生

事前のテストで概ね不具合を潰せていたのですが、テスト観点が一部漏れていたことにより、リリース後に発覚した不具合が複数ありました。

特に先述したCSVアップロードでの不具合について、mbstringに変更が加えられていることは事前にリリースノートから把握していました。そのため、通常の打鍵テストに加え機種依存文字周りのエッジケースがテストできていれば、処理系への依存度が高い不具合をより細かく潰すことができたと感じています。

また、今回は手動テストで進めることとなりましたが、普段からテスト自動化が行われていれば漏れなくテストができ、普段の開発においても品質が向上するため、今後はテスト自動化についても進めていくことが重要と感じました。

終わりに

このバージョンアップは終わりでは無く、今後も継続的にバージョンアップが必要となります。今後は反省点としても述べたリファクタリングやテストの自動化を取り入れることで、継続的なバージョンアップを行う下地を整え、より安全・便利なサービスを加盟店の皆様にご提供できるよう努めていきたいと思います。

今回はかなり泥臭く対応を行っており、一見真新しいことは見当たらないかもしれませんが、何か皆さんの参考になれば幸いです。

ブログの著者欄

川原 帝智

GMOペイメントゲートウェイ株式会社

Webアプリケーションエンジニア | 2021年11月にGMOペイメントゲートウェイ株式会社入社。オンライン決済代行サービスであるPGマルチペイメントサービスの開発・運用を担当しています。

採用情報

関連記事

KEYWORD

採用情報

SNS FOLLOW

GMOインターネットグループのSNSをフォローして最新情報をチェック