Upgrade to Pro — share decks privately, control downloads, hide ads and more …

「いちユーザーがPHPに新機能を追加するまで/PHPConference 2022」

COLOPL Inc.
September 22, 2022

「いちユーザーがPHPに新機能を追加するまで/PHPConference 2022」

※資料内の参照リンクを選択し閲覧する場合は、ダウンロードをお願いいたします

\積極的に技術発信を行なっております/
▽ Twitter/COLOPL_Tech
https://twitter.com/colopl_tech

▽ connpassページ
http://colopl.connpass.com

▽ COLOPL Tech Blog
http://blog.colopl.dev

COLOPL Inc.

September 22, 2022
Tweet

More Decks by COLOPL Inc.

Other Decks in Technology

Transcript

  1. いちユーザーが PHP に
    新機能を追加するまで
    ~ Random Extension 5.x ~

    View Slide

  2. 氏名  :
    部署  :
    自己紹介
    工藤 剛 / Go Kudo
    2017 年新卒として入社し運用タイトルのサーバー
    エンジニアを経て SRE チームへ
    運用タイトルの PHP のバージョンアップや静的解析
    の導入・保守などを主に担当
    2
    サーバー基盤グループ SRE チーム

    View Slide

  3. ● Random Extension の概要
    ● 提案までの経緯
    ● PHP Internals Mailing List と議論の進め方
    ● RFC の概要及び作成方法
    ● PHP の開発・テストを行うための環境構築とテクニック
    ● マージされるまで、されたあとの作業
    ● まとめ
    3
    Agenda

    View Slide

  4. Random Extension
    の概要
    4

    View Slide

  5. Random Extension
    乱数を用いた処理を提供する組み込みの拡張機能
    特徴
    ● オブジェクト指向な API
    ● 乱数生成器をユーザー定義可能
    ● mt_srand(), mt_rand() とドロップインで交換可能
    ● メルセンヌ・ツイスタよりモダンな RNG の提供
    ● ステートがオブジェクト単位で保持されており安全
    何が嬉しいのかについては後ほど
    5

    View Slide

  6. 6
    Random Extension

    View Slide

  7. 提案までの経緯
    7

    View Slide

  8. コロプラにおけるサーバーサイド構成図
    8
    引用: 大規模ゲームインフラとしての Kubernetes とノーメンテナンス運用
    https://speakerdeck.com/toversus/da-gui-mo-kemuinhuratositefalse-kubernetes-tofalsementenansuyun-yong

    View Slide

  9. 9
    PHP と API Server
    ● API Server
    ○ ステートレスに行える処理
    ■ プレイ開始・終了処理
    ■ データの取得・生成・受け渡し
    ○ リクエスト毎にステートレスな PHP を採用
    ● Game Server
    ○ ステートフルな処理
    ■ PvP, PvE におけるリレー通信
    ■ Live Streaming における一対多・多対多通信
    ○ Go や Node.js を採用
    サーバー側ゲームロジックの大半を PHP で実装

    View Slide

  10. ゲームの根幹を担うデータを生成・反映・保存する処理
    たとえば...
    ● ダンジョンのマップ生成
    ● 与えたり受けたりするダメージの計算
    ● 獲得報酬の抽選
    ゲームでは多くの場合にランダムな数 (乱数) が求められる
    10
    サーバー側ゲームロジックとは

    View Slide

  11. ゲームに求められる乱数の要件
    ● 可能な限りランダムな結果
    ● 結果の再現性
    ○ リプレイ機能やアプリケーションのチート検出のため
    ■ 抽選など結果の再現性よりもより真にランダムであることを求めることもある
    ● 実行速度
    ランダムでありつつ再現性があるという相反する要素を
    満たさなければならない
    11
    ゲームと乱数

    View Slide

  12. 無作為に生成された数値のこと (例: サイコロの出目)
    現代のコンピュータは確定的な計算をしているため
    完全に無作為な数を生成することは不可能 *1
    *1
    真なる乱数がどうしても必要な場合、ハードウェアベースの乱数生成器を搭載する場合もある。最近の
    CPU は熱ノイズなどを利用して乱数を生成する機能を備えており、拡張命令で利用可能だったりする
    (amd64 なら RDRAND, RDSEED 命令, arm64 (v8.5A 以降) なら RNDR 命令)
    各 OS に搭載された CSPRNG (後述) もこれらの TRNG (後述) から生成された値を利用している事が多い
    12
    乱数とは?

    View Slide

  13. 乱数生成機は大まかに以下の形で分類できる
    13
    乱数生成器の分類
    乱数生成器 (RNG: Random Number Generator)
    真性乱数生成器
    (TRNG: True
    Random Number
    Generator)
    例:
    ● ダイス
    ● ノイズ
    ● コインの裏表
    ● etc…
    疑似乱数生成器
    (PRNG: Pseudo Random Number Generator)
    例:
    ● MT19937
    ● Xorshift
    ● Xoshiro
    ● Xoroshiro
    ● PCG
    ● LCG
    ● etc…
    暗号論的擬似乱数生成器
    (CSPRNG:
    Cryptographically Secure
    PRNG)
    例:
    ● Linux getrandom(2)
    ● BSD arc4random(3)
    ● etc…

    View Slide

  14. PHP には再現性のある乱数生成器がすでに実装されている!
    しかし...
    14
    PHP と乱数生成器 (PRNG)

    View Slide

  15. PHP の乱数生成器実装はいろいろな問題を抱えていた...
    https://zenn.dev/zeriyoshi/articles/abd808d1c6d31b
    15
    PHP と乱数生成器 (PRNG)
    注: 記事は私的なものであり、所属する企業としての見解ではありません

    View Slide

  16. 1. メルセンヌ・ツイスタ *1 としてそもそも実装が間違っていた
    ○ PHP 7.1 にて修正された (互換性のため間違った実装も残されている)
    *1: 疑似乱数生成アルゴリズム, 周期が 2^19937 - 1 であることから MT19937 とも
    2. 初期シード *2 が PID と日時で行われている
    ○ PHP 8.1 で直した https://github.com/php/php-src/commit/53ee3f7f897f7ee33a4c45210014648043386e13
    *2: コンテナ環境で利用すると有効なシード値が時刻のみになり、結果が偏る恐れがある
    3. PHP ランタイムに対して状態がグローバル
    ○ 詳細は次ページ
    他にもいろいろ...
    https://zenn.dev/zeriyoshi/articles/abd808d1c6d31b
    16
    PHP の乱数生成器が抱える問題

    View Slide

  17. メルセンヌ・ツイスタの状態 (次に生成される数値の元)が PHP の実行時ランタイ
    ムに対しグローバル
    途中で意図せず mt_rand() を呼び出すとそれ以降の結果がズレる
    17
    "状態がグローバル" とは

    View Slide

  18. 乱数を利用する他の関数でもメルセンヌ・ツイスタの状態を進めてしまう
    ● mt_rand()
    ● shuffle()
    ● str_shuffle()
    ● array_rand()
    何らかの機能追加などでこれらの関数を利用してしまうと
    意図せず再現性が失われる
    18
    "状態がグローバル" とは

    View Slide

  19. PHP 標準のメルセンヌ・ツイスタを安全に利用することは困難
    ● とはいえ、ゲームにおいて乱数を一切用いないというのは不可能
    ● PHP Extension として実装する?
    ○ C 言語のコードを正しくメンテナンスしていけるか
    ○ メモリ・リソースリークを防ぎきれるか
    ○ 上流 (PHP 本体の実装) に適切に追従していけるか
    ○ etc…
    PHP で PRNG を実装できないか?
    19
    乱数問題と解決案

    View Slide

  20. PHP による Xorshift128+ の実装

    特徴
    ● オブジェクトスコープ
    ● デフォルトの初期シードを random_int() で生成
    ● Chromium や Firefox で実績のある Xorshift128+ アルゴリズム
    ● (PHP 実装にしては) 比較的高速
    再現性が求められる用途にはこのライブラリを使用することに
    20
    CRandom

    View Slide

  21. 使用していく中でいくつかの問題が見えてきた
    ● (わかってはいたが) ネイティブ実装に比べて圧倒的に遅い
    ○ 特にシード処理が遅い
    ○ PHP 8.0 から導入された JIT でかなり改善できるが JIT 自体がまだ不安定で見送り
    ● 実装を切り替えることができない
    ○ "特定の要件を満たすまで乱数を生成し続ける" ワークロードの負荷試験が困難
    ○ 負荷試験環境ではシード値固定の PRNG を、本番環境では CSPRNG を利用したい
    やっぱりこれ...ネイティブ実装できないかなぁ....
    21
    CRandom の課題

    View Slide

  22. とりあえず作って PECL で公開 (PoC)
    https://github.com/zeriyoshi/php-ext-orng
    22
    orng (Object-scoped Random Number Generator)
    PHP 自体に同じようなも
    のがあったほうが良いの
    では....?

    View Slide

  23. PHP Internals Mailing List (開発者メーリングリスト) に似たような話があった!
    ORNG の実装を整理し、 PHP 本体に機能追加の提案を出してみよう
    23
    過去ログを見てみる

    View Slide

  24. ● ほとんど反応をもらえなかった
    ○ 最初に来たのは "あなたをノックダウンします" という返信
    ○ カタコトなせいで "やべーやつ来たし触らんとこ" みたいな流れになってるのか?と推測
    ■ sorry を連呼しグダグダと弁明
    ● 更なる "やべーやつ" へ...
    ● Nikita 氏がポジティブな返信をくれ、徐々に話が進み始めた
    ○ とはいえ英語力の低さからなかなかうまく進まない...
    ● 意見をまとめられず何度も更新される仕様と実装
    ○ 1.0 から始まったバージョンはついに 5.x に到達...
    24
    PHP Internals Mailing List に突撃

    View Slide

  25. ● PHP Extension を保守していた経験を元に実装を行った
    ○ php-src における作法を理解しきれておらず最初はいびつな実装に...
    ● Windows 環境でのデバッグがつらい (経験がない)
    25
    RFC の内容を実装
    PHP 謹製の Autotools っぽい何か (php-sdk) と
    notepad.exe, cmd.exe, windbg.exe との
    たのしいひととき

    View Slide

  26. いろいろありつつ (後述) も RFC は可決され、 master ブランチにマージされた
    しかし...
    PHP 8.2.0beta1 にて Windows 向けのビルドが SEGV する問題が発生
    26
    無事マージされるも...

    View Slide

  27. ZTS ビルドにて特定のケースで未初期化領域にアクセスしていた...
    27
    SEGV 問題

    View Slide

  28. 28
    謝り癖よくない

    View Slide

  29. Internals ML での議論を積極的に進めてくれた Tim さんがとても協力してくれて
    いる
    29
    バグ修正やリファクタリング

    View Slide

  30. Random Extension のメンテナになった
    30
    Random Extension Maintainer

    View Slide

  31. Docker で手軽に試せるようになった!
    31
    PHP 8.2.0 RC1, 2 がリリース

    View Slide

  32. PHP 8.2.0
    ● ドキュメントの整備 (英, 日)
    ● PHP 8.2.0 ランディングページの整備
    PHP 8.3.0
    ● 検討中
    ○ ランタイムグローバルな RNG 関数 (mt_srand(), mt_rand()) の非推奨化
    ○ 暗黙的にランタイムグローバルな RNG 実装を利用する関数の実装変更
    ■ shuffle()
    ■ str_shuffle()
    ■ array_rand()
    ○ MT_RAND_PHP の非推奨化
    32
    残タスク

    View Slide

  33. タイムライン
    33
    2018
    スコープの問題が社内で広く
    認知され始める
    対策チームが立ち上がる
    超優秀な後輩が CRandom を
    開発
    2019 2020
    Internals ML に最初の提案
    メールを送信
    当時の実装ターゲットは PHP
    8.1 だった
    orng を開発
    2021
    2021
    議論が進展しないため投票へ踏
    み切るも API と実装のいびつさ
    から Declined に
    投票開始と共に大量に寄せられ
    るツッコミの嵐に泣きそうになる
    コンセプトには理解が得られてい
    たので、投票フェーズになってか
    ら指摘された問題を修正した
    RFC を作ることに
    議論を続けるも落とし所が見つ
    からず、モチベが低下
    2022
    8.1 Feature Freeze を目前に
    するも Windows 環境でのデ
    バッグで行き詰まりモチベが終

    手元に Windows マシンが無い
    問題を解決するため会社として
    取り組めないかを相談し、 OK
    をもらう
    致命的だった英語面もチームメ
    ンバーに協力してもらえることに
    じわじわとだが議論も進み
    RFC も改善されてくる
    8.2 Feature Freeze
    目前に投票を開始、無
    事 Accepted
    Supplemental RFC
    master merged

    View Slide

  34. PHP Internals
    Mailing List と
    議論の進め方
    34

    View Slide

  35. PHP Internals Mailing List (以下: Internals ML) とは
    PHP の "内部" にまつわる話題のためのメーリングリスト
    https://www.php.net/mailing-lists.php
    ● 実装の変更・新機能追加の議論
    ● 変更や新機能追加に伴う RFC 作成権限の付与依頼・議論と各種アナウンス
    ● PHP Group 自体の運用に関わる議論
    PHP-ML を見やすくまとめてくれる externals.io が便利
    https://externals.io/
    35

    View Slide

  36. 1. Internals ML に参加する
    2. 提案メールを出してみる (いわゆるジャブ)
    3. RFC を書く (この時点でひとまずの実装・ GitHub への PR を出すと良)
    4. 最低 2 週間ほど議論を行う
    5. RFC の状態を Vote にして ML に告知メールを出す
    6. 2 週間投票を行う
    7. 投票結果に応じて状態を Accepted または Declined に更新し、メールを出す
    参照: https://wiki.php.net/rfc/howto
    36
    Internals ML での大まかな流れ

    View Slide

  37. ● Under Discussion の時に反応がないことが多いがめげない
    ○ Vote フェーズになって議論が突然加速することが多い
    ○ 反応がなさすぎても "もしかして空気読めてない?ごめん" とか言わない
    ○ ML では反応がなくても stackoverflow の Room 11 では触れられてたりも
    ■ あんまり公な場所じゃなさそうなのでチラ見するくらいで
    https://chat.stackoverflow.com/rooms/11/php
    ● 英語は機械翻訳でだいたいなんとかなる
    ○ とはいえスラングとかも結構使われたりする
    ○ 英語がダメダメならある程度は覚悟しておいたほうが良い
    ■ 覚悟しておけばなんとかなるレベル
    ● なんでもかんでも sorry と言わない
    ○ 日本人的な感覚で sorry を使いすぎるのはダメ
    ○ 情緒的ではなく建設的に話をする
    37
    Internals ML での議論のポイント

    View Slide

  38. RFC の概要と
    作成方法
    38

    View Slide

  39. RFC とは
    Request for Comment の略
    ● 現状どういう課題があるのか
    ● どういう解決策があるのか
    ● することによるメリット・デメリット
    を簡潔にまとめたもの
    下位互換性に影響する変更や新機能の追加には
    RFC を作成し、有権者による 2/3 以上の賛成を
    得る必要がある
    39

    View Slide

  40. まずは Internals ML や Room 11 でジャブを打ってみる
    既存の RFC をなんとなく読んでおき、提案内容の RFC の大まかな流れが思いついたら
    wiki.php.net のアカウントを作成して Internals ML に RFC karma のリクエストを送る
    今見るとだいぶ恥ずかしい...
    40
    RFC 作成までの流れ

    View Slide

  41. 具体的には
    ● 提案の概要
    ● より具体的な提案の内容
    ● メリットとデメリット
    ● (必要なら) 将来的な展望
    ● 下位互換性への影響
    を書いていく
    https://wiki.php.net/rfc/rng_extension
    41
    RFC の書き方

    View Slide

  42. ● 過去の RFC を参考にしよう
    ○ 文章のフォーマットみたいなのは過去に即しておけばだいたいなんとかなる
    ○ RFC karma が得られたら他の人のページも見られるので参考に
    ● 人に頼ろう
    ○ ネイティブもしくはそれに近い人がいれば事前に読んでもらえないか頼む
    ○ Twitter にいる日本の PHP 界隈の人たちも見てくれるかも
    ● 正直、めっちゃ難しい
    ○ 秩序立てが困難
    ■ ですます調がだである調になるみたいなのが頻発
    ■ ツッコミの嵐をくらって勝手にメンタルが削れる
    ● 相手に悪意があるわけではないので考えすぎないのが吉
    ○ 英語で論文とか書いたことがあれば苦でもない? (書いたこと無い)
    42
    RFC の書き方のポイント

    View Slide

  43. 環境構築と
    テクニック
    43

    View Slide

  44. PHP の技術スタック
    ● 言語は基本的に C (C99), m4 (Autotools)
    ● 対応するプラットフォームは Unix-like OS (含 macOS), Windows
    ● 複数のスレッドモデル
    ○ NTS: Non-Thread Safe (Unix-like OS での標準)
    ○ ZTS: Zend Thread Safe (スレッドセーフ, Windows IIS での標準)
    ● 複数の SAPI
    cli: Command Line Interface, fpm: FastCGI Process Manager
    apache2handler: Apache, cgi: CGI, etc...
    44

    View Slide

  45. ● Ubuntu ベースで環境を構築すると楽
    ○ PHP 本体の CI でも使われているのでパイプラインを参考にできる
    https://github.com/php/php-src/blob/master/azure/job.yml
    ○ ってかだいたい既存の CI パイプラインを参考にすればなんとかなる
    ● Docker を活用する
    ○ static QEMU + binfmt_misc で他のアーキテクチャを利用可能にしておくと楽
    ○ Docker Desktop for Mac なら標準で QEMU が組み込まれているので何もしなくていい
    ○ ビッグエンディアン (IBM s390x など) な環境も簡単に作れる
    ● 開発マシンには amd64 (非 Apple Silicon マシン) を使うと快適
    ○ 32-bit (i386) 環境でのテストが速い
    このあたりをしっかり説明すると発表に収まらなくなるので
    後日 COLOPL Tech Blog あたりに書きたい...
    45
    PHP 開発 Tips 1

    View Slide

  46. ● 基本的なビルドからテストまでの道のり
    ○ $ ./buildconf —force
    ○ $ ./configure —enable-debug
    ○ $ make -j$(nproc)
    ○ $ make test
    ● 開発に使えるツールを把握しておく
    ○ Valgrind
    ■ https://valgrind.org/
    ■ ./configure で —with-valgrind の指定が必要
    ○ LLVM Sanitizer (ASan, MSan, UBSan)
    ■ https://github.com/google/sanitizers
    ■ Clang でオプションを指定してビルドする必要がある
    ○ Zend Memory Manager によるメモリ管理が行われるとデバッグが困難になるので
    環境変数に USE_ZEND_ALLOC=0 を指定すること (OS 標準のメモリ確保関数を使う)
    46
    PHP 開発 Tips 2

    View Slide

  47. ● PHP 本体のテストフレームワーク (PHPT) を覚えよう
    ○ Random Extension の例:
    https://github.com/php/php-src/tree/master/ext/random/tests
    ○ run-tests.php で実行する
    ■ make コマンドで実行したほうが楽かも
    $ TEST_PHP_ARGS="./ext/random/tests" make test
    ● クラスや関数の定義は PHP ファイルで行う (ようになった)
    ○ Random Extension の例:
    https://github.com/php/php-src/blob/master/ext/random/random.stub.php
    ○ 編集したら以下を実行して C ヘッダファイルを生成 (要 PHP)
    $ ./build/gen-stub.php —force-regeneration —generate-optimizer-info
    47
    PHP 開発 Tips 2

    View Slide

  48. あとは
    既存の実装を見つつ真似すれば
    わりとなんとかなる!
    48

    View Slide

  49. わからないことがあったら Twitter とかで聞いてください
    多分私もわからないので一緒に悩みます
    49
    相談所のご案内

    View Slide

  50. マージされるまで・
    されたあとの
    作業について
    50

    View Slide

  51. マージされるまで
    実装が完了したら https://github.com/php/php-src に PR を作成
    https://github.com/php/php-src/pull/8094
    GitHub を見ていない人もいるので RFC についての議論は GitHub ではなく
    Internals ML で行うこと
    その他は特に変わった部分はない
    51

    View Slide

  52. 不備や不具合などが見つかると Internals ML で指摘をもらったり GitHub の
    Issue が立つので定期的に確認しておく (両方見ておくこと)
    必要に応じて修正し、 Pull Requestを作成する
    52
    マージされたあと

    View Slide

  53. マージされた後に RFC を伴うレベルの変更が必要になった場合、追加の RFC を
    作成する場合がある (所謂 Supplemental RFC)
    過去の例
    ● Shorter Attribute Syntax
    https://wiki.php.net/rfc/shorter_attribute_syntax
    ○ Shorter Attribute Syntax Change
    https://wiki.php.net/rfc/shorter_attribute_syntax_change
    ● Attributes (v2)
    https://wiki.php.net/rfc/attributes_v2
    ○ Attribute Amendments
    https://wiki.php.net/rfc/attribute_amendments
    53
    補足的な変更が必要になった場合

    View Slide

  54. ● Feature Freeze に間に合う場合
    ○ RFC を新規に作成し、通常通り投票を行う
    ○ Random Extension でも発生した
    ■ https://wiki.php.net/rfc/random_extension_improvement
    ● Feature Freeze に間に合わない場合
    ○ RFC を介さない (対象バージョンの Release Manager 及び Internals ML での議論ベー
    ス) の変更を行う必要が生じる
    ■ これ自体そもそも良いことではない
    ○ こちらも Random Extension で発生してしまった
    ■ https://externals.io/message/118290
    期限ギリギリで RFC を作成するのは危険
    54
    Supplemental RFC の注意点

    View Slide

  55. まとめ
    55

    View Slide

  56. タスクリスト
    1. 言語改善のためのアイディア考案
    2. 実現可能か調査・検討
    3. アイディアの共有・ブラッシュアップ
    ○ Internals ML, Twitter, stackoverflow Room 11…
    4. Pull Request 作成
    5. (なければ) RFC karma のリクエスト, RFC 作成
    6. Internals ML での議論・投票
    7. Pull Request のレビュー対応
    8. ドキュメントの整備
    9. リリース!
    56

    View Slide

  57. 振り返り
    ● 機能実装・整理に関してはコツさえ掴めばかなり直感的
    ○ そこまでゴリゴリに C 言語っぽい感じではない
    ■ 確かに Zephir みたいなアプローチをしてみたくなる気持ちもわかる
    ○ ある程度の慣れは必要そう
    ● コミュニティの課題も見えてきた
    ○ Random Extension に限らずどの RFC も投票フェーズになって初めて議論が進む傾向
    ■ stackoverflow Room 11 はカジュアルに話ができて良いが、通常のルートからは
    たどり着けない...
    ● 現状半公式みたいになってるけどいっそ公式にしてほしい気持ち
    ● コミュニケーションの難しさ
    ○ ニホンジン エイゴ ニガテ
    ○ 今からでも本気で英会話勉強しようかなという気持ちが芽生えた
    57

    View Slide

  58. コロプラではエンターテインメントで日常をより楽しくする仲間を募集しています
    ● Google Cloud Spanner や Kubernetes (GKE) を用いた開発
    ● PHP, Go を用いたゲームアプリケーション開発
    ● OSS 活動も積極的に進めています
    https://github.com/colopl
    https://be-ars.colopl.co.jp/recruit/career/
    技術ブログもよろしくお願いします!
    https://blog.colopl.dev/
    58
    We are Hiring!

    View Slide

  59. 質疑応答
    59

    View Slide

  60. 60
    ご清聴
    ありがとう
    ございました

    View Slide