Slide 1

Slide 1 text

Laravel Nightwatchの裏側 Laravel公式Observabilityツールを支える設計と実装 Ryuta Hamasaki PHPerKaigi 2026

Slide 2

Slide 2 text

Ryuta Hamasaki Senior Software Engineer at Laravel @avosalmon

Slide 3

Slide 3 text

nightwatch.laravel.com

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

335,838,779,310

Slide 7

Slide 7 text

queries テーブル (USリージョン) • 39,844,341,114 レコード • 21.04TB (非圧縮) • 838.56GB (圧縮)

Slide 8

Slide 8 text

このデータは どうやって集まっている?

Slide 9

Slide 9 text

Laravel App Nightwatch Agent Ingest API Kafka ClickHouse Dashboard → → ← → Nightwatch Package Your App Nightwatch TCP ClickPipes → Write Read HTTP

Slide 10

Slide 10 text

各レイヤーを深掘りしていきます DEEP DIVE Nightwatch パッケージ:データ収集 Nightwatch エージェント:収集したデータを送信 データパイプライン:大規模データを高速に処理・保存 01 02 03 Dashboard:大規模データを集計して可視化 04

Slide 11

Slide 11 text

Nightwatch Agent Ingest API Kafka ClickHouse Dashboard → → ← → Your App Nightwatch TCP ClickPipes → Write Read HTTP Laravel App Nightwatch Package

Slide 12

Slide 12 text

laravel / nightwatch

Slide 13

Slide 13 text

データ収集〜Agentに送信 01 - Nigtwatch パッケージ Boot → ϝτϦΫεऩू Ϩεϙϯε Agentʹૹ৴ → → → ϦΫΤετ

Slide 14

Slide 14 text

データ収集〜Agentに送信 01 - Nigtwatch パッケージ Boot → ϝτϦΫεऩू Ϩεϙϯε Agentʹૹ৴ → → → ϦΫΤετ Eventリスナー・Middlewareを登録

Slide 15

Slide 15 text

データ収集〜Agentに送信 01 - Nigtwatch パッケージ Boot → ϝτϦΫεऩू Ϩεϙϯε Agentʹૹ৴ → → → ϦΫΤετ 各イベントでメトリクスを収集し、メモリ上にバッファ

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

enum ExecutionStage: string { case Bootstrap = 'bootstrap'; case BeforeMiddleware = 'before_middleware'; case Action = 'action'; case Render = 'render'; case AfterMiddleware = 'after_middleware'; case Sending = 'sending'; case Terminating = 'terminating'; case End = 'end'; }

Slide 18

Slide 18 text

データ収集〜Agentに送信 01 - Nigtwatch パッケージ Boot → ϝτϦΫεऩू Ϩεϙϯε Agentʹૹ৴ → → → ϦΫΤετ

Slide 19

Slide 19 text

データ収集〜Agentに送信 01 - Nigtwatch パッケージ Boot → ϝτϦΫεऩू Ϩεϙϯε Agentʹૹ৴ → → → ϦΫΤετ

Slide 20

Slide 20 text

リクエスト〜ジョブのトレース 01 - Nigtwatch パッケージ LaravelのContext機能でリクエストのtrace idをジョブと共有 use Illuminate\Support\Facades\Context; // Request Context::addHidden('nightwatch_trace_id', $trace); // Job Context::getHidden('nightwatch_trace_id');

Slide 21

Slide 21 text

パフォーマンスに影響はないのか 01 - Nigtwatch パッケージ • ユーザーのアプリケーションを遅くしないことが最優先 • レスポンスを返した後、まとめてAgentに送信 • Agentとの通信はローカルネットワーク内の TCP通信なので高速

Slide 22

Slide 22 text

Laravel App Nightwatch Agent Ingest API Kafka ClickHouse Dashboard → → ← → Nightwatch Package Your App Nightwatch TCP ClickPipes → Write Read HTTP

Slide 23

Slide 23 text

なぜエージェントが必要なのか 02 - Nightwatch Agent • アプリケーション全体のスループットが下がる可能性 • ローカルネットワーク内のTCP通信は高速 • 複数リクエストのデータをバッファし、まとめてバッチ 送信

Slide 24

Slide 24 text

ストレステストの結果 02 - Nightwatch Agent

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

React PHP 02 - Nightwatch Agent • PHPでイベントドリブンな非同期処理を実現 • TCPサーバー・タイマーなどのストリーム処理が可能 • PHPの枠を超えた常駐プロセスを構築できる

Slide 27

Slide 27 text

use React\EventLoop\Loop; use React\Socket\ConnectionInterface; use React\Socket\TcpServer; $server = new TcpServer('127.0.0.1:2407'); $server->on('connection', function (ConnectionInterface $connection) { $payload = new Payload; $connection->on('data', function (string $chunk) use ($payload) { $payload->append($chunk); }); $connection->on('close', function () use ($payload) { $this->ingest->write($payload); }); }); Loop::run()

Slide 28

Slide 28 text

Laravel App Nightwatch Agent Ingest API Kafka ClickHouse Dashboard → → ← → Nightwatch Package Your App Nightwatch TCP ClickPipes → Write Read HTTP

Slide 29

Slide 29 text

Overview 03 - σʔλύΠϓϥΠϯ • マルチリージョン構成:US / EU / AU • リリース初日から世界中のLaravelアプリがデータを送信 • 数十億レコード規模のデータを継続的に処理 • データロスがあってはならない

Slide 30

Slide 30 text

Ingest API 03 - σʔλύΠϓϥΠϯ • 世界中のエージェントからのデータの受け口 • 認証・バリデーション・利用量の上限チェック • 受け取ったデータを即座にKafkaへ送信 • レスポンスは高速に返す:データベースへの保存処理は 後段に任せる

Slide 31

Slide 31 text

Kafka ( MSK ) 03 - σʔλύΠϓϥΠϯ • 高スループット:数十万〜数百万メッセージ/秒を処理 • 高い耐久性:データロスを防ぐ • Ingest APIとDBの間のバッファとして機能 Ingest API Kafka ClickHouse Dashboard → ← → ClickPipes → Write Read

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

Row-based vs Column-based

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

KafkaからClickHouseに どうやって保存している?

Slide 38

Slide 38 text

Ingest API Kafka ClickHouse Dashboard → → ← → ↓ Your App Nightwatch TCP HTTP ClickPipes → Write Read Laravel App Nightwatch Package Nightwatch Agent

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

Laravel App Nightwatch Agent Ingest API Kafka ClickHouse Dashboard → → ← → Nightwatch Package Your App Nightwatch TCP ClickPipes → Write Read HTTP

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

Tech Stack 04 - Dashboard Laravel Inertia.js React TypeScript shadcn/ui Tailwind CSS

Slide 43

Slide 43 text

Laravel & ClickHouse 04 - Dashboard glushkovds / phpclickhouse-laravel smi2 / phpclickhouse

Slide 44

Slide 44 text

timestamp path method status duration (ms) 2026 - 03 - 19 14 : 32 : 01.483 /users GET 200 142.5 2026 - 03 - 19 14 : 32 : 01.891 /dashboard GET 200 38.2 2026 - 03 - 19 14 : 32 : 02.104 /orders POST 201 512.8 2026 - 03 - 19 14 : 32 : 02.337 /users/{id} GET 200 95.1 2026 - 03 - 19 14 : 32 : 03.002 /reports GET 200 1284.3 requests テーブル

Slide 45

Slide 45 text

SELECT toStartOfMinute(timestamp) AS minute, count() AS count, countIf(status >= 500) AS errors, avg(duration) AS avg, quantile(0.95)(duration) AS p95, FROM requests WHERE timestamp >= now() - INTERVAL 1 HOUR GROUP BY minute ORDER BY minute

Slide 46

Slide 46 text

minute count errors avg p95 2026 - 03 - 19 14 : 28 : 00 1,204 3 84.2 245.2 2026 - 03 - 19 14 : 29 : 00 1,387 12 97.5 312.8 2026 - 03 - 19 14 : 30 : 00 1,156 1 72.1 198.4 2026 - 03 - 19 14 : 31 : 00 1,293 5 88.9 267.1 2026 - 03 - 19 14 : 32 : 00 1,342 8 91.3 289.5 数十億行のテーブルでも1秒以内に集計

Slide 47

Slide 47 text

まとめ PACKAGE Laravelのイベントをフックし、 パフォーマンスへの影響を最小化して収集 AGENT ReactPHPによるEvent-Drivenな 常駐プロセス(TCPサーバー) PIPELINE Ingest API + Kafka + ClickPipesで 大規模データを処理 DASHBOARD ClickHouseによる高速なデータ集計

Slide 48

Slide 48 text

ANNOUNCEMENT 日本初のLaravel公式カンファレンス laravellive.jp

Slide 49

Slide 49 text

೥݄೔

Slide 50

Slide 50 text

TACHIKAWA STAGE GARDEN

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

No content

Slide 57

Slide 57 text

Laravel だけじゃないよ! Laravel Live Japan 2026 Laravel PHP AI Testing Database UI / UX Community Career JavaScript Native App

Slide 58

Slide 58 text

શηογϣϯ ϥΠϒ຋༁͋Γ🌏

Slide 59

Slide 59 text

&BSMZ#JSEνέοτ laravellive.jp ݄೔·Ͱ

Slide 60

Slide 60 text

Thank You