\積極的に技術発信を行なっております/
▽ Twitter/COLOPL_Tech https://twitter.com/colopl_tech
▽ connpassページ http://colopl.connpass.com
▽ COLOPL Tech Blog http://blog.colopl.dev
サーバー基盤グループ PE チーム 工藤 剛コロプラはなぜゲームアプリケーションでPHP を使い続けるのか
View Slide
22017 年新卒として入社、運用タイトルのサーバーエンジニアを経てSRE チームを経て PE (Platform Engineering) チームへ主にミドルウェアの更新対応やアプリケーションの保守性向上などに取り組んでいるPHP おじさん氏名 :部署名 :自己紹介工藤 剛技術基盤本部 第 3 バックエンドエンジニア部サーバー基盤グループ PE チーム
コロプラにおけるサーバーサイド構成図3引用: 大規模ゲームインフラとしての Kubernetes とノーメンテナンス運用https://speakerdeck.com/toversus/da-gui-mo-kemuinhuratositefalse-kubernetes-tofalsementenansuyun-yong
4コロプラにおける Server たち● API Server○ ステートレスに行える処理■ プレイ開始・終了■ データの取得・生成・永続化○ を採用● Game (Real Time) Server○ ステートフルな処理■ PvP, PvE におけるリレー通信■ Live Streaming における一対多・多対多通信○ を主に使用
なぜ Web 用の言語である PHP をゲームに使うのか?5よくある疑問
なぜ Web 用の言語である PHP をゲームに使うのか?スケールが容易でステートレスなサーバーサイド実装に最適な言語だから6よくある疑問
PHP は求められる要件をほとんど満たしている● スクラップアンドビルドのサイクルを高速化できること○ 高速なイテレーションこそが高品質な製品を産むという考え● ステートレスであること○ ステートを持たず、並列化することで容易にスケールアウトできること● 負荷が予測可能であること○ ガベージコレクションなどがほぼ発生せず、常に安定したパフォーマンスで動作できること● パフォーマンスが良いこと○ 実行効率に優れ、莫大なリクエストを正しく処理できること● 言語レベルの実装を理解できること○ 何かあれば言語の実装を確認し、問題の原因追求ができること7コロプラで求められるアーキテクチャ
コードを書き換えて保存するだけで即時実行することができるコンパイラ型・トランスパイラ型の言語ではどうしても待ちが発生する(インタプリタ型でも機械語へのコンパイルは発生するが、オンデマンドなので待ち時間は短い)8スクラップアンドビルドの高速化実行開始Java☕(bytecode)
とはいいつつも、現状に見合わない部分も...● K8s 環境下では結局コンテナイメージのビルド待ちが発生する● 他言語のコンパイルにかかる時間が大幅に高速化されてきている○ AOT で直接バイナリコードを吐く言語 (Go 等) が優秀● opcache.validate_timestamps=0 環境下では単に書き換えるだけではダメ正直なところ、開発サイクルの高速化というメリットはだいぶ弱くなってきている印象...9スクラップアンドビルドの高速化
Request1 End一般的な SAPI*1 (apache2handler, fpm, cgi 等) ではリクエストごとにステートが破棄される前回実行した結果に依存した処理は PHP だけでは原理的に実装できない*2ため、基本的に実装がステートレスになりスケーラビリティを担保しやすい10ステートレス性Zend Engine + ExtensionRequest1 StartFreeZend Engine + Extension Request1 Working Memory FreeRequest2 StartZend Engine + Extension FreeRequest2 EndZend Engine + Extension Request2 Working Memory Free*1: Server Side API: PHP の実行形態 *2: Extension の導入や常駐化、サードパーティ SAPI などを行えば可能
負荷見積もりにおける理想の姿は "常に一定のスループットを維持" してくれる形ただし、様々な理由からそのようなことにはならない● API ごとのリソース特性の違い (I/O bound, CPU bound, etc…)● キャッシュされていないデータへのアクセスによる待機時間● 実行環境のハードウェアに起因するスループットの変化"詰まり" (スパイク) が発生すると負荷が一部に偏りユーザー体験に影響を及ぼす恐れがあるため、ワーストケースに合わせてサービス影響が出ないような構成を取る必要が生じる(≒ コスト増加)11負荷の予測可能性
Node.js アプリケーションにて GC (Full GC) でスパイクが発生している図(縦軸はレイテンシ)12負荷の予測可能性
PHP は他言語に比べ、比較的負荷予測が容易● スパイク (詰まり) が起きにくい○ "特定の状況下でのみ発生するパフォーマンス劣化" が原理的に起きにくい■ パフォーマンスに大きな影響を与える循環参照 GC をほぼ考慮しなくて良い■ "リクエストが詰まる" ようなことが少なく、 DB など特定のコンポーネントへ突然負荷が集中する状況が起きにくい● リクエストを受けてから実行までの時間にばらつきが少ない○ 仮想マシンのフットプリントが小さく、リクエストを処理可能になるまでの時間が短い● パフォーマンスチューニングが容易○ 負荷試験結果からある程度適切な割当リソース量を見積もりやすい13負荷の予測可能性
PHP はインタプリタの中でもかなりパフォーマンスの良い言語Node.js (V8) には敵わないものの、 JIT を有効にすれば匹敵する性能とはいえここまで CPU バウンドな処理は実際のワークロードにはほぼない14良好なパフォーマンス"一般的なコード" でテストするため実装コードは ChatGPT (GPT-4) で生成コードの手直しや最適化は一切なし40 x 80 で 8192 回走査
OPcache 拡張機能を利用することで実行効率を大幅に向上可能● コードパス解析による最適化● OPcode コンパイル結果の共有メモリ (shm) へのキャッシュ● 定数配列のメモリへのキャッシュ (PHP 7.0 以降)○ 詳細は hnw さんの記事が詳しいですhttps://hnw.hatenablog.com/entry/2020/08/12/212433● preload (実行前事前ロード) (PHP 7.4 以降)● Just-in-Time Compiler (PHP 8.0 以降)○ 実際のワークロードで 10% 程度効率改善を確認15良好なパフォーマンスFPM PMOPcache shmworker worker workerscript script
APCu 拡張を利用することで、 OPcache 同様 shm 領域を簡易的な KVS として利用することができる実際にマスタデータキャッシュ用途で利用しておりパフォーマンスの改善とデータベースの負荷低減に役立っているstore / fetch 時に serialize / unserialize コストがかかるので注意16良好なパフォーマンスFPM PMAPCu shmworker worker workerDB
PHP 自体は C 言語で実装されており、乱雑とはしているがコードの雰囲気を読み取る程度は (HHVM 等に比べて) 比較的容易ビルドツールチェーンやデバッグ関連機能も整備が行き届いておりgdb や lldb を使ったデバッグや Valgrind, LLVM Sanitizer を使ったメモリチェックなども快適で、良い意味で枯れている17言語実装の明瞭性
"何かあった時に自前でなんとかできる" 安心感が PHP にはある!サイボウズさんではパッチを当ててビルドした PHP を使用 (!)● https://speakerdeck.com/akamah/20nian-mononoju-da-regasipurodakutowo-php-8-dot-0niatupudetositaji-nodui-ce-tode-raretazhi-jianコロプラでも PHP Extension を作成・保守しています (OSS)● https://blog.colopl.dev/entry/2023/07/06/110000○ 奇しくもサイボウズさんとほぼ同じものを作っていました18言語実装の透明性
PHP はステートレスなサーバーサイド言語として未だ有望!もちろん解決したい問題がないわけではない● より実行効率を追求したい○ リクエスト単位での初期化を部分的にやめる (RoadRunner, Swoole, FrankenPHP,...)● コンテナ環境での使い勝手を改善したい○ 現状 HTTP サーバーが別途必要● もっと型安全にコードを書きたい● etc...次の PHP Innovator は君だ!!!19まとめ