บทความ

Laravel Pulse คืออะไร ติดตั้งยังไง ใช้ดูอะไรได้บ้าง

Laravel Pulse เป็น dashboard ที่ติดตั้งในแอปของเราเอง ใช้ดู request, query และ job ที่ช้า queue, cache, exception และ CPU ของ server โพสต์นี้ไล่ตั้งแต่ติดตั้ง เปิดสิทธิ์บน production ไปจนถึงลดภาระด้วย sampling และ Redis

เผยแพร่
อัปเดต
— เพิ่มขั้นตอนติดตั้งและตั้งค่าสำหรับ Pulse 1.8 บน Laravel 13
เวลาอ่าน
6 นาที
สรุปจาก
Eric L. Barnes · laravel-news.com

Pulse เปิดตัวที่งาน Laracon AU เมื่อ 16 พ.ย. 2566 เป็น open source ใช้ได้โดยไม่มีค่าใช้จ่าย ตัว dashboard เขียนด้วย Livewire ตอนนี้ออกถึง v1.8.1 แล้ว รองรับ Laravel 10 ถึง 13 ใช้คู่กับ Livewire 3 หรือ 4 ก็ได้ เว็บนี้เองผมก็ติดตั้ง Pulse ไว้ดูว่าหน้าไหนเริ่มช้า

หน้า dashboard ของ Laravel Pulse ธีมมืด ฉายบนจอเวที Laracon AU 2023

Pulse บนเวที Laracon AU 2023 ในหน้าเดียวมีทั้ง CPU และ memory ของ server, Application Usage, Queues, Cache และ Slow Queries

ติดตั้ง Laravel Pulse

Pulse เก็บข้อมูลลง database ซึ่งเอกสารของ Laravelระบุว่าต้องเป็น MySQL, MariaDB หรือ PostgreSQL ติดตั้งผ่าน Composer แล้ว publish ไฟล์ config กับ migration จากนั้นสั่ง migrate เพื่อสร้างตาราง pulse_*

composer require laravel/pulse
php artisan vendor:publish --provider="Laravel\Pulse\PulseServiceProvider"
php artisan migrate

เสร็จแล้วเปิด /pulse บนเครื่อง local ได้เลย ค่าที่ปรับได้อยู่ใน config/pulse.php และเกือบทุกค่าตั้งผ่าน .env ได้ เช่น PULSE_PATH ถ้าอยากย้าย dashboard ไปไว้ที่อื่น

เปิดหน้า /pulse บน production ด้วย gate viewPulse

ค่าเริ่มต้น Pulse ให้เข้า /pulse ได้เฉพาะตอน APP_ENV=local พอขึ้น server จริงจะได้ 403 ทุกคน เราต้องกำหนด gate viewPulse เองว่าใครเข้าได้ ใส่ไว้ใน AppServiceProvider

use App\Models\User;
use Illuminate\Support\Facades\Gate;

public function boot(): void
{
    Gate::define('viewPulse', function (User $user) {
        return in_array($user->email, [
            '[email protected]',
        ]);
    });
}

closure รับ User แบบไม่ nullable คนที่ยังไม่ login จึงเข้าไม่ได้ ถ้าแอปมี role อยู่แล้วก็เปลี่ยนไปเช็ก role แทนรายชื่ออีเมลได้

Pulse มีการ์ดอะไรบ้าง

หน้า dashboard ตั้งต้นมาเก้าการ์ด แต่ละการ์ดดึงข้อมูลจาก recorder ของตัวเองใน config/pulse.php เราปิด recorder ที่ไม่ใช้ หรือปรับ threshold ทีละตัวได้

Slow Requests บอกว่า route ไหนช้า

การ์ดนี้แสดง route ที่ตอบช้ากว่า threshold (ค่าเริ่มต้น 1,000 ms) พร้อม method, URL และ action ของ controller เรียงตามจำนวนครั้งหรือตามเวลาที่ช้าสุด ตอนเปิดตัวการ์ดนี้ชื่อ Slow Routes อย่างในภาพ

การ์ด Slow Routes แสดง DELETE, POST และ PUT ของ route /flights พร้อม controller action ที่ตอบช้าเกิน 1000ms

แต่ละแถวบอก method, route และ controller action ที่ตอบช้าเกิน threshold

บาง route ช้าโดยธรรมชาติ เช่น หน้าออกรายงาน เราตั้ง threshold แยกเป็นราย route ได้ด้วย regex

Recorders\SlowRequests::class => [
    // ...
    'threshold' => [
        '#^/admin/reports#' => 5000,
        'default' => env('PULSE_SLOW_REQUESTS_THRESHOLD', 1000),
    ],
],

Slow Queries บอกว่า query ไหนช้า และอยู่บรรทัดไหน

Pulse เก็บ SQL ที่ช้ากว่า threshold โดยไม่ใส่ค่า binding แล้วจัดกลุ่มตาม SQL กับไฟล์และบรรทัดที่เรียก เราเลยรู้ทันทีว่าต้องไปแก้ที่ไหน ถ้าเจอ query เดิมซ้ำเป็นร้อยครั้งใน request เดียว ลองดูเรื่อง Eager Loading กับปัญหา N+1

การ์ด Slow Queries บนจอ Laracon AU แสดง insert into tickets และ select จากตาราง flights พร้อมจำนวนครั้งและเวลาที่ช้าสุด

Slow Queries แสดง SQL พร้อม path ของไฟล์ จำนวนครั้ง และเวลาที่ช้าสุด ภาพจาก Zayn Buksh

Slow Jobs และ Slow Outgoing Requests

สองการ์ดนี้ทำงานแบบเดียวกับ Slow Requests การ์ดแรกดู job ใน queue ที่รันนานเกิน threshold การ์ดที่สองดูคำขอที่แอปยิงออกไปข้างนอกผ่าน HTTP client ของ Laravel เช่น เรียก API ของ payment gateway หรือ LINE แล้วรอนาน ใน config เราจัดกลุ่ม URL ด้วย regex ได้ จะได้ไม่เห็น URL ที่ต่างกันแค่ ID แยกเป็นคนละแถว

Application Usage บอกว่า user คนไหนใช้งานหนัก

การ์ดนี้จัดอันดับ 10 user ได้สามแบบ คือ ส่ง request มากที่สุด เจอหน้าช้ามากที่สุด และ dispatch job มากที่สุด ถ้าแอปเป็น backend ให้ frontend หรือแอปมือถือเรียก API การ์ดนี้ช่วยให้เห็นได้เร็วว่า user คนไหนยิง API ถี่ผิดปกติ

การ์ด Application Usage แสดง Top 10 users making requests พร้อมชื่อ อีเมล และจำนวน request

Pulse เก็บแค่ user ID แล้วดึงชื่อกับอีเมลจาก model User ตอนแสดงผล

Exceptions บอกว่า error ไหนเกิดบ่อย

การ์ด Exceptions นับว่า exception แต่ละ class เกิดกี่ครั้ง ล่าสุดเมื่อไร และเกิดที่ไฟล์ไหน เหมาะกับดูว่า error ไหนกำลังพุ่ง แต่การ์ดนี้ไม่มี stack trace ไม่มีอีเมลแจ้งเตือน และไม่มีปุ่มปิด issue ถ้าต้องการระบบติดตาม error เต็มรูปแบบ ลองดู watchtower-laravel ที่ผมเขียนไว้ใช้เอง หรือ Sentry ก็ได้

Queues บอกว่า job ค้างหรือ fail ไปเท่าไร

ถ้าแอปส่งงานไปทำใน background การ์ด Queues จะแสดงกราฟของแต่ละ queue ว่ามี job รอ (queued), กำลังทำ (processing), ทำเสร็จ (processed), ปล่อยกลับไปรอคิวใหม่ (released) และ fail กี่ตัว ดูย้อนหลังได้ตามช่วงเวลาที่เลือกบน dashboard

การ์ด Queues แสดงกราฟของ queue default และ high แยกเส้น queued, processing, processed, released และ failed

เส้นสีแดงคือ job ที่ fail ถ้าเส้นนี้เริ่มสูงขึ้นก็ถึงเวลาเข้าไปดู log ของ worker

Cache บอก hit rate ของแต่ละ key

การ์ด Cache นับ hit กับ miss รวมทั้งแอป และแยกราย key ถ้าชื่อ key มี ID ปนอยู่ เช่น product:15, product:16 เราจัดกลุ่มด้วย regex ใน config ให้รวมเป็น product:* แถวเดียวได้

Recorders\CacheInteractions::class => [
    // ...
    'groups' => [
        '/:\d+/' => ':*',
    ],
],

Servers บอก CPU, memory และ disk ของทุกเครื่อง

การ์ด Servers แสดง CPU, memory และพื้นที่ disk ของทุกเครื่องที่รันคำสั่ง pulse:check (ดูหัวข้อถัดไป) ถ้าแอปวางอยู่หลัง load balancer หลายเครื่อง ทุกเครื่องจะรายงานเข้า dashboard เดียวกัน ตั้งชื่อเครื่องเองได้ด้วย PULSE_SERVER_NAME ตอนเปิดตัว ทีม Laravel เล่าว่า Forge ใช้ Pulse ดู request เป็นล้านครั้งโดยไม่ต้องเปิด sampling

การ์ด Servers แสดงห้าเครื่อง prod-web-1, prod-web-2, prod-cache, prod-db และ prod-worker พร้อมเปอร์เซ็นต์ CPU และกราฟ

เครื่องที่ส่งข้อมูลมาภายใน 30 วินาทีล่าสุดจะมีจุดสีเขียวหน้าชื่อ

มีทั้งธีมสว่างและธีมมืด

dashboard สลับธีมได้จากปุ่มมุมขวาบน หรือปล่อยให้ตามการตั้งค่าของระบบปฏิบัติการ

dashboard ของ Laravel Pulse ธีมสว่าง ฉายบนจอเวที Laracon AU 2023

หน้าเดียวกับภาพแรก แต่เป็นธีมสว่าง ภาพจาก Zayn Buksh

เพิ่มการ์ดของเราเองด้วย Livewire

ถ้าอยากจัดหน้าใหม่ ให้ publish view ของ dashboard ออกมาแก้ ไฟล์จะอยู่ที่ resources/views/vendor/pulse/dashboard.blade.php

php artisan vendor:publish --tag=pulse-dashboard

ในไฟล์นี้การ์ดแต่ละใบเป็น Livewire component เรากำหนดความกว้างด้วย cols ย้ายลำดับ หรือลบการ์ดที่ไม่ใช้ออกได้ โดยไม่ต้อง build JavaScript ใหม่

<x-pulse>
    <livewire:pulse.servers cols="full" />

    <livewire:pulse.slow-requests cols="6" />

    <livewire:pulse.slow-queries cols="6" />
</x-pulse>

การ์ดของเราเองคือ Livewire component ที่ extends Laravel\Pulse\Livewire\Card บันทึกตัวเลขด้วย Pulse::record() แล้วดึงผลรวมมาแสดงด้วย $this->aggregate() รายละเอียดอยู่ในเอกสาร Custom Cards ตอนเปิดตัวทีม Laravel โชว์การ์ดยอดขายตั๋วเครื่องบินที่เขียนเอง วางคู่กับการ์ดมาตรฐาน

การ์ด Flights ที่เขียนเอง แสดงยอดขายตั๋ว รายได้ จำนวนเที่ยวบินล่าช้าและยกเลิก บนจอ Laracon AU

การ์ด Flights เป็นการ์ดที่เขียนขึ้นเองสำหรับแอปตัวอย่างในงาน ส่วนการ์ดด้านล่างเป็นการ์ดมาตรฐานของ Pulse

ให้ pulse:check ทำงานตลอดเวลาบน server

การ์ดส่วนใหญ่เก็บข้อมูลเองจาก event ของ Laravel แต่การ์ด Servers ต้องมีคำสั่ง pulse:check คอยวนอ่านค่า CPU, memory และ disk ทุกเครื่องที่อยากเห็นในการ์ดต้องรันคำสั่งนี้

php artisan pulse:check

คำสั่งนี้ทำงานค้างไว้ไม่จบ บน VPS เราให้ Supervisor ดูแลและสั่งรันใหม่ให้เองถ้าหลุด แบบเดียวกับ queue worker

[program:pulse-check]
command=php /var/www/my-app/artisan pulse:check
user=www-data
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/var/www/my-app/storage/logs/pulse-check.log
sudo supervisorctl reread
sudo supervisorctl update

pulse:check ไม่เห็นโค้ดใหม่จนกว่าจะรันใหม่ ในสคริปต์ deploy ให้สั่ง php artisan pulse:restart ด้วย Pulse ส่งสัญญาณ restart ผ่าน cache แอปจึงต้องตั้ง cache driver ไว้ใช้งานได้

ถ้าแอปอยู่บน shared hosting ที่ใช้ cPanel หรือ DirectAdmin มักรัน process ค้างไว้ไม่ได้ การ์ด Servers จะว่างไป แต่การ์ดอื่นยังทำงานครบ

แอป traffic สูง ลดภาระด้วย sampling และ Redis ingest

ค่าเริ่มต้น Pulse เขียนข้อมูลลง database หลังส่ง response ให้ผู้ใช้แล้ว และเก็บไว้ 7 วัน แอปขนาดเล็กถึงกลางใช้ค่าเริ่มต้นได้เลย ถ้า traffic สูงขึ้นมีทางลดภาระสามทาง

  • Sampling บันทึกแค่บางส่วน เช่น ตั้ง sample rate ของ recorder UserRequests เป็น 0.1 Pulse จะเก็บประมาณ 10% ของ request แล้วคูณกลับตอนแสดงผล ตัวเลขบน dashboard จะมี ~ นำหน้าให้รู้ว่าเป็นค่าประมาณ
  • แยก database ตั้ง PULSE_DB_CONNECTION ให้ Pulse เขียนลง connection อื่น ไม่ไปแย่งกับ database หลักของแอป
  • Redis ingest ส่งข้อมูลเข้า Redis stream ก่อน แล้วให้ pulse:work ย้ายลง database ทีหลัง ต้องใช้ Redis 6.2 ขึ้นไป และควรใช้ Redis connection แยกจาก queue
PULSE_USER_REQUESTS_SAMPLE_RATE=0.1
PULSE_DB_CONNECTION=pulse
PULSE_INGEST_DRIVER=redis
PULSE_REDIS_CONNECTION=pulse
php artisan pulse:work

pulse:work ทำงานค้างไว้เหมือน pulse:check จึงต้องให้ Supervisor ดูแล และใช้ pulse:restart ตอน deploy เหมือนกัน ถ้าเปิด Redis ingest แล้วลืมรัน pulse:work ข้อมูลจะค้างอยู่ใน Redis และ dashboard จะว่าง

ดูเพิ่ม

Jess Archer เปิดตัว Pulse บนเวที Laracon AU 2023 ดูย้อนหลังได้ที่นี่

ดูบน YouTube

อ่านต่อ

ล่าสุด

ดูทั้งหมด →