$30 off During Our Annual Pro Sale. View Details »

Cygamesを支えるPHPと、その高速化の取り組み

Cygames
November 08, 2016

 Cygamesを支えるPHPと、その高速化の取り組み

2016/11/03 PHPカンファレンス 2016

Cygames

November 08, 2016
Tweet

More Decks by Cygames

Other Decks in Technology

Transcript

  1. View Slide

  2. ©  Cygames,  Inc.
    今回お話したいこと
    Cygamesのアプリはピーク時には秒間5万アク
    セス100万クエリを捌く必要があります
    サーバーサイドは、最⾼高のコンテンツを開発し、
    それを⾼高速かつ安定的に提供することを⽬目指して
    います。
    今回はそのサーバー構成/技術や、どのような価
    値観で開発しているかと、⾼高速化の取り組みを紹
    介します!

    View Slide

  3. ©  Cygames,  Inc.
    今回お話したいこと
    • 前半
    • Cygamesのサーバー構成/技術スタック
    • コンテンツ開発に対してのマインドセット
    • 負荷分散/⾼高速化/リリースでの取り組み
    • 後半
    • ⾼高速化のためZephir導⼊入検討
    • Zephirの概要と導⼊入
    • 運⽤用してみてとこれから

    View Slide

  4. ©  Cygames,  Inc.
    ⾃自⼰己紹介
    • ⼩小笠笠原空宙(たかひろ)
    • サーバーサイドエンジニーア
    • ほぼPHP
    • ちょっとperl
    • 2014年年7⽉月 Cygames join
    • その前はモバイルサイト/ソーシャルゲーム開発

    View Slide

  5. ©  Cygames,  Inc.
    ©  Cygames,  Inc.
    5
    ちょっと紹介

    View Slide

  6. ©  Cygames,  Inc.

    View Slide

  7. ©  Cygames,  Inc.

    View Slide

  8. ©  Cygames,  Inc.

    View Slide

  9. ©  Cygames,  Inc.
    ©  Cygames,  Inc.

    View Slide

  10. ©  Cygames,  Inc.
    ©  Cygames,  Inc.
    MySQLに変わるDB
    「 CySQL 」を開発中!
    •シャドーバースポータルで
    ⼀一部稼働済み

    View Slide

  11. ©  Cygames,  Inc.

    View Slide

  12. ©  Cygames,  Inc.
    5000万DL
    300万⼈人プレイ/daily

    View Slide

  13. ©  Cygames,  Inc.
    とあるアプリの現状
    • ⽉月間300億PV
    • ピーク時、秒間5万アクセス
    • ピーク時、秒間100万クエリ
    • 1⽇日のDBのトランザクションデータ増加量量
    • 1〜~2TB
    • 1⽇日のログデータ増加量量
    • 60GB〜~

    View Slide

  14. ©  Cygames,  Inc.
    Cygamesを⽀支えるサーバーサイド
    • サーバー構成/技術スタック
    • 何を、どのように利利⽤用しているのか
    • 開発スタイル/マインドセット
    • どのような価値観で開発しているか
    • 負荷分散/⾼高速化/リリースでの取り組み
    • 開発~∼運⽤用までの取り組み
    • 今/これからの取り組み
    • 今後どう前進しようとしているか

    View Slide

  15. ©  Cygames,  Inc.
    ©  Cygames,  Inc.
    15
    とあるサーバー構成例例

    View Slide

  16. ©  Cygames,  Inc.
    とあるサーバー構成例例(⼤大雑把な)
    Batch PHP
    Node.js
    PHP-‐‑‒FPM
    Nginx
    MySQL
    Memcached
    redis

    View Slide

  17. ©  Cygames,  Inc.
    とあるサーバー構成例例(⼤大雑把な)
    Batch PHP
    Node.js
    PHP-‐‑‒FPM
    Nginx
    MySQL
    Memcached
    redis

    View Slide

  18. ©  Cygames,  Inc.
    とあるサーバー構成例例(⼤大雑把な)
    Batch PHP
    Node.js
    PHP-‐‑‒FPM
    Nginx
    MySQL
    Memcached
    redis

    View Slide

  19. ©  Cygames,  Inc.
    とあるサーバー構成例例(⼤大雑把な)
    Batch PHP
    Node.js
    PHP-‐‑‒FPM
    Nginx
    MySQL
    Memcached
    redis

    View Slide

  20. ©  Cygames,  Inc.
    とあるサーバー構成例例(⼤大雑把な)
    Batch PHP
    Node.js
    PHP-‐‑‒FPM
    Nginx
    MySQL
    Memcached
    redis

    View Slide

  21. ©  Cygames,  Inc.
    とあるサーバー構成例例(⼤大雑把な)
    Batch PHP
    Node.js
    PHP-‐‑‒FPM
    Nginx
    MySQL
    Memcached
    redis

    View Slide

  22. ©  Cygames,  Inc.
    とあるサーバー構成例例(⼤大雑把な)
    Batch PHP
    Node.js
    PHP-‐‑‒FPM
    Nginx
    MySQL
    Memcached
    redis

    View Slide

  23. ©  Cygames,  Inc.
    とあるアプリの周辺技術

    View Slide

  24. ©  Cygames,  Inc.
    とあるアプリの周辺技術
    Ansible
    Vagrant
    Munin
    Mackerel
    Jenkins
    New  Relic
    Google  BigQuery
    Fluentd
    Elasticsearch
    Kibana

    View Slide

  25. ©  Cygames,  Inc.
    ©  Cygames,  Inc.
    25
    開発スタイル
    マインドセット

    View Slide

  26. ©  Cygames,  Inc.
    ©  Cygames,  Inc.
    26
    ⾯面⽩白くなければ
    意味がない

    View Slide

  27. ©  Cygames,  Inc.
    ⾯面⽩白くなければ意味がない
    • ⾯面⽩白さにゴールはない…

    View Slide

  28. ©  Cygames,  Inc.
    ⾯面⽩白くなければ意味がない
    • ⾯面⽩白さにゴールはない…
    • 素早くトライ&エラーを繰り返す
    • 素早く微調整を繰り返す
    • それが⾏行行いやすい実装
    • ⾯面⽩白くなければばっさり捨てることも厭わない

    View Slide

  29. ©  Cygames,  Inc.
    ©  Cygames,  Inc.
    29
    CS最優先

    View Slide

  30. ©  Cygames,  Inc.
    CS(カスタマーサポート)最優先
    • お客様からの問い合わせには即対応
    • 即対応できるようなログの設計
    • ログの可視化ツールの構築
    • 本番環境のデータを複製し、実機で動きを確認
    できる検証環境
    • 確証を持って対応できるように

    View Slide

  31. ©  Cygames,  Inc.
    ©  Cygames,  Inc.
    31
    当たり前のことを
    当たり前にやる

    View Slide

  32. ©  Cygames,  Inc.
    当たり前のことを当たり前にやる
    • ⼩小さな差がピーク時に⼤大きな差に
    • 不不必要な処理理は書かない
    • 不不必要なデータは取得しない
    • 適切切なリファクタリング
    • 運⽤用し易易い実装、拡張しやすい実装
    • ⽇日々の積み重ねが、
    良良くも悪くもピーク時に顕在化する

    View Slide

  33. ©  Cygames,  Inc.
    当たり前のことを当たり前にやる
    • 当たり前のレベルがスピードにつながる
    • ほぼ毎⽇日複数回デプロイ
    • ほぼ常にイベント開催
    • 新機能追加、機能改善、etc
    • PJに関わる⼈人間も多くなる
    • 当たり前のことを増やし、積み上げることで
    チームのレベルを上げていく

    View Slide

  34. ©  Cygames,  Inc.
    ©  Cygames,  Inc.
    34
    負荷分散/⾼高速化/
    リリース
    での取り組み

    View Slide

  35. ©  Cygames,  Inc.
    秒間5万アクセス
    秒間5万アクセスのアクセスを
    捌くため負荷分散/処理理の⾼高速化は
    サーバーサイドの最重要課題!

    View Slide

  36. ©  Cygames,  Inc.
    負荷分散/スケールアウトの取り組み
    • DBは⽔水平、垂直分割
    • キャッシュはTwemproxyで分散
    • Node.jsはNginxでバランシング
    • 各種ログは⾮非同期で保存
    • バッチ処理理できるものはバッチ処理理へ
    • 分散/スケールアウトできるように
    • できるだけキャッシュ
    • 同期処理理は必要最低限に

    View Slide

  37. ©  Cygames,  Inc.
    ©  Cygames,  Inc.
    37
    ⾼高速化の取り組み

    View Slide

  38. ©  Cygames,  Inc.
    プロファイリングの取り組み
    • 「推測するな、計測せよ」
    • New  relicで解析
    • 以前はxhprofなど
    • 重いクエリ、最適化できる処理理などを地道に対応
    • FW側の不不要な処理理なども最適化
    • 4.5秒以上かかったリクエストを⽇日次で集計、通知
    • 検知 ⇔  最適化の地道な対応
    イベント開始><;
    負荷対策リリース\(^o^)/
    レスポンスタイム推移

    View Slide

  39. ©  Cygames,  Inc.
    DB関連での取り組み
    • ボトルネックの多くはDB関連
    • トランザクション中の処理理は最⼩小限に
    • まとめられるクエリはまとめる
    • indexはカーディナリティが⾼高い順に
    • ⽇日次で開発環境で実⾏行行された全クエリをexplain
    • 問題のありそうなクエリは通知

    View Slide

  40. ©  Cygames,  Inc.
    DB関連での取り組み
    • 本番DBのGeneral_̲Log,Slow_̲Queryも解析

    View Slide

  41. ©  Cygames,  Inc.
    DB関連での取り組み
    • 本番DBのGeneral_̲Log,Slow_̲Queryも解析
    • テーブル単位でサマリー
    • ロック、処理理件数など確認できる

    View Slide

  42. ©  Cygames,  Inc.
    DB関連での取り組み
    • 本番DBのGeneral_̲Log,Slow_̲Queryも解析
    • 実際に実⾏行行されたクエリを⼀一覧
    • 渡されたパラメータ等確認
    • 運⽤用の過程でレコードの偏りなどで不不適切切なindex
    が選択されることも

    View Slide

  43. ©  Cygames,  Inc.
    DB関連での取り組み
    • 本番DBのGeneral_̲Log,Slow_̲Queryも解析
    • 対象クエリのexplain表⽰示
    • index,type,partition など確認

    View Slide

  44. ©  Cygames,  Inc.
    DB関連での取り組み
    • とにかくデータがもりもり増えていく
    • トランザクションデータは毎⽇日1~∼2TB単位で増加
    • CS/分析⽤用途の⾏行行動ログも毎⽇日60GB〜~で増加
    • 必要なくなったデータは順次パージしないと
    ディスク容量量を圧迫してしまう

    View Slide

  45. ©  Cygames,  Inc.
    DB関連での取り組み
    • 必要なくなったデータは順次パージ
    • イベント単位でテーブル作成、終了了後にdrop
    • パーティション単位で毎⽇日drop&add
    • 不不要なテーブルは週次でアラートを通知
    • 常に必要なデータのみを保持するように

    View Slide

  46. ©  Cygames,  Inc.
    DB関連での取り組み
    • 数⼗十GBのテーブルを安全にdropする
    • データファイルが⼤大きいとファイル削除時、
    io_̲waitで数秒間ではあるがレスポンス劣劣化
    i. drop対象のデータファイルにhard  link貼る
    ii. drop  table実⾏行行
    iii. hard  linkしたファイルのサイズを切切り詰めた後
    に、remove(linuxのtruncateコマンド)
    • ゆるやかに削除することで数百テーブル、合計数百
    GBのテーブル削除もレスポンス劣劣化なく実⾏行行

    View Slide

  47. ©  Cygames,  Inc.
    リリース時の取り組み
    • リリース前には職種/チーム問わずレビュー
    • 全スタッフ ≒  ゲームユーザ
    • プランナー/エンジニア/デザイナ/バックオフィス
    • ⾯面⽩白いと確信が持てるまでブラッシュアップ
    • リリース前には実際に運⽤用テスト
    • 各種更更新作業などの通常運⽤用リハーサル
    • 緊急デプロイなどの障害対応フローなども確認

    View Slide

  48. ©  Cygames,  Inc.
    ©  Cygames,  Inc.
    48
    今/これからの取り組み

    View Slide

  49. ©  Cygames,  Inc.
    今/これからの取り組み
    • PHP7対応
    • FWのcoreを拡張させている箇所の対応
    • 各種extensionの対応状況の調査
    • 品質と⽣生産性の向上、仕組みづくり
    • ゲーム特有の問題を検知できる仕組み
    • ユニット/E2Eテストだけではない何か
    • Zephirによる⾼高速化/共通化
    • この後詳しく・・・

    View Slide

  50. ©  Cygames,  Inc.
    ⼀一旦まとめ
    • Cygamesサーバーサイドは、最⾼高のコンテン
    ツを開発し、それを⾼高速/安定的な提供を⽬目標
    としています
    • ⽇日々、トライ&エラー/実装⇔計測を地道に繰
    り返し実績を積み上げ、上記の実現を⽬目指して
    います!

    View Slide

  51. ©  Cygames,  Inc.
    ©  Cygames,  Inc.
    Zephirやってみた
    ⼩小笠笠原 空宙

    View Slide

  52. ©  Cygames,  Inc.
    経緯
    • レスポンスの⾼高速化は最優先事項の1つ
    • クエリ/処理理最適化もある程度度やった感
    • (まだまだ最適化できることはあるけど…)
    • 違う⾓角度度からの最適化を⾏行行いたい

    View Slide

  53. ©  Cygames,  Inc.
    Zephir検討への経緯
    • レスポンスの⾼高速化は最優先事項の1つ
    • クエリ/処理理最適化もある程度度やった感
    • (まだまだ最適化できることはあるけど…)
    • 違う⾓角度度からの最適化を⾏行行いたい
    ミドルウェアのバージョン
    上げようぜ!

    View Slide

  54. ©  Cygames,  Inc.
    Zephir検討への経緯
    • レスポンスの⾼高速化は最優先事項の1つ
    • クエリ/処理理最適化もある程度度やった感
    • (まだまだ最適化できることはあるけど…)
    • 違う⾓角度度からの最適化を⾏行行いたい
    ミドルウェアのバージョン
    上げようぜ!
    フレームワーク変えようぜ!

    View Slide

  55. ©  Cygames,  Inc.
    Zephir検討への経緯
    • レスポンスの⾼高速化は最優先事項の1つ
    • クエリ/処理理最適化もある程度度やった感
    • (まだまだ最適化できることはあるけど…)
    • 違う⾓角度度からの最適化を⾏行行いたい
    ミドルウェアのバージョン
    上げようぜ!
    フレームワーク変えようぜ!
    ⾔言語変えようぜ!

    View Slide

  56. ©  Cygames,  Inc.
    Zephir検討への経緯
    • レスポンスの⾼高速化は最優先事項の1つ
    • クエリ/処理理最適化もある程度度やった感
    • (まだまだ最適化できることはあるけど…)
    • 違う⾓角度度からの最適化を⾏行行いたい
    ミドルウェアのバージョン
    上げようぜ!
    フレームワーク変えようぜ!
    ⾔言語変えようぜ!
    ⾯面⽩白くなければ意味がない
    エンジニア的にはやってみたいんだがしかし・・・

    View Slide

  57. ©  Cygames,  Inc.
    Zephir検討への経緯
    • レスポンスの⾼高速化は最優先事項の1つ
    • クエリ/処理理最適化もある程度度やった感
    • (まだまだ最適化できることはあるけど…)
    • 違う⾓角度度からの最適化を⾏行行いたい
    ミドルウェアのバージョン
    上げようぜ!
    フレームワーク変えようぜ!
    ⾔言語変えようぜ!
    ⾯面⽩白くなければ意味がない
    エンジニア的にはやってみたいんだがしかし・・・
    Zephirっていうのが
    あるらしいぞい

    View Slide

  58. ©  Cygames,  Inc.
    Zephirとは
    • PHPerでも簡単にextensionが書ける⾔言語
    • PHPのような記述でextensionが作成できる
    • if⽂文の書式が違う
    • 変数に$使わない
    • 変数上書き時は、let  を使う
    • 静的/動的型⾔言語
    • メモリ管理理等が必要ない
    • ⾼高速FW PhalconはZephirで実装

    View Slide

  59. ©  Cygames,  Inc.
    Zephirについて
    • Hello  World
    namespace  Utils;
    class  Hello
    {
    //say  func
    public  static  function  say()
    {
    echo  "Hello  World!";
    }
    }
    Utils¥Hello::say();    //  prints  Hello  World!
    $zephir build

    View Slide

  60. ©  Cygames,  Inc.
    Extensionが⽣生成/実⾏行行までのフロー
    1. Zephirのスケルトンを作成
    $zephir init utils
    utils
    ├──  ext //Zephirのcore,⽣生成されるextensionなどが配置される

    └──  utils //ここに.zepファイルを作成していく

    View Slide

  61. ©  Cygames,  Inc.
    Extensionが⽣生成/実⾏行行までのフロー
    2.Zephirのファイルを作成
    $vim  utils/hello.zep
    namespace  Utils;
    class  Hello
    {
    public  static  function  say()
    {
    echo  "Hello  World!";
    }
    }

    View Slide

  62. ©  Cygames,  Inc.
    Extensionが⽣生成/実⾏行行までのフロー
    3.Zephirでextension⽣生成→compile
    • ZephirがPHPで.zepファイルを解析
    • C⾔言語のextensionファイル群⽣生成
    • gccでコンパイル、.soファイルをext_̲dirにコピー
    $zephir build
    Compiling...
    Installing...
    Extension  installed!
    Don't  forget  to  restart  your  web  server
    hello.zep
    C⾔言語
    utils ext
    ファイル群
    utils.so
    PHP gcc

    View Slide

  63. ©  Cygames,  Inc.
    どんなソースが⽣生成される?
    • Zephirでフィボナッチ数列列
    • 定義通り再帰でやってみる
    class  Fib
    {
    public  function  calc(int n)  -‐‑‒>  int
    {
    if  n  <  2  {
    return  n;
    }
    return  self::calc(n  -‐‑‒ 1)  +  self::calc(n  -‐‑‒ 2);
    }
    }

    View Slide

  64. ©  Cygames,  Inc.
    どんなソースが⽣生成される?
    PHP_̲METHOD(Utils_̲Fib,  calc)  {
    zval *n_̲param =  NULL,  *_̲0  =  NULL,  *_̲1  =  NULL,  *_̲2  =  NULL;
    int n,  ZEPHIR_̲LAST_̲CALL_̲STATUS;
    ZEPHIR_̲MM_̲GROW();
    zephir_̲fetch_̲params(1,  1,  0,  &n_̲param);
    n  =  zephir_̲get_̲intval(n_̲param);
    if  (n  <  2)  { RETURN_̲MM_̲LONG(n);}
    ZEPHIR_̲INIT_̲VAR(_̲1);
    ZVAL_̲LONG(_̲1,  (n  -‐‑‒ 1));
    ZEPHIR_̲CALL_̲SELF(&_̲0,  "calc",  NULL,  0,  _̲1);
    zephir_̲check_̲call_̲status();
    ZEPHIR_̲INIT_̲NVAR(_̲1);
    ZVAL_̲LONG(_̲1,  (n  -‐‑‒ 2));
    ZEPHIR_̲CALL_̲SELF(&_̲2,  "calc",  NULL,  0,  _̲1);
    zephir_̲check_̲call_̲status();
    zephir_̲add_̲function(return_̲value,  _̲0,  _̲2);
    RETURN_̲MM();
    }

    View Slide

  65. ©  Cygames,  Inc.
    どんなソースが⽣生成される?
    PHP_̲METHOD(Utils_̲Fib,  calc)  {
    zval *n_̲param =  NULL,  *_̲0  =  NULL,  *_̲1  =  NULL,  *_̲2  =  NULL;
    int n,  ZEPHIR_̲LAST_̲CALL_̲STATUS;
    ZEPHIR_̲MM_̲GROW();
    zephir_̲fetch_̲params(1,  1,  0,  &n_̲param);
    n  =  zephir_̲get_̲intval(n_̲param);
    if  (n  <  2)  { RETURN_̲MM_̲LONG(n);}
    ZEPHIR_̲INIT_̲VAR(_̲1);
    ZVAL_̲LONG(_̲1,  (n  -‐‑‒ 1));
    ZEPHIR_̲CALL_̲SELF(&_̲0,  "calc",  NULL,  0,  _̲1);
    zephir_̲check_̲call_̲status();
    ZEPHIR_̲INIT_̲NVAR(_̲1);
    ZVAL_̲LONG(_̲1,  (n  -‐‑‒ 2));
    ZEPHIR_̲CALL_̲SELF(&_̲2,  "calc",  NULL,  0,  _̲1);
    zephir_̲check_̲call_̲status();
    zephir_̲add_̲function(return_̲value,  _̲0,  _̲2);
    RETURN_̲MM();
    }
    int型で⽐比較を
    ⾏行行っている

    View Slide

  66. ©  Cygames,  Inc.
    どんなソースが⽣生成される?
    PHP_̲METHOD(Utils_̲Fib,  calc)  {
    zval *n_̲param =  NULL,  *_̲0  =  NULL,  *_̲1  =  NULL,  *_̲2  =  NULL;
    int n,  ZEPHIR_̲LAST_̲CALL_̲STATUS;
    ZEPHIR_̲MM_̲GROW();
    zephir_̲fetch_̲params(1,  1,  0,  &n_̲param);
    n  =  zephir_̲get_̲intval(n_̲param);
    if  (n  <  2)  { RETURN_̲MM_̲LONG(n);}
    ZEPHIR_̲INIT_̲VAR(_̲1);
    ZVAL_̲LONG(_̲1,  (n  -‐‑‒ 1));
    ZEPHIR_̲CALL_̲SELF(&_̲0,  "calc",  NULL,  0,  _̲1);
    zephir_̲check_̲call_̲status();
    ZEPHIR_̲INIT_̲NVAR(_̲1);
    ZVAL_̲LONG(_̲1,  (n  -‐‑‒ 2));
    ZEPHIR_̲CALL_̲SELF(&_̲2,  "calc",  NULL,  0,  _̲1);
    zephir_̲check_̲call_̲status();
    zephir_̲add_̲function(return_̲value,  _̲0,  _̲2);
    RETURN_̲MM();
    }
    intではなく、
    ZVALで値の
    やり取りをしている

    View Slide

  67. ©  Cygames,  Inc.
    どんなソースが⽣生成される?
    PHP_̲METHOD(Utils_̲Fib,  calc)  {
    zval *n_̲param =  NULL,  *_̲0  =  NULL,  *_̲1  =  NULL,  *_̲2  =  NULL;
    int n,  ZEPHIR_̲LAST_̲CALL_̲STATUS;
    ZEPHIR_̲MM_̲GROW();
    zephir_̲fetch_̲params(1,  1,  0,  &n_̲param);
    n  =  zephir_̲get_̲intval(n_̲param);
    if  (n  <  2)  { RETURN_̲MM_̲LONG(n);}
    ZEPHIR_̲INIT_̲VAR(_̲1);
    ZVAL_̲LONG(_̲1,  (n  -‐‑‒ 1));
    ZEPHIR_̲CALL_̲SELF(&_̲0,  "calc",  NULL,  0,  _̲1);
    zephir_̲check_̲call_̲status();
    ZEPHIR_̲INIT_̲NVAR(_̲1);
    ZVAL_̲LONG(_̲1,  (n  -‐‑‒ 2));
    ZEPHIR_̲CALL_̲SELF(&_̲2,  "calc",  NULL,  0,  _̲1);
    zephir_̲check_̲call_̲status();
    zephir_̲add_̲function(return_̲value,  _̲0,  _̲2);
    RETURN_̲MM();
    }
    再帰部分の
    関数コール

    View Slide

  68. ©  Cygames,  Inc.
    どんなソースが⽣生成される?
    PHP_̲METHOD(Utils_̲Fib,  calc)  {
    zval *n_̲param =  NULL,  *_̲0  =  NULL,  *_̲1  =  NULL,  *_̲2  =  NULL;
    int n,  ZEPHIR_̲LAST_̲CALL_̲STATUS;
    ZEPHIR_̲MM_̲GROW();
    zephir_̲fetch_̲params(1,  1,  0,  &n_̲param);
    n  =  zephir_̲get_̲intval(n_̲param);
    if  (n  <  2)  { RETURN_̲MM_̲LONG(n);}
    ZEPHIR_̲INIT_̲VAR(_̲1);
    ZVAL_̲LONG(_̲1,  (n  -‐‑‒ 1));
    ZEPHIR_̲CALL_̲SELF(&_̲0,  "calc",  NULL,  0,  _̲1);
    zephir_̲check_̲call_̲status();
    ZEPHIR_̲INIT_̲NVAR(_̲1);
    ZVAL_̲LONG(_̲1,  (n  -‐‑‒ 2));
    ZEPHIR_̲CALL_̲SELF(&_̲2,  "calc",  NULL,  0,  _̲1);
    zephir_̲check_̲call_̲status();
    zephir_̲add_̲function(return_̲value,  _̲0,  _̲2);
    RETURN_̲MM();
    }
    ZVALなので
    intの⾜足し算も関数
    コールになっている

    View Slide

  69. ©  Cygames,  Inc.
    Zephirでフィボナッチ数列列
    • ZVALでの値のやりとり、関数コールもほぼ同
    じようなのでそこまで⼤大きな差はでなかった
    • が、ほぼソース変えず⾼高速化
    0
    0.5
    1
    1.5
    2
    2.5
    3
    3.5
    4
    4.5
    PHP Zephir
    90%程度度に
    [s]

    View Slide

  70. ©  Cygames,  Inc.
    ©  Cygames,  Inc.
    70
    もう少し実⽤用的なもの

    View Slide

  71. ©  Cygames,  Inc.
    Zephirでログ出⼒力力
    • fwrite()でtsv形式でファイル出⼒力力
    $fp =  fopen($file,  "a");
    fwrite($fp,  implode("¥t",  $msg_̲arr).PHP_̲EOL);
    fclose($fp);
    public  function  write(string  file,  array  msg_̲arr)
    {
    var fp =  fopen(file,  "a");
    fwrite(fp,  implode("¥t",  msg_̲arr).PHP_̲EOL);
    fclose(fp);
    }

    View Slide

  72. ©  Cygames,  Inc.
    Zephirでログ出⼒力力
    • fwrite()でtsv形式でファイル出⼒力力
    • 単純な関数コールなので差は出にくい
    0
    10
    20
    30
    40
    50
    60
    PHP Zephir
    ほぼ変わらず
    [ms]

    View Slide

  73. ©  Cygames,  Inc.
    ZephirでNGワードチェック
    • NGワード配列列をループさせてstrpos()で検索索
    • NGワードは50語
    public  $ng_̲list=  [“ダメな⾔言葉葉”,“いけない⾔言葉葉”,“やばい⾔言葉葉",…];
    public  function  check($str)
    {
    foreach ($this-‐‑‒>ng_̲list as  $key  =>  $value)  {
    if  (strpos($str,  $value)  !==  false)  {
    $is_̲ng =  true;
    //break;  ⽐比較のためbreakはしない
    }
    }
    }

    View Slide

  74. ©  Cygames,  Inc.
    ZephirでNGワードチェック
    • NGワード配列列をループさせてstrpos()で検索索
    • 配列列が⼤大きくなるほど改善あり
    • strpos()はZephir側で⾼高速化されている
    0
    0.05
    0.1
    0.15
    0.2
    0.25
    0.3
    0.35
    0.4
    PHP Zephir
    約20%程度度に!!
    [ms]

    View Slide

  75. ©  Cygames,  Inc.
    ⼀一旦ここまでわかったこと
    • PHPとの互換性のためZVALでの計算など、
    実質PHPがやっていることと同様の事を⾏行行って
    いる様⼦子。C⾔言語的に最適化の余地はある
    • 配列列処理理などループ処理理などは速くなる
    • Zephirで標準関数のいくつか⾼高速化されている
    • PHPのコードをほぼ変えずに、Zephirの構⽂文
    規則に整えればextension化ができる
    • 引数の型などはチェックは確実に⾏行行う
    • PHPだとwarningでもFATAL  ERRORになる

    View Slide

  76. ©  Cygames,  Inc.
    改めてZephir/extension化すること
    • Pros
    • ⾼高速化できる
    • PJ/FWなど関係なく利利⽤用可能
    • 特定箇所のみに適応できる
    • PHPに戻すことも可能
    • Cons
    • デプロイフローが増える
    • 修正がしにくい

    View Slide

  77. ©  Cygames,  Inc.
    導⼊入箇所例例
    • コード修正がほぼない共通処理理
    • ループを多⽤用する箇所
    • アプリ要件的に多⽤用される処理理
    • Zephir側で⾼高速化された標準関数を多⽤用してい
    る箇所
    • Library/Optimizers/以下

    View Slide

  78. ©  Cygames,  Inc.
    ⼀一部導⼊入してみた結果
    • ゲームアプリで多い抽選処理理で⼀一部適応
    • 2〜~6ms レスポンスタイムの改善

    View Slide

  79. ©  Cygames,  Inc.
    Zephirまとめ
    • やっぱり銀の弾丸はありませんでした(・∀・)
    • 条件さえ合えば影響範囲を絞って適応できる
    • ロールバックも可能
    • ⽤用法と⽤用量量を守りつつ選択肢の⼀一つに

    View Slide

  80. ©  Cygames,  Inc.
    全体まとめ
    • Cygamesは、
    最⾼高のコンテンツを作りたいと思っています
    • それには⾼高速なトライ&エラーが⽋欠かせない
    • 同時に⾼高速なレスポンスも⽋欠かせない
    • それらを両⽴立立させるためPHPを使っています!

    View Slide