فصل ۸: نظارت و بهینهسازی عملکرد¶
در این فصل، به بررسی ابزارها و تکنیکهای نظارت و بهینهسازی عملکرد Laravel Reverb در نسخه ۱۲ لاراول میپردازیم. موضوعات شامل ادغام با Laravel Pulse برای نظارت بر اتصالات و پیامها، تنظیم recorders برای جمعآوری دادهها، بهینهسازی event loop با استفاده از ReactPHP و ext-uv برای مدیریت اتصالات بالا، و مدیریت حافظه و garbage collection در سرور Reverb است. این فصل بر اساس مستندات رسمی لاراول ۱۲.x و بهترین شیوههای توسعه تنظیم شده و شامل مثالهای عملی است.
ادغام با Laravel Pulse برای نظارت بر اتصالات و پیامها¶
Laravel Pulse یک ابزار نظارت سبک و بومی است که برای مانیتورینگ عملکرد اپلیکیشنهای لاراول طراحی شده است. با استفاده از Pulse، میتوانید اتصالات WebSocket، پیامهای ارسالی، و معیارهای عملکرد Reverb را در یک داشبورد بصری مشاهده کنید.
نصب و تنظیم Laravel Pulse¶
- نصب Pulse:
composer require laravel/pulse
php artisan vendor:publish --provider="Laravel\Pulse\PulseServiceProvider"
php artisan migrate
- اجرای Pulse: Pulse بهصورت پیشفرض دادهها را در دیتابیس ذخیره میکند. برای فعال کردن داشبورد:
php artisan pulse:install
این دستور routeهای لازم را به پروژه اضافه میکند و داشبورد در آدرس /pulse قابل دسترسی خواهد بود.
- تنظیم دسترسی به داشبورد:
برای محدود کردن دسترسی به داشبورد Pulse، فایل
config/pulse.phpرا ویرایش کنید:
<?php
return [
'dashboard' => [
'enabled' => true,
'middleware' => ['auth', 'role:admin'],
],
'storage' => [
'driver' => 'database',
'connection' => 'mysql',
],
];
- middleware: دسترسی را به کاربران با نقش
adminمحدود میکند. -
storage: دادهها را در دیتابیس ذخیره میکند (میتوانید از Redis نیز استفاده کنید).
-
فعال کردن Pulse برای Reverb:
Pulse بهصورت خودکار معیارهای مربوط به Reverb را جمعآوری میکند، اما باید مطمئن شوید که Reverb به درستی تنظیم شده است (فایل config/reverb.php).
تنظیم Recorders (ReverbConnections, ReverbMessages) و داشبورد Pulse¶
Pulse از recorderها برای جمعآوری دادههای خاص استفاده میکند. دو recorder مهم برای Reverb عبارتند از:
- ReverbConnections: تعداد اتصالات WebSocket فعال را ردیابی میکند.
- ReverbMessages: پیامهای ارسالی از طریق Reverb را مانیتور میکند.
تنظیم Recorders¶
- فایل
config/pulse.phpرا برای فعال کردن recorderهای Reverb ویرایش کنید:
<?php
return [
'recorders' => [
\Laravel\Pulse\Recorders\ReverbConnections::class => [
'enabled' => true,
'sample_rate' => 1.0, // جمعآوری 100% دادهها
],
\Laravel\Pulse\Recorders\ReverbMessages::class => [
'enabled' => true,
'sample_rate' => 0.1, // جمعآوری 10% پیامها
],
],
];
-
sample_rate: درصد دادههای جمعآوریشده را مشخص میکند. برای محیط توسعه، میتوانید از 1.0 استفاده کنید، اما در تولید، مقادیر پایینتر (مانند 0.1) برای کاهش بار توصیه میشود.
-
مشاهده دادهها در داشبورد Pulse:
پس از تنظیم، به آدرس /pulse بروید. در داشبورد، کارتهای زیر نمایش داده میشوند:
- Connections: تعداد کل اتصالات فعال WebSocket.
- Messages: تعداد پیامهای ارسالی در بازههای زمانی مختلف (مثلاً هر دقیقه).
مثال عملی: نمایش اتصالات و پیامها¶
برای تست، یک event ساده ایجاد کنید که پیامها را به یک کانال حضور ارسال کند:
<?php
namespace App\Events;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class PulseTestMessage implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
public function __construct($message)
{
$this->message = $message;
}
public function broadcastOn()
{
return new PresenceChannel('test-room');
}
public function broadcastAs()
{
return 'test.message';
}
}
Route برای ارسال پیام:
<?php
use App\Events\PulseTestMessage;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('pulse-test');
});
Route::post('/send-test', function () {
event(new PulseTestMessage(request('message', 'Test message for Pulse')));
return response()->json(['status' => 'Message sent']);
});
فایل resources/views/pulse-test.blade.php:
<!DOCTYPE html>
<html>
<head>
<title>Pulse Test</title>
<meta name="csrf-token" content="{{ csrf_token() }}">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
@vite(['resources/js/app.js'])
</head>
<body>
<h1>Test Reverb with Pulse</h1>
<form id="test-form">
<input type="text" name="message" placeholder="Type a message...">
<button type="submit">Send</button>
</form>
<ul id="messages"></ul>
<script>
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$('#test-form').submit(function(e) {
e.preventDefault();
$.post('/send-test', $(this).serialize());
});
window.Echo.join('test-room')
.listen('.test.message', (e) => {
$('#messages').append(`<li>${e.message}</li>`);
});
</script>
</body>
</html>
- سرور Reverb را اجرا کنید:
php artisan reverb:start - سرور لاراول را اجرا کنید:
php artisan serve - فایلهای جاوااسکریپت را کامپایل کنید:
npm run dev - به
/pulseبروید تا معیارهای اتصالات و پیامها را مشاهده کنید.
بهینهسازی Event Loop با ReactPHP و ext-uv¶
Reverb از ReactPHP برای مدیریت event loop استفاده میکند، که برای پردازش اتصالات WebSocket بهصورت غیرهمزمان مناسب است. برای سناریوهای با تعداد اتصالات بالا، میتوانید از افزونه ext-uv برای بهبود عملکرد استفاده کنید.
نصب ext-uv¶
- افزونه
ext-uvرا نصب کنید (نیاز به PHP 8.2+ و سیستم لینوکس/مک):
pecl install uv
- فایل
php.iniرا ویرایش کنید و افزونه را فعال کنید:
extension=uv.so
- Reverb را برای استفاده از
ext-uvتنظیم کنید:
فایل config/reverb.php:
<?php
return [
'apps' => [
[
'app_id' => env('REVERB_APP_ID', 'my-reverb-app'),
'key' => env('REVERB_APP_KEY', 'your-app-key'),
'secret' => env('REVERB_APP_SECRET', 'your-app-secret'),
'capacity' => 1000,
'allowed_origins' => ['example.com'],
],
],
'host' => env('REVERB_HOST', 'localhost'),
'port' => env('REVERB_PORT', 8080),
'scheme' => env('REVERB_SCHEME', 'http'),
'event_loop' => 'uv', // استفاده از ext-uv
];
- event_loop: با تنظیم روی
uv، Reverb از افزونهext-uvبرای مدیریت event loop استفاده میکند، که عملکرد بهتری در مقایسه با event loop پیشفرض ReactPHP ارائه میدهد.
مزایای ext-uv¶
- کارایی بالاتر: استفاده از libuv برای مدیریت I/O غیرهمزمان، که در Node.js نیز استفاده میشود.
- مقیاسپذیری: مناسب برای اپلیکیشنهایی با هزاران اتصال همزمان.
- کاهش تأخیر: بهبود زمان پاسخگویی برای پیامهای WebSocket.
تست عملکرد¶
برای تست عملکرد با تعداد اتصالات بالا، از ابزارهایی مانند wrk یا k6 استفاده کنید:
k6 run -u 1000 -d 30s script.js
فایل script.js برای تست:
import ws from 'k6/ws';
export default function () {
const url = 'ws://localhost:8080/app/your-app-key?protocol=7&client=js';
const params = { tags: { name: 'reverb-test' } };
const res = ws.connect(url, params, function (socket) {
socket.on('open', () => {
socket.send(JSON.stringify({
command: 'subscribe',
identifier: JSON.stringify({ channel: 'test-room' })
}));
});
socket.on('message', (data) => console.log('Message received:', data));
socket.setTimeout(() => socket.close(), 5000);
});
}
مدیریت حافظه و Garbage Collection در سرور Reverb¶
برای اپلیکیشنهای با اتصالات بالا، مدیریت حافظه و garbage collection حیاتی است تا از نشت حافظه (memory leaks) و کاهش عملکرد جلوگیری شود.
تکنیکهای مدیریت حافظه¶
- محدود کردن اتصالات: همانطور که در فصل هفتم توضیح داده شد، از
capacityدرconfig/reverb.phpبرای محدود کردن تعداد اتصالات استفاده کنید. - استفاده از Queues: برای کاهش بار روی سرور، broadcasting را به queue منتقل کنید:
BROADCAST_QUEUE_CONNECTION=redis
- تنظیم Garbage Collection: در PHP، garbage collection را بهینه کنید:
gc_enable();
ini_set('memory_limit', '512M'); // تنظیم در php.ini یا runtime
- مانیتورینگ حافظه:
از Pulse برای نظارت بر مصرف حافظه استفاده کنید. همچنین، میتوانید از ابزارهای خارجی مانند New Relic یا Prometheus استفاده کنید.
مثال: لاگگیری مصرف حافظه¶
برای ردیابی مصرف حافظه، یک middleware سفارشی ایجاد کنید:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Log;
class LogMemoryUsage
{
public function handle($request, Closure $next)
{
$response = $next($request);
Log::info('Memory usage', [
'peak' => memory_get_peak_usage(true) / 1024 / 1024 . ' MB',
'current' => memory_get_usage(true) / 1024 / 1024 . ' MB',
]);
return $response;
}
}
این middleware را به routeهای ارسال پیام اعمال کنید:
Route::middleware(['auth', 'log.memory'])->post('/send-test', function () {
event(new PulseTestMessage(request('message', 'Test message')));
return response()->json(['status' => 'Message sent']);
});
نکات و بهترین شیوهها¶
- نظارت مداوم: از Pulse یا ابزارهای خارجی مانند Prometheus برای مانیتورینگ real-time استفاده کنید.
- بهینهسازی نمونهبرداری: در Pulse، از
sample_rateپایینتر در تولید استفاده کنید تا بار سرور کاهش یابد. - تست بار: قبل از استقرار، تستهای بار (load testing) با ابزارهایی مانند k6 انجام دهید.
- مدیریت منابع: در سرورهای با منابع محدود، از ext-uv و Redis برای بهبود عملکرد استفاده کنید.
تمرین پیشنهادی¶
- یک کارت سفارشی در داشبورد Pulse برای نمایش تعداد پیامهای ارسالی در هر کانال اضافه کنید.
- یک تست بار با 5000 اتصال همزمان اجرا کنید و تأثیر ext-uv را در مقایسه با event loop پیشفرض بررسی کنید.
- یک سیستم هشدار برای مصرف حافظه بالا پیادهسازی کنید (مانند ارسال ایمیل هنگام عبور از آستانه).
منابع¶
- مستندات رسمی لاراول:
laravel.com/docs/12.x/pulse - مستندات Reverb:
laravel.com/docs/12.x/reverb - مستندات ReactPHP:
reactphp.org
در فصل بعدی، به استقرار Reverb در محیط تولید و مقیاسپذیری افقی خواهیم پرداخت.