Build a Real‑Time Analytics Dashboard in Laravel with Echo, WebSockets, and ClickHouse

Mahmut Sarıkaya 4 dk okuma 2 Görüntülenme 0
Build a Real‑Time Analytics Dashboard in Laravel with Echo, WebSockets, and ClickHouse

Why real‑time insight matters

Imagine a SaaS product that processes 2,000 events per second and needs to surface conversion rates within seconds. Delayed reporting turns a hot lead into a missed opportunity. According to a 2023 industry survey, 68% of product managers consider sub‑second latency a competitive advantage. Laravel developers can meet that demand by combining Laravel Echo, WebSockets broadcasting, and ClickHouse’s columnar speed.

System requirements and stack overview

The core stack includes Laravel 10+, PHP 8.2+, Node.js 18+, Redis for queueing, a WebSocket server (Laravel Echo Server or Swoole), and ClickHouse 23.3+. Redis handles the broadcast queue, while ClickHouse stores immutable event logs optimized for aggregation. The data flow is simple: client → Laravel route → event → broadcast via Echo → listener writes to ClickHouse → dashboard consumes aggregated queries.

Installing and configuring broadcasting

First, add the broadcasting driver and Echo server. Run:

composer require pusher/pusher-php-server
npm install --save laravel-echo socket.io-client
npm install -g laravel-echo-server

Update .env with:

BROADCAST_DRIVER=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
ECHO_SERVER_HOST=0.0.0.0
ECHO_SERVER_PORT=6001

In config/broadcasting.php set the redis connection and enable authEndpoint for private channels.

Setting up Laravel Echo Server

Generate a default configuration file:

laravel-echo-server init

Edit laravel-echo-server.json to match your Redis instance and enable SSL if needed. Start the server with:

laravel-echo-server start

The server now listens on port 6001 and will forward any broadcasted events to connected browsers.

Defining an analytics event

Create a Laravel event that implements ShouldBroadcast. The event carries minimal payload—event name, user ID, and timestamp.

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class RealTimeMetric implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;

public $metric;
public $userId;
public $occurredAt;

public function __construct(string $metric, int $userId)
{
$this->metric = $metric;
$this->userId = $userId;
$this->occurredAt = now();
}

public function broadcastOn()
{
return new PrivateChannel('analytics');
}

public function broadcastAs()
{
return 'MetricRecorded';
}
}

Whenever a user completes a purchase, fire the event:

use App\Events\RealTimeMetric;

RealTimeMetric::dispatch('purchase', $user->id);

Persisting data to ClickHouse

Set up a listener that receives the event and inserts a row into ClickHouse. Use the kawax/laravel-clickhouse package for a fluent query builder.

namespace App\Listeners;

use App\Events\RealTimeMetric;
use ClickHouseDB\Client;

class StoreMetricInClickHouse
{
protected $click;

public function __construct() {
$this->click = new Client([
'host' => env('CLICKHOUSE_HOST', '127.0.0.1'),
'port' => env('CLICKHOUSE_PORT', 8123),
'username' => env('CLICKHOUSE_USER', 'default'),
'password' => env('CLICKHOUSE_PASSWORD', ''),
]); }

public function handle(RealTimeMetric $event) {
$this->click->insert('analytics.events', [
'metric' => $event->metric,
'user_id' => $event->userId,
'occurred_at' => $event->occurredAt->format('Y-m-d H:i:s'),
]); }
}

Register the listener in EventServiceProvider. ClickHouse’s merge‑tree engine will automatically compress millions of rows while keeping aggregation queries under 200 ms.

Consuming the stream on the frontend

In a Vue component (or plain JS), import Echo and listen to the private channel. The dashboard updates instantly without a page reload.

import Echo from 'laravel-echo';
window.Echo = new Echo({
broadcaster: 'socket.io',
host: window.location.hostname + ':6001'
});

window.Echo.private('analytics')
.listen('.MetricRecorded', (e) => {
// Update chart data structure
this.metrics.push({
name: e.metric,
user: e.userId,
time: e.occurredAt
});
this.refreshChart();
});

The component can use Chart.js to render a line chart that reflects the last 5 minutes of activity. Because the data arrives via WebSockets, the UI stays responsive even under 5,000 concurrent users.

Performance tips and scaling

1. Batch inserts: modify the listener to collect events in Redis and flush them every 100 ms using a scheduled job. This reduces round‑trips to ClickHouse by up to 85%.
2. Partitioning: create ClickHouse tables partitioned by day (PARTITION BY toYYYYMMDD(occurred_at)) to keep query times constant as history grows.
3. Horizontal scaling: run multiple Echo Server instances behind a load balancer and share the same Redis pub/sub channel. Laravel’s queue workers can be scaled independently for the ClickHouse writer.

Conclusion

By wiring Laravel Echo, a Redis‑backed WebSocket server, and ClickHouse’s lightning‑fast columnar engine, you can deliver a real‑time analytics dashboard that reacts in sub‑second latency, even at high event volumes. The approach stays within the Laravel ecosystem, leverages familiar broadcasting conventions, and scales horizontally with minimal code changes. Implement the steps above, monitor your ClickHouse query latency, and you’ll turn raw events into actionable insight the moment they happen.

Sources

Official Laravel Documentation – Broadcasting
ClickHouse Documentation – MergeTree Engine
Laravel Echo Server GitHub README

Author: Mahmut Sarıkaya — sarikayadev.com

Etiketler: #laravel real-time analytics #laravel echo #clickhouse integration #websockets broadcasting #laravel broadcasting
Paylaş:
M

Yazar

Mahmut Sarıkaya

yazılım Geliştirici

Yorumlar

Henüz yorum yok. İlk yorumu siz yapın!

Yorum Bırakın

3 + 2 =