phpcon2017に参加した

phpcon2017に参加したのでざっくりメモ。

※参加しながらのメモなので随時更新します。

「OPcacheの最適化器の今」

スライド:

www.slideshare.net

PHPを実行時はバイトコード命令にコンパイルして逐次実行している。

OPchaceの役割

キャッシュ済みならキャッシュからバイトコード命令を実行する

キャッシュ済みでないならコンパイルしてキャッシュする

コンパイル時に最適化しておけばはやくなるんじゃね?これだ!!

PHP5.5の最適化

  • 定数式の置き換え
    • 計算が必要な定数をあらかじめ計算しておくなど
  • 条件分岐の置き換え
    • 実行時には条件分岐が決まってるので計算しておく
  • 連続ジャンプの短絡
    • 省略できるif文などは省略
  • 制御フローグラフ
  • グラフ構造を表現しておき、必要な命令だけを残す

PHP5.6の最適化

  • 関数呼び出しの効率化
  • 未使用リテラルの削除

PHP7.0の最適化

  • 関数スタックフレームの最適化 そんなに大きく変わってない

PHP7.1の最適化

  • コールグラフの構築
    • 関数間の呼び出し関係をグラフ構造に表現し、最適化する
  • データフロー解析に基づく最適化
    • プログラムの各点でデータが取り得る値を解析する

PHP7.2の最適化

  • 定数の伝播
  • 不要コードの除去
  • 未使用変数の除去
    • 使わない変数を除去する

PHP7.2にしよう!!

Lancersのバージョンアップ施策について

過去にもリプレースしようとしたが、2年かかる見積もりだったので、ペンドになった。 要因としてソースコードが肥大化していた。ソースコード全体で約60万行くらいあった。

目的

  • 開発リソースの最大化
  • サポートが終了している
  • Cake1.3もサポートが、、

バージョンアップの前準備として

今あるユニットテストを動くようにする。Nginx + php-fpmで動くようにする。

段階的にあげるように戦略を立てた。 推進者一人、インフラ担当一人、アプリエンジニア一人。

Cake1.3から2.8で詰まったところ

アップグレードシェルの実行だけでは動かなかった。変更点のドキュメントを読み修正していく必要があった。 ヘルパーの仕様が変わってた部分については、ラッパークラスを作成する事で対応していった。

進め方

アップデートしたブランチを作成し、そこで動作確認しつつ修正を加えていく。 毎週masterから差分を取り込むのが大変、、同じような修正が必要になる。 →オレオレUpgradeShellを作った。

事前にCakePHP1.3でできることは先にやっていく。

まとめて切り替えるのではなく、1コントローラーずつ以降していく事で安全に切り替える。 →1.3と2.8の同居をさせるためにindex.phpに細工を入れる。

今後の進め方

PHPのバージョンアップはカナリアテスト。CakePHPのバージョンアップは2バージョンを用意しながら少しずつ進めていく。Codeceptionを利用していく。ユニットテストも2バージョンを用意していく。

まとめ

  • 事前にできることはやっておく
  • Upgrade Shell が全てをやってはくれない
  • 実はバージョン同居できる

質問

  • どれくらいの以降期間を想定しているか?
    • 1年から1年半程度
  • エンジニアではない関係者にどのように説得したか?
    • 開発速度を早めることができますよ、今の施策やりながら裏でアップデートしますよ。というような伝え方。
  • 3系にあげる際の戦略はありますか?
    • 基本的には2系にあげる時と同じやり方を考えています。

Serverless FrameworkでAWSフルマネージドなツールをいくつか作って得たアーキテクチャ設計の知見

スライドは後日公開されるらしい

サーバーレスアーキテクチャ

※諸説ある - イベントドリブン - サーバ単位ではなくイベント単位 - ステートレス - 実行後のコンテナは破棄されるのでステートレスなアーキテクトが求められる

いわゆるLAMPアーキテクチャでは開発者がOSから環境まで、管理する必要がある。 それに対してサーバレスアーキテクチャではイベントを管理、実行を管理する必要がある。 開発者は動くための関数だけを管理すれば良い。

Serverless Frameworkとは何か

インフラもアプリも一括管理できるデプロイツール

サーバレスアーキテクチャで開発する際に気をつける事

  • LAMPアーキテクチャではない事を知る。
    • ステートをモテない
    • 安易にRDMSを使用するとアンチパターン
    • 画像などのバイナリの取り扱いは難しい(リクエスト・レスポンス制限)
    • 認証・認可の仕組み
  • マネージドサービスを知る

サーバレスアーキテクチャでの設計やアイデア

tipsみたいなもの - POST with config - 設定値もステートなので、POSTに含めてしまう - Reserved Timestamp ID - 実は一覧を作るのは難しい - S3を使っている - Instant Job Queue - S3 Object Tagging - Env Sync - デプロイ時の環境変数とfunctionが実行されるコンテナの環境変数に設定する

まとめ

サーバレスアーキテクトが得意なものとLAMPアーキテクトが得意なものは違う。サーバレスアーキテクトがハマると強力。 Serverless Frameworkを使うとインフラもコードで管理できる。

広告配信管理システムを支えるPHP ~ レガシーシステムからの段階的移行戦略

speakerdeck.com

価値あるコードをよりよくしたい

下準備

phpmd, phpcpd, phpdcd, phpcs, phan などを使い複雑そうなところを見つける

例外とハンドリング

  1. アプリケーションベース例外を定義
  2. アプリケーショングローバルな例外ハンドラを実装
  3. ロギングとエラー表示

アプリケーションベース例外にユーザ向けのメッセージを表示するためのメンバ変数を定義している。 ロギングも例外の中でやってくれるようにしているので、例外を投げるだけでいい。

NewRelicを使ってモニタリング

パフォーマンスモニタリングもできる。 エラーがどこでどれだけ起きてたかなどを見れる。

コードを消す

PHPStormつかってます。

phpcs + php7ccで洗い出しつつ基本はマニュアル読みながら修正。

どんどん使用していないものは削除。テストも合わせて消す。

遅いテストは生産性を落とす。

Redashにたよる。「それRedashでよくない?このクエリでデータ出せますよ」

「最良のコードは、コードなし」いらないコードはどんどん消そう。コードなしで機能を提供できるならない方がいい。

外部ツールにうまく頼ろう!!

実装ガイドラインを作る

PSR-1,2準拠 + php-cs-fixerのci組み込み

@deprecatedをうまく使い、非推奨なコードを明示。消す前に@deprecated入れて本番で出てないかログを見ることで安心して消せる。

まとめ

まずは守りを固めて、より良いコードをかける体制を作っていく。

DockerでPHPアプリケーションを本番リリースするまで

必要な事 - ローカルでコンテナを作成 - レジストリにコンテナをPUSH - 本番にリリース

K8S, GKE

マネージドな環境をつかうことで簡単にできる

Laravelで作る分析環境 ブースを回った

ここで差がつくエラー処理

メモ: 複数のphpのバージョンで実行結果を見ることができるらしい。便利そう。 3v4l.org

エラー

php7ではパースした時点でエラーになりうるものをエラーとして扱ってくれる。php7は賢いので。 (絶対実行されないif文の中でも)

例外

php5ではExceptionまたはExceptionを継承したクラス

php7ではThrowableを継承したクラス

エラーと例外(エラー)が混在していて扱いが面倒なので、例外(エラー)に統一してやると楽。

開発時、ユニットテストのときはE_ALLで指定してやって、本番ではE_ALL & ~E_NOTICE & ~E_DEPRECATEDしてやるとよい

ローカルのMacとリモートのCentOS7上のtmux2.5とクリップボード共有したい

背景

手元のMacBookPro上にtmuxを導入してクリップボード共有する記事はよく出てくる。 しかし、自分の場合VPS上で作業することが多いので、VPS上に環境構築をしたいと考えた。 (出先や、違うPCから作業することもあるため、手元のマシンに構築するのが面倒だった。) VPS上のCentOS7上にtmux2.5を導入した上でローカルマシンとクリップボードの共有しようとしたが、 意外と記事がなくハマったので記事として残しておこうと思う。

前提条件

ローカルマシン MacBookPro
リモートマシン CentOS7.3
tmux 2.5

※tmuxはすでに導入済みとする

手順

リモートマシン CentOS

xsel をインストールする

$ sudo yum install -y xsel --enablerepo=epel

ssh して使うのでsshの設定を編集
$ vim /etc/ssh/sshd_config

X11Forwarding yes
X11DisplayOffset 10
X11UseLocalhost yes

のようにしておく

sshd リスタート

$ sudo systemctrl restart sshd

tmuxから使えるように設定する
$ vim .tmux.conf

bind-key -T copy-mode-vi y send-keys -X copy-pipe-and-cancel “xsel -ib”

ローカルマシン Mac

x11 接続するために xquartz をインストー
$ brew update
$ brew cask install xquartz
インストール後 Mac再起動する(しないと環境変数DISPLAYがセットされない)
Xauthの作成
$ open /Applications/Utilities/XQuartz.app
# ~/.Xauthorityを作成してくれます
xhostに追加

$ sudo xhost your.server.name

動作確認

リモートマシンにログインして動作確認する。

リモート→ローカル

$ cat /etc/redhat-release | xsel -bi 実行後にローカルマシンで貼り付けして CentOS Linux release 7.3.1611 (Core) のように出ていれば問題ない

ローカル→リモート

ローカルで適当なものをコピーしてリモートで xsel -bo でコピーしたものが出力されていれば問題ない

tmuxで使う

上記の手順でtmuxの設定もしてあるので、そのままtmux上のキーバインドでコピペできます。
※tmuxの設定再読み込みしておくことをお忘れなく

お疲れ様でした。

crontab に設定してある php のバッチが実行されないとき

laravelのスケジュールをcronに設定したのに動かなかったので原因調査をした。 その時のメモ

状況

crontab は下記の状態

$ crontab -l
* * * * * php /project/path/artisan schedule:run >> /dev/null 2>&1

原因調査

cron の生存確認

とりあえずcronが動作しているかを確認した

$ systemctl status crond
● crond.service - Command Scheduler
   Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)
   Active: active (running) since Sat 2017-06-17 21:18:06 JST; 2 days ago
 Main PID: 1927 (crond)
   CGroup: /system.slice/crond.service
           └─1927 /usr/sbin/crond -n

→動いてそう

cronが実行されたときのログを見てみる

$ tail -f /var/log/cron 
Jun 20 18:08:01 133-130-116-162 CROND[17721]: (deploy) CMD (php /project/path/artisan schedule:run >> /dev/null 2>&1)
Jun 20 18:09:01 133-130-116-162 CROND[17773]: (deploy) CMD (php /project/path/artisan schedule:run >> /dev/null 2>&1)

→動いてそう

cron実行時のログを確認

出力する設定に変更し確認する

$ crontab -e
php /web/pengin-news/current/artisan schedule:run >> /project/path/storage/logs/cron.log 2>&1

$ $ tail -f /project/path/storage/logs/cron.log 
/bin/sh: php: command not found
/bin/sh: php: command not found

こいつや!!!!

解決編

どうやらcronが実行される際のpathが下記になっているようでした

# 確認方法
$ crontab -e
*/1 * * * * printenv > /tmp/printenv.txt
$ cat /tmp/printenv.txt
SHELL=/bin/sh
USER=vagrant
PATH=/usr/bin:/bin
PWD=/home/vagrant
LANG=en_US.UTF-8
SHLVL=1
HOME=/home/vagrant
LOGNAME=vagrant
_=/usr/bin/printenv

PATH=/usr/bin:/bin
そう /usr/bin:/bin しか見てないのです。

crontab で pathを定義して解決

which コマンドで php のパスを調査しておき crontab に書いておけば大丈夫でした。

$ which php
/usr/local/php7/bin/php
$ crontab -e
PATH=/usr/bin:/bin:/usr/local/php7/bin

* * * * * php /project/path/artisan schedule:run >> /project/path/storage/logs/cron.log 2>&1
$ tail -f /project/path/storage/logs/cron.log
/bin/sh: php: command not found
No scheduled commands are ready to run.

お疲れさまでした。