ソースコード20万行の大規模サイトのPHPを5.1から5.4に上げるためにやったことまとめ

仕事で携わっていた大規模商用サイトでPHPのバージョンを5.1から5.4にバージョンアップする作業が今年の9月に無事終わりました。
かれこれ3年近くも要した大変な作業でした。
(3年間そればかりやってたわけではないです、念のためw)
ものすごい苦労したので、他の人の役に立てればと思いノウハウをここに公開します。
まだやってない人は今すぐ着手しましょう!

大規模ってどのくらい?

画面数とバッチ数あわせて500個くらい。
PHPファイルとSmartyテンプレートファイルと単体テストを合わせて1885個。 これらソースコードの行数が合計約20万行。
数え方
$ find app bin test template (中略) -type f \( -name '*.php' -or -name '*.tpl' \) | wc -l
1885
$ find app bin test template (中略) -type f \( -name '*.php' -or -name '*.tpl' \) | xargs wc -l
194568

所要期間

着手しはじめたのが2010年12月ごろ、完了したのが2013年9月だったので何と3年近くかかったことになります。
長引いた原因は、日々の機能追加や運用をしながら孤独に片手間で細々とやってたからです。(単純に人手不足とも言う)
また、PHPバージョンアップと同時にCentOSサーバを5から6にあげることにしたのでサーバ再構築のための工数も含まれています。

後半は仕事仲間が増えてその人が専業でバージョンアップ作業をやってくれたのでだいぶ楽できました。
それと専任のテスターさんたちにも参加していただいたので本番で大きなトラブルなく完了することができました。
感謝感謝です。

サーバ入れ替え作業が終わってPHP5.1の入った古いサーバを削除したときの、まさに「技術的負債」を返済し終わった瞬間の、あのスッキリ感、もう言葉にはできません。

終わってみてこの件に関するRedmineのチケットを数えてみたら70個もありましたw

動機

PHPのバージョンをあげる動機について今さら多くを語る必要はないでしょう。
一番大きい理由はセキュリティリスクでしょう。
二番目に大きい理由はプログラマのモチベーションでしょうか。
array()書くのめんどくさい!!クロージャ使いたい!!
他にもメモリリーク削減とかパフォーマンス向上とか。

遭遇した問題点

  • split, ereg等の非推奨関数があちこちで使われていた
  • Ethna2.3.5がPHP5.3非対応だった
  • htmlspecialcharsの後方互換のない仕様変更
  • サーバ設定・構築手順が「秘伝のタレ」だった

split, ereg系の非推奨関数があちこちで使われていた

PHP5.1時代には普通に使われていた関数のうちいくつかが、PHP5.4時代になるとDEPRECATEDの烙印を押されてしまっていました。
これはもう地道に一つ一つ置き換えていきました。

世の中的に使われている関数たちをそんなに簡単にオワコン化するなよと枕を濡らしてPHPを恨んだこともありましたが、まあオープンソースってそういうものなんでしょう、きっと。(例えばRubyも1.8から1.9で大分変ったとききます)

Ethna2.3.5がPHP5.3非対応だった

使っていたEthnaはバージョン2.3.5で、PHP5.3に非対応でした。
幸い@sotarokさんが PHP5.3に対応させるための改修を進めくれていたので、私はその改修されたソースコードを慎重に自分のプロジェクトに少しづつ適用させていくだけで済みました。
具体的に言うと、
  • オブジェクトを渡すときの参照の&をやめる ( $obj =& new Hoge() みたいなやつ)
  • var をprotectedやpublicなど適切なモディフィエに置き換える
  • その他、PHP4スタイルのコードをPHP5スタイルに書き換える

とはいえ改修範囲は広く、相当慎重にやったのでこれだけで数か月かかった気がします。

htmlspecialcharsの後方互換のない仕様変更

これは泣きました。全俺が泣いた。
PHP5.4のhtmlspecialcharsに非互換問題 | 徳丸浩の日記

Ethnaの最新版が、これのせいでPHP5.4では動きませんでした。
泣いてもしょうがないので、ここはもうえいやっとEthnaをフォークして自分でEthnamという後継プロジェクトを作ってPHP5.4に対応させました。

そのあたりの詳しい話はこちらをどうぞ。

Ethnaの後継プロジェクトEthnam(えすなえむ)をリリースしました。

サーバ設定・構築手順が「秘伝のタレ」だった

よくある話で、サーバを構築したエンジニアはもう既に現場にはおらず、サーバ構築手順書的なものもありませんでした。
ただ、「どうやって構築したかわからないけど問題なく動いてるサーバ」が私の眼前にあるのみでした。

そこで私は稼働中のサーバの設定ファイルを一行づつ丁寧に読み解き、サーバ構築手順をシェルスクリプト化しながら新サーバ構築の準備を進めました。
新しい開発サーバをシェルスクリプト一発で自動構築できたときは、とても感動しました。(このときはまだChefとか知らなかった)
これで秘伝のタレが明文化されてほっとひと安心。

最終的には私が作ったサーバ構築シェルスクリプトを仕事仲間くんがChef化してくれ、そのレシピを使って新サーバを構築するところまでいけました。

バージョンアップで不具合は出たか?

ぶっちゃけ少し不具合出ました。
いくつかあげます。
CentOS6でstrftimeの曜日出力がバグ
PHPのstrftimeで曜日が文字化けするという不具合が出ました。
strftime("%a")
さらに調べてみたらそのサーバ上でC言語でstrftimeを実行した場合も化けるということがわかり、これはどうもCentOS6のバグだったようです。
yum updateしたら直りました。
曜日変換は関数などに依存しないで自前で連想配列でやった方がいいのかもしれません。
よく「車輪の再発明するな」と言われますが、他人が作った車輪はある日突然挙動が変わるというのを痛感しました。
memcache.compress_thresholdのせいでデータが壊れた
サーバを再構築したときに、memcache.compress_thresholdにいつの間にか"20000"という上限が設定されてしまい、データが壊れるという現象に遭遇しました。
これがどういうメカニズムでなぜ起こったのかは忘れました>< 

下記記事と同じような現象だったと記憶しています。
http://d.hatena.ne.jp/sun-basix/20110916/1316195484

(思い出したら詳しく書きます。)

バージョンアップしてよかったこと

メモリリークが激減!!
効果として一番大きかったのはこれです。
PHP5.1はメモリ管理が緩いためメモリリークが頻発していました。リークしすぎてサーバが落ちたこともありました。
PHP5.3あたりでメモリ管理が賢くなったらしく、バージョンをあげたことでリーク度合が激減しました。
おそらくこれが大きく寄与したのかと思われます。
http://www.php.net/manual/ja/features.gc.performance-considerations.php
実行時間の高速化!!
abコマンドで負荷テストをやってみたところ、高負荷時のパフォーマンス(rps)が30%ほどアップしました。
PHP5.1
Requests per second:    39.61 [#/sec] (mean)
Time per request:       1514.886 [ms] (mean)
PHP5.4
Requests per second:    52.07 [#/sec] (mean)
Time per request:       1152.395 [ms] (mean)
最新機能を使える!!
個人的に一番うれしかったのはこれです。
Short Array Syntaxが使える!!
無名関数が使える!!
array_mapとかarray_filterがすっきり書ける!!

あとはPHPと関係ないですが、CentOS6にあげることでSystem Perlがv5.10になったり(sayが使える!)、ファイルシステムがext4になったり(MongoDBがちゃんと動く!)、とにかくいいことずくめでした。

これからのこと

モダンPHPに関して浦島太郎状態なので、空白の3年間をうめるべく精進したいと思います。
まずはComposer使うとこから。
あとPSR-0も。

まとめ

今は毎日PHP5.4が書けるので幸せです。
ありがとう、そしてありがとう。
みなさんも、まだの人はがんばってバージョン上げましょう!

Enjoy new PHP and Linux!

続きを書きました。
20万行の大規模サイトのPHPを5.1から5.4に上げた話の続き
カテゴリ:

人気記事