Slide 1

Slide 1 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ ランサーズ PHP7 バージョンアップへの道 https://www.lancers.jp/ 「テクノロジーで、個をエンパワーメントする」

Slide 2

Slide 2 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ ͸͡Ίʹ

Slide 3

Slide 3 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ ⾃⼰紹介 3 ⽒名︓⾦澤 裕毅 出⾝︓宮城県仙台市 ランサーズSRE 略歴︓ ⼤学時代はネットワークを専攻 Windowsパッケージ開発(C++) ASP開発(Java)&インフラ(オンプレ) SNS開発(PHP)&インフラ(オンプレ) 現在はランサーズのSRE

Slide 4

Slide 4 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ 会社概要 会社名︓ランサーズ株式会社 設⽴︓2008年4⽉ 従業員︓約170名 事業︓オンラインマッチング事業 https://www.lancers.jp/ 所在地︓ 〒150-0002 東京都渋⾕区渋⾕ 3-10-13 TOKYU REIT 渋⾕Rビル 9F

Slide 5

Slide 5 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ App S3 ELB App CloudFront Cloud Search Route53 EC2 instance WebSocket ErastiCache Memcached ErastiCache Redis Aurora Reader Aurora Writer EC2 EC2 instance EC2 ●Amazon Linux 2017.03 ○PHP 5.3提供の最終バージョン ●PHP 5.3.29 ○AWS SDK V1&V2 ○CakePHP 1.3.6 ○Composer ○PECL ○PEAR ●Webサーバー ○Apache 2.2 ●Appサーバー ○mod_php ELB WebSocket 2017/03のサーバー構成(バージョンアップ決断時)

Slide 6

Slide 6 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ App S3 ELB App CloudFront Cloud Search Route53 EC2 instance WebSocket ErastiCache Memcached ErastiCache Redis Aurora Reader Aurora Writer Api ELB Api EC2 EC2 instance ErastiCache Redis EC2 EC2 ●Amazon Linux 2018.03 ●PHP 7.3.6(remi) ○AWS SDK V3 ○CakePHP 2.10 ○Composer ●Webサーバー ○Nginx 1.14.1 ●Appサーバー ○PHP-FPM こっちは Python ELB WebSocket 2019/06現在のサーバー構成

Slide 7

Slide 7 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ Docker for Mac(Windows) docker exec 3306 9000 Docker マウント SQLクライアント 開発環境(エディタ) ターミナル ●Docker for Mac(Windows)で構築 ○本番環境とほぼ同じ構成をDockerコンテナで再現 ○DockerマウントでPCとソースを共有 ■開発はPC上のエディタで⾏う Amazon ECR 10.10.6.11 App ランサーズ本体 10.100.106.5 WordPress コーポレート、ブログ 10.100.51.11 MySQL 10.100.6.131 WebSocket メッセージサービス データ⼊り ランサーズの開発環境

Slide 8

Slide 8 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ ソースコード量 ファイル数 行数 ビュー 約2000 約16万 コントローラー 約260 約10万 モデル 約280 約9万 バッチ 約130 約5万 UT 約500 約20万 全体 約3170 約60万

Slide 9

Slide 9 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ όʔδϣϯΞοϓͷྺ࢙

Slide 10

Slide 10 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ バージョンアップの歴史 ˠ ˠ ˠYNPSF ˠ ˠ ˠ 2017/6完了 約2カ⽉ 2019/2/5完了 1年超 PHP5.6に必須 CakePHP2.10に必須 PHP7.3に必須 2019/3/27完了 約2カ⽉ 2019/4/17完了 約1⽇ 2019/5/28完了 約1.5カ⽉ AWS V3化

Slide 11

Slide 11 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ 1)1ˠ όʔδϣϯΞοϓ

Slide 12

Slide 12 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ 以前PHP5.6を試したとき(CakePHP1.3時代) 2017/06/08 01:38:06 [error] 12029#0: *87 FastCGI sent in stderr: "PHP message: PHP Strict Standards: Non-static method Configure::getInstance() should not be called statically in /var/www/lancers/cake/bootstrap.php on line 38 PHP message: PHP Strict Standards: Non-static method CakeLog::handleError() should not be called statically in /var/www/lancers/cake/libs/cake_log.php on line 290 PHP message: PHP Strict Standards: Non-static method CakeLog::handleError() should not be called statically in /var/www/lancers/cake/libs/debugger.php on line 707" while reading response header from upstream, client: 172.17.0.5, server: dev.lancers.jp, request: "GET /user/login?1496853486&ref=header_menu HTTP/1.1", upstream: "fastcgi://unix:/var/run/php-fpm/php-fpm.sock:", host: "dev.lancers.jp", referrer: http://dev.lancers.jp/ PHP message: PHP Warning: curl_setopt() expects parameter 2 to be long, string given in /var/www/lancers/app/vendors/AmazonSDK/lib/requestcore/requestcore.class.php on line 610 [08-Jun-2017 01:44:52] WARNING: [pool www] child 13007 said into stderr: "NOTICE: PHP message: PHP Strict Standards: Non-static method CakeLog::handleError() should not be called statically in /var/www/lancers/cake/libs/cake_log.php on line 290" [08-Jun-2017 01:44:52] WARNING: [pool www] child 13007 said into stderr: "NOTICE: PHP message: PHP Strict Standards: Non-static method CakeLog::handleError() should not be called statically in /var/www/lancers/cake/libs/debugger.php on line 707" [08-Jun-2017 01:44:52] WARNING: [pool www] child 13006 said into stderr: "NOTICE: PHP message: PHP Strict Standards: Non-static method Configure::getInstance() should not be called statically in /var/www/lancers/cake/bootstrap.php on line 38" ●表向きは問題なく表⽰ ○debugレベル0の場合 ●エラーログにWarningが多発 ○CakePHP1.3関連 ○AWS SDK v1関連 ●Nginxのエラーログ ●PHP-FPMのエラーログ

Slide 13

Slide 13 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ PHP5.6のインストール ●PHP5.3時代 ○Amazon Linux 2017.03を利⽤ ■PHP 5.3提供の最終バージョン ○Amazon Linuxのリポジトリからインストール ●PHP5.6 ○Amazon Linux 2018.03最新版を利⽤ ○remiリポジトリからインストール

Slide 14

Slide 14 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ PHP5.3 ⇔ PHP5.6の切り替え ●開発環境のdocker-compose.yml ●docker-compose.override.ymlを以下のように記述 ●↑のdocker-compose.override.ymlを配置して起動 version: '2' services: app: image: xxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/lancers_app:latest hostname: app networks: lancers: ipv4_address: 10.100.6.11 extra_hosts: - "dev.lancers.jp:10.100.50.11" … container_name: app-6-11 volumes: - ~/www:/var/www version: '2' services: app: image: xxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/lancers_app:5.6 $ docker-compose up -d

Slide 15

Slide 15 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ PHP5.6切り替え結果 ●Strict Warningが多発 ○debugレベル2の場合

Slide 16

Slide 16 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ 1)1ˠ όʔδϣϯΞοϓʹ൐͏ରԠ

Slide 17

Slide 17 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ PHP5.6バージョンアップに伴う警告対応 ●親クラスと⼦クラスの引数が合わない ○CakePHP1.3→2.8で引数が変更されたパターン ■PHP5.3では警告されなかった ■Model.php(親クラス) ■WorkTask.php(⼦クラス) ●以下のソースの⼦クラス全関数の引数をチェック ○Model.php ■Behavior.php ○Controller.php ■Component.php Strict Standards: Declaration of WorkTask::afterSave() should be compatible with Model::afterSave($options = Array) public function afterSave($cretated) public function afterSave($created, $options = array()) CakePHP1.3時代のまま これを親クラスと合わせる

Slide 18

Slide 18 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ PHP5.6バージョンアップに伴う警告対応 ●参照を引数に取る関数の対応 ○Strict (2048): Only variables should be passed by reference ●参照が戻り値の関数の対応 ○Strict (2048): Only variables should be assigned by reference $key = array_shift(array_keys($data)); ↓ $keys = array_keys($data); $key = array_shift($keys); $Db =& ConnectionManager::getDataSource($model->useDbConfig); ↓ $Db = ConnectionManager::getDataSource($model->useDbConfig);

Slide 19

Slide 19 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ PHP5.6バージョンアップに伴う警告対応 ●初期化せずにオブジェクトとみなして代⼊(PHP5.4からWaring) ○Warning Error: Creating default object from empty value in ... ●⼊れ⼦にも初期化が必要 $record->type = 'type1ʼ; ↓ $record = new stdclass(); $record->type = 'type1'; $record = new stdclass(); $record->type = 'type1'; $record->fields->key = 'key1ʼ; ↓ $record = new stdclass(); $record->type = 'type1'; $record->fields = new stdclass(); $record->fields->key = 'key1';

Slide 20

Slide 20 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ 1)1ˠ όʔδϣϯΞοϓ݁Ռ

Slide 21

Slide 21 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ サーバーレスポンス ●約20ms改善(160ms前後→140ms前後)

Slide 22

Slide 22 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ バッチ実⾏時間 ●約7時間かかる集計バッチ ○PHP5.3 ■2:00-9:04(実⾏時間︓7:04) ○PHP5.6 ■2:00-8:27(実⾏時間︓6:27) 約37分短縮

Slide 23

Slide 23 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ 1)1Խޙͷ ϥΠϒϥϦΞοϓσʔτ

Slide 24

Slide 24 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ AWS SDKのバージョンアップ ●2019/6/24にAmazon S3のAWS署名バージョン2が廃⽌ ○AWS SDK V3にバージョンアップが必要 ■PHP5.5以上が必要 ●Guzzleも同時にバージョンアップが必要 ○AWS SDK V2はGuzzle V3に依存 ○AWS SDK V3はGuzzleHttp V6に依存 ●Composer 1.7.3以降だとGuzzle V3がインストールできない ○AWS SDK V2もインストールできない ○Composer 1.7.2で⽌めていた $ php composer.phar install Loading composer repositories with package information Installing dependencies (including require-dev) from lock file Your requirements could not be resolved to an installable set of packages. Problem 1 - Conclusion: remove guzzle/guzzle v3.9.3 - don't install guzzle/guzzle v3.9.3|remove guzzlehttp/guzzle v3.8.1 - don't install guzzlehttp/guzzle v3.8.1|don't install guzzle/guzzle v3.9.3 - Installation request for guzzle/guzzle v3.9.3 -> satisfiable by guzzle/guzzle[v3.9.3]. - Installation request for guzzlehttp/guzzle v3.8.1 -> satisfiable by guzzlehttp/guzzle[v3.8.1]. … 延期になったらしい

Slide 25

Slide 25 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ Guzzleのバージョンアップ ●Guzzle 3.9.3 → GuzzleHttp 6.3.3 ○Guzzle¥Http¥Client ■→GuzzleHttp¥Client ○Guzzle¥http¥Url ■→廃⽌ ○Guzzle¥Plugin¥Oauth¥OauthPlugin ■→GuzzleHttp¥Subscriber¥Oauth¥Oauth1 ●composer.jsonに追加が必要 “guzzlehttp/oauth-subscriber": "0.3.*",

Slide 26

Slide 26 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ AWS SDKのバージョンアップ ●Aws¥Common¥Enum¥Region → 削除 ○V3では廃⽌されている ○リテラルで書き直しが必要 ●各サービスのV3対応 ○例︓S3の場合 ○↓ ○※詳細はGitHubで公開 ■https://bit.ly/2IAbYOx $client = S3Client::factory(array( 'key' => Configure::read('AWS.AccessKey'), 'secret' => Configure::read('AWS.SecretKey'), 'region' => Region::AP_NORTHEAST_1, )); $client = new S3Client([ 'version' => 'latest', 'credentials' => [ 'key' => Configure::read('AWS.AccessKey'), 'secret' => Configure::read('AWS.SecretKey'), ], 'region' => 'ap-northeast-1', ]);

Slide 27

Slide 27 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ 1)1ˠ όʔδϣϯΞοϓ४උ

Slide 28

Slide 28 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ CakePHP2.8→2.10バージョンアップ ●CakePHP2.9でObjectクラスが⾮推奨 ○CakeObjectに名前を変更 ■PHP7ではObjectが予約語になる ■↓ ○Mcrypt対応 ■CakePHP2はSecurityライブラリでまだmcryptを使っている ■CakePHP2.10からOpenSSLが選択できるようになった ●以下のOptionで変更可能 Configure::write('Security.useOpenSsl', true); class User extends Object class User extends CakeObject

Slide 29

Slide 29 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ 廃⽌、⾮推奨関数対応 ●廃⽌される関数の対応 ○ereg_* ○eregi ○mysql_* ○split ●⾮推奨関数対応 ○__autoload ■PHP7.2で⾮推奨 ●spl_autoload_register関数に置き換える ●警告対応 ○microtime ●PDOの対応 ○$stmt->bindParam(':param1', $float, PDO::PARAM_INT); ■PHP5.6→⼩数のまま更新 ■PHP7.3→整数に切り捨てて更新 ●PHP7.2のタイミングで仕様変更されたらしい ⼩数なら PARAM_STRにすべき

Slide 30

Slide 30 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ mcrypt対応 ●PHP7.1で⾮推奨。PHP7.2で削除 ○OpenSSLに移⾏が必要 ■※PECLのmcryptを⼊れる回避策はある ■→今回全てOpenSSLに移⾏した ●mcrypt関数のブロック暗号処理 ○⽂字列を固定ブロック⻑に分解 ○最後のブロックの余った部分に0x00パディングを⾏う ■これを⼿動で実装 ●対応したmcrypt暗号形式 ○Blowfish CBCモード ○Blowfish ECBモード ■PEAR::CryptBlowfishで利⽤されていた

Slide 31

Slide 31 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ mcrypt対応 ●Blowfish(CBCモード) ○暗号化 ↓ $resource = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_CBC, ''); mcrypt_generic_init($resource, $key, $iv); $encrypted = mcrypt_generic($resource, $content); mcrypt_generic_deinit($resource); mcrypt_module_close($resource); $l = strlen($key); if ($l < 16) { $key = str_repeat($key, ceil(16 / $l)); } if ($m = strlen($content) % 8) { $content .= str_repeat("¥x00", 8 - $m); } $encrypted = openssl_encrypt($content, 'bf-cbc', $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv); $encrypted = base64_encode($encrypted); ⼿動で0x00パディング OPENSSL_ZERO_PADDING ではダメ

Slide 32

Slide 32 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ mcrypt対応 ●Blowfish(CBCモード) ○復号処理 ↓ $resource = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_CBC, ''); mcrypt_generic_init($resource, $key, $iv); $decrypted = mdecrypt_generic($resource, $content); mcrypt_generic_deinit($resource); mcrypt_module_close($resource); $l = strlen($key); if ($l < 16) { $key = str_repeat($key, ceil(16 / $l)); } $content = base64_decode($content); $decrypted = openssl_decrypt($content, 'bf-cbc', $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv); $decrypted = trim($decrypted);

Slide 33

Slide 33 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ PHP5.6 ⇔ PHP7.3の切り替え ●開発環境のdocker-compose.yml ●docker-compose.override.ymlを以下のように記述 ●↑のdocker-compose.override.ymlを配置して起動 version: '2' services: app: image: xxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/lancers_app:latest hostname: app networks: lancers: ipv4_address: 10.100.6.11 extra_hosts: - "dev.lancers.jp:10.100.50.11" … container_name: app-6-11 volumes: - ~/www:/var/www version: '2' services: app: image: xxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/lancers_app:7.3 $ docker-compose up -d

Slide 34

Slide 34 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ 1)1ˠ όʔδϣϯΞοϓ݁Ռ

Slide 35

Slide 35 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ サーバーレスポンス ●約60ms改善(150ms前後→90ms前後)

Slide 36

Slide 36 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ CPU使⽤率 ●約半分に ○サーバーがオートスケーリングしなくなった ■1⽇中2台体制 ●→半分にスケールダウン PHP5.6 PHP7.3

Slide 37

Slide 37 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ バッチ実⾏時間 ●約7時間かかる集計バッチ ○PHP5.3 ■2:00-9:04(実⾏時間︓7:04) ○PHP5.6 ■2:00-8:27(実⾏時間︓6:27) 約37分短縮 ○PHP7.3 ■2:00-7:44(〜9:55)(実⾏時間︓5:44〜7:55) 期待したほど伸びず

Slide 38

Slide 38 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ ࠓޙͷల๬

Slide 39

Slide 39 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ バージョンアップの歴史 ˠ ˠ ˠYNPSF ˠ ˠ ˠ 2017/6完了 約2カ⽉ 2019/2/5完了 1年超 PHP5.6に必須 CakePHP2.10に必須 PHP7.3に必須 2019/3/27完了 約2カ⽉ 2019/4/17完了 約1⽇ 2019/5/28完了 約1.5カ⽉ AWS V3化

Slide 40

Slide 40 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ CakeFestに登壇します ●サイト ○https://cakefest.org/ ●開催⽇ ○ワークショップ︓2019/11/7〜2019/11/8 ○カンファレンス︓2019/11/9〜2019/11/19 ●登壇テーマ ○CakePHP3への滑らかな移⾏を考える ■11/9 11:10-11:45

Slide 41

Slide 41 text

1)1ΧϯϑΝϨϯε෱Ԭ ϦδΣΫτίϯ ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ