Slide 1

Slide 1 text

© 2022 New Relic, Inc. All rights reserved 推測するな、計測せよ New Relic × Laravel 実践 Yuzuru Ohira & mpyw PHPerKaigi 2023 Day1 (発表時の内容に加筆修正済み)

Slide 2

Slide 2 text

© 2022 New Relic, Inc. All rights reserved 自己紹介 Joe 氏とは以前の職場での知り合い。 最近 PHP を書く機会が激減して少し寂しくなっている… @mpyw PHPerKaigi 初登壇です!

Slide 3

Slide 3 text

パクツイ 登壇しろという圧を感じていたところに 都合よく依頼が飛んできたので便乗

Slide 4

Slide 4 text

© 2022 New Relic, Inc. All rights reserved New Relic の 導入と実演

Slide 5

Slide 5 text

© 2022 New Relic, Inc. All rights reserved New Relic の導入と実演 Ⅰ 題材とする Laravel アプリの簡単な紹介 Ⅱ New Relic Agent を Laravel アプリに導入 Ⅲ New Relic APM の基本的な仕組み Ⅳ New Relic を使った Laravel アプリの改善

Slide 6

Slide 6 text

© 2022 New Relic, Inc. All rights reserved. 題材とする Laravel アプリの簡単な紹介 ● 総務省が提供する Excel 統計データを整形して使用 ● 項目 ○ 全人口, 男性人口, 女性人口, 人口密度, 若年層人口, 高齢者人口, etc… ○ 計 27 項目 ● 自治体 ○ Prefectures (都道府県 + 全国): 48 ○ Cities (市町村 + 東京23区): 1742 ○ Districts (区): 175 大量の人口統計を表示・編集するアプリ 27 × (48+1742+175) = 53055 個

Slide 7

Slide 7 text

© 2022 New Relic, Inc. All rights reserved. 題材とする Laravel アプリの簡単な紹介 バックエンドのテーブル構成

Slide 8

Slide 8 text

© 2022 New Relic, Inc. All rights reserved. クリックすると 展開表示 遅延表示しているだけ 遅延取得はしていない これらを一気に表示・送信する巨大フォーム

Slide 9

Slide 9 text

© 2022 New Relic, Inc. All rights reserved. 題材とする Laravel アプリの簡単な紹介 ● (読込)Eager Loading, Lazy Loading の切り替え ● (更新)Validator の切り替え (デモの都合上)バックエンドの動作を切り替える機能を搭載

Slide 10

Slide 10 text

© 2022 New Relic, Inc. All rights reserved New Relic の導入と実演 Ⅰ 題材とする Laravel アプリの簡単な紹介 Ⅱ New Relic Agent を Laravel アプリに導入 Ⅲ New Relic APM の基本的な仕組み Ⅳ New Relic を使った Laravel アプリの改善

Slide 11

Slide 11 text

© 2022 New Relic, Inc. All rights reserved. New Relic Agent を Laravel アプリに導入 ● ガイドインストール機能! (初心者はとりあえずこれで) ● PHPer の方はだいたい APM → PHP → Docker を 選んでおけばいいと思います ● 時間の都合上ポチポチする部分は省略 具体的な導入手順 https://github.com/mpyw-yattemita/phperkaigi2023-laravel-newrelic-performance 少しアレンジして整備した見本 ↓

Slide 12

Slide 12 text

© 2022 New Relic, Inc. All rights reserved. New Relic Agent を Laravel アプリに導入 ● PHP Agent ○ PHP Extension として関数の 呼び出しなどをトラッキング ○ フレームワークごとの特殊対応も ● PHP Daemon ○ PHP Agent が収集したデータを New Relic に転送する ● Infrastructure ○ リソースの使用状況などを New Relic に転送する ○ 直インストールまたは 特権を付与されたコンテナ 一般的なコンテナ構成 (今回は Kubernetes を使っているため若干異なります )

Slide 13

Slide 13 text

© 2022 New Relic, Inc. All rights reserved New Relic の導入と実演 Ⅰ 題材とする Laravel アプリの簡単な紹介 Ⅱ New Relic Agent を Laravel アプリに導入 Ⅲ New Relic APM の基本的な仕組み Ⅳ New Relic を使った Laravel アプリの改善

Slide 14

Slide 14 text

© 2022 New Relic, Inc. All rights reserved. New Relic APM の基本的な仕組み ● APM ○ バックエンドアプリのパフォーマンス分析 ○ 1 回のリクエストのトレースなどを トランザクションという単位で計測 ○ PHP Extension ゆえに自動記録可能! ● Distributed Tracing ○ ある 1 回のトランザクションの間に, マイクロサービス間で発生したやり取りを すべて連結して記録できる ○ フロントエンドの Web ブラウザ上での 動きも含めて記録できる ○ APM で異常検知されなかった (サンプリングされた)正常系も確認できる New Relic の主要機能 ● Logs ○ JSONL 形式でのログの記録と検索 ○ Logs in Context という機能を使うと トランザクションに紐付けできる ○ PHP Extension ゆえに自動紐付け可能! ● Infrastructure ○ CPU やメモリなどのリソースの 使用状況を監視できる ● Synthetic Monitoring ○ HTTP リクエストを定期的に 飛ばして死活監視

Slide 15

Slide 15 text

© 2022 New Relic, Inc. All rights reserved. AWS Fargate では 大幅性能劣化 ( CPU クロックの相性が悪い ) 8.2 ( 収録時まで 8.1 でしたが,   完了後に対応されました 🎉) 8.x (公式サポートはされていないが概 ね 9.x, 10.x でも動きそう) 自動記録の制約 対応 PHP バージョン 対応 Laravel バージョン PHP × New Relic は自動記録できて便利 …だが? ちょっと惜しいポイントが … EC2 ベースの ECS/EKS を使う💡 手動記録する 🥺 自動記録の対象関数を限定 💡 ← newrelic.transaction_tracer.detail = 0 ← newrelic.transaction_tracer.custom = Foo::x,Bar::y ← Fargate よりはマシというだけで,依然として多少のオーバーヘッドはある IO 遅延がメインの PHP アプリケーションの場合は無視できる程度

Slide 16

Slide 16 text

© 2022 New Relic, Inc. All rights reserved. New Relic APM の基本的な仕組み ● バックエンドからの JavaScript スクリプト注入 ○ PHP Agent が HTML を返却する際, PHP 標準機能にある output_handler を 使って注入している ○ Extension をインストールしていれば 自動的に New Relic の Output Handler が 登録される ● フロントエンドから New Relic に直接通信 ○ デベロッパーツールで通信している 様子を確認できる (参考) Distributed Tracing がフロントエンドを監視する仕組み

Slide 17

Slide 17 text

© 2022 New Relic, Inc. All rights reserved. New Relic APM の実際の画面を確認 時間のかかったトランザクション Laravel デフォルトでは コントローラ名@メソッド がタイトル

Slide 18

Slide 18 text

© 2022 New Relic, Inc. All rights reserved. New Relic APM の実際の画面を確認 時間のかかった SQL ・ テーブル名と操作の種類 ・ どのトランザクションから呼び出されているか ・ (スロークエリ判定された場合)具体的なクエリの内容

Slide 19

Slide 19 text

© 2022 New Relic, Inc. All rights reserved New Relic の導入と実演 Ⅰ 題材とする Laravel アプリの簡単な紹介 Ⅱ New Relic Agent を Laravel アプリに導入 Ⅲ New Relic APM の基本的な仕組み Ⅳ New Relic を使った Laravel アプリの改善

Slide 20

Slide 20 text

© 2022 New Relic, Inc. All rights reserved 大量レコードの 読み込み

Slide 21

Slide 21 text

© 2022 New Relic, Inc. All rights reserved. New Relic を使った Laravel アプリの改善 バックエンドのテーブル構成(再掲) 大量レコードの読み込み

Slide 22

Slide 22 text

© 2022 New Relic, Inc. All rights reserved. 大量レコードの読み込み Eloquent Model のリレーションシップ定義

Slide 23

Slide 23 text

© 2022 New Relic, Inc. All rights reserved. 大量レコードの読み込み Eloquent Model のカスタム属性定義 親に依存 祖先に依存

Slide 24

Slide 24 text

© 2022 New Relic, Inc. All rights reserved. ● 子要素の Eager Loading 設定の分岐 ○ Eager Loading なし ○ Cities のみ Eager Loading ○ Cities, Districts ともに Eager Loading ● 親要素の Eager Loading 設定の分岐 ○ Eager Loading なし ○ City, Prefecture ともに Eager Loading 大量レコードの読み込み コントローラ

Slide 25

Slide 25 text

© 2022 New Relic, Inc. All rights reserved. 大量レコードの読み込み HTTP Resource の toArray() の実装 ● 子要素の Lazy Loading 設定の分岐 ○ Lazy Loading しない ○ Cities のみ Lazy Loading ○ Cities, Districts ともに Lazy Loading whenLoaded() は Eager Loading されている場合のみ表示する機能

Slide 26

Slide 26 text

© 2022 New Relic, Inc. All rights reserved. 実演タイム (時間が無ければカット)

Slide 27

Slide 27 text

© 2022 New Relic, Inc. All rights reserved. 大量レコードの読み込み Cities, Districts を Lazy Load した場合の結果 (APM) N+1 がとんでもないことに! Prefecture City City District District

Slide 28

Slide 28 text

© 2022 New Relic, Inc. All rights reserved. 大量レコードの読み込み Cities, Districts を Eager Load した場合の結果 (APM) 親に依存している疑似属性での Lazy Loading がボトルネックに Prefecture City City District District

Slide 29

Slide 29 text

© 2022 New Relic, Inc. All rights reserved. 大量レコードの読み込み Cities, Districts を Eager Load した場合の結果 (Distributed Tracing) リソース → レスポンスの変換で 時間がかかっているのが分かる

Slide 30

Slide 30 text

© 2022 New Relic, Inc. All rights reserved. 大量レコードの読み込み Cities, Districts, Parent を Eager Load した場合の結果 (APM) Prefecture City City District District

Slide 31

Slide 31 text

© 2022 New Relic, Inc. All rights reserved. 大量レコードの読み込み 実際のところは… ループ処理中での Lazy Loading を 検知して例外をスローしてくれる

Slide 32

Slide 32 text

© 2022 New Relic, Inc. All rights reserved 大量レコードの更新

Slide 33

Slide 33 text

© 2022 New Relic, Inc. All rights reserved. New Relic を使った Laravel アプリの改善 仕様のおさらい ● フロントエンドから 27 種類のフィールドが自治体の数だけあり, 合計 50000 以上のフィールドが送られる ● 受け取った JSON を編集してそのまま送り返している ↓ prefectures, cities, districts がネストしている 大量レコードの更新

Slide 34

Slide 34 text

© 2022 New Relic, Inc. All rights reserved. 大量レコードの更新 種類ごとに 1000 件溜まったらバルクアップデートするコード UPDATE SET x = ELT(FIELD(id, 1, 2, 3, …), ‘a’, ‘b’, ‘c’, …) WHERE id IN (1, 2, 3, …)

Slide 35

Slide 35 text

© 2022 New Relic, Inc. All rights reserved. 大量レコードの更新 バリデーションルールの定義(省略あり) ワイルドカードでネストした配列の 子要素を指定する機能がある ● CPU 演算で完結するシンプルなルール群 ● データベースアクセスしないルールのみ

Slide 36

Slide 36 text

© 2022 New Relic, Inc. All rights reserved. 大量レコードの更新 バリデーションルールの定義(省略なし)

Slide 37

Slide 37 text

© 2022 New Relic, Inc. All rights reserved. 実演タイム (時間が無ければカット)

Slide 38

Slide 38 text

© 2022 New Relic, Inc. All rights reserved. 大量レコードの更新 ネストした Cities, Districts を Laravel の通常の Validator で更新した場合の結果 (APM) Validator のワイルドカードルール関連が激重 タイムアウトして データベースにアクセスするところまで たどり着いていない…

Slide 39

Slide 39 text

© 2022 New Relic, Inc. All rights reserved. なんでそんなに重いの?

Slide 40

Slide 40 text

© 2022 New Relic, Inc. All rights reserved. New Relic を使った Laravel アプリの改善 Laravel の Validator が重い理由 大量レコードの更新 送られてくるデータは 立体構造やな

Slide 41

Slide 41 text

© 2022 New Relic, Inc. All rights reserved. New Relic を使った Laravel アプリの改善 Laravel の Validator が重い理由 大量レコードの更新 でもルールは 宣言的にこう書きたい

Slide 42

Slide 42 text

© 2022 New Relic, Inc. All rights reserved. New Relic を使った Laravel アプリの改善 Laravel の Validator が重い理由 大量レコードの更新 データ側をいったん フラットしにしてみよう

Slide 43

Slide 43 text

© 2022 New Relic, Inc. All rights reserved. New Relic を使った Laravel アプリの改善 Laravel の Validator が重い理由 大量レコードの更新 完全フラットやと途中階層の バリデーションが出来ひんな

Slide 44

Slide 44 text

© 2022 New Relic, Inc. All rights reserved. New Relic を使った Laravel アプリの改善 Laravel の Validator が重い理由 大量レコードの更新 ルールに対応するところは 途中階層の配列も用意せな

Slide 45

Slide 45 text

© 2022 New Relic, Inc. All rights reserved. New Relic を使った Laravel アプリの改善 Laravel の Validator が重い理由 大量レコードの更新 ヨシッ! あとはルール側の * をデー タの分だけ 複製すればいいわ!

Slide 46

Slide 46 text

© 2022 New Relic, Inc. All rights reserved. New Relic を使った Laravel アプリの改善 Laravel の Validator が重い理由 大量レコードの更新 できた!

Slide 47

Slide 47 text

© 2022 New Relic, Inc. All rights reserved. 変換されたルール 変換されたデータ ルールとデータが1対1対応! シンプルになった✌ 今からループ回すで!

Slide 48

Slide 48 text

© 2022 New Relic, Inc. All rights reserved. 変換されたルール 変換されたデータ ルールとデータが1対1対応! シンプルになった✌ 今からループ回すで! そりゃ重いやろ

Slide 49

Slide 49 text

© 2022 New Relic, Inc. All rights reserved. New Relic を使った Laravel アプリの改善 Validator が重すぎるのでなんとかする ● Laravel の Validator を使わずに自分で何とかする ○ 理論上最速だがやや書くのが大変 ● 「ワイルドカード → 配列インデックス」の置換処理を Laravel に任せずに自前でやる ○ 効果あるか怪しいが …簡単! 大量レコードの 更新 バリデーション

Slide 50

Slide 50 text

© 2022 New Relic, Inc. All rights reserved. すべて自前で書く場合

Slide 51

Slide 51 text

© 2022 New Relic, Inc. All rights reserved. すべて自前で書く場合

Slide 52

Slide 52 text

© 2022 New Relic, Inc. All rights reserved. すべて自前で書く場合

Slide 53

Slide 53 text

© 2022 New Relic, Inc. All rights reserved. ワイルドカード→配列インデックスの置換処理だけ自前で書く場合 $i, $j, $k, … かんたん ♫

Slide 54

Slide 54 text

© 2022 New Relic, Inc. All rights reserved. 実演タイム (時間が無ければカット)

Slide 55

Slide 55 text

© 2022 New Relic, Inc. All rights reserved. タイムアウト 1秒 NewRelic なし: 8〜15秒 New Relic あり: 15〜30秒 Laravel Validator Pure PHP Validator Wildcard-less Laravel Validator 大量レコードのバリデーション ネストした Cities, Districts をバリデーションした場合 … とっさの改修には 意外と耐えられるかも!

Slide 56

Slide 56 text

© 2022 New Relic, Inc. All rights reserved. (参考) Laravel 8.x までと Laravel 9.x からの違い Validator::$excludeUnvalidatedArrayKeys array 要素からバリデーション対象外のキーを排除 ● Laravel 8.x まで false がデフォルト ● Laravel 9.x から true がデフォルト 実行時間が 2倍ぐらいに

Slide 57

Slide 57 text

© 2022 New Relic, Inc. All rights reserved. 大量レコードのバリデーション 実際のところは… ● ワイルドカードルールがネストしまくりのフォーム設計は可能な限りやめましょう ● どうしても避けられないときは … ○ 要素数を Laravel のバリデータを使わずに 現実的な数までに制限しましょう ○ 制限してもなお無視できない量がある場合は,ワイルドカードルールに代わる 解決策を考えましょう

Slide 58

Slide 58 text

© 2022 New Relic, Inc. All rights reserved まとめ

Slide 59

Slide 59 text

© 2022 New Relic, Inc. All rights reserved. まとめ ● New Relic には便利な機能がいっぱい! ○ APM, Distributed Tracing, Logs in Context には特にお世話になることが多そう ● 推測するな,計測せよ ○ PHP でも IO がボトルネックとは限らない ○ 有名 OSS の中にも恐ろしく非効率なコードが紛れていることがある

Slide 60

Slide 60 text

© 2022 New Relic, Inc. All rights reserved 1ユーザー &月間100GB の転送量までなら無料 https://newrelic.com/signup

Slide 61

Slide 61 text

© 2022 New Relic, Inc. All rights reserved Full-Stack Observability テスト開講❗❗ https://learn.newrelic.com/full-stack-observability-exam-jp