Server Monitoring Best Practices: Keeping Your Laravel App and Redis Clusters Alive on Linode
Establishing a Robust Monitoring Foundation with Prometheus and Grafana
For any production Laravel application, especially those leveraging Redis for caching and session management, a comprehensive monitoring strategy is non-negotiable. This isn’t about basic uptime checks; it’s about deep visibility into resource utilization, application performance, and the health of critical dependencies like Redis. We’ll focus on a Prometheus and Grafana stack, deployed on Linode, as our primary telemetry and visualization tools.
Node Exporter: System-Level Metrics for Laravel Servers
The first layer of monitoring involves gathering system-level metrics from your Linode instances. The Prometheus Node Exporter is the de facto standard for this. It exposes a wide array of hardware and OS metrics, including CPU usage, memory consumption, disk I/O, and network traffic.
Installation on a typical Ubuntu Linode:
wget https://github.com/prometheus/node_exporter/releases/download/v1.7.0/node_exporter-1.7.0.linux-amd64.tar.gz tar xvfz node_exporter-1.7.0.linux-amd64.tar.gz sudo mv node_exporter-1.7.0.linux-amd64/node_exporter /usr/local/bin/ sudo useradd --no-create-home --shell /bin/false prometheus sudo chown prometheus:prometheus /usr/local/bin/node_exporter
Next, configure Node Exporter as a systemd service to ensure it runs automatically and can be managed easily.
[Unit] Description=Node Exporter Wants=network-online.target After=network-online.target [Service] User=prometheus Group=prometheus Type=simple ExecStart=/usr/local/bin/node_exporter [Install] WantedBy=multi-user.target
Save this content as /etc/systemd/system/node_exporter.service. Then, enable and start the service:
sudo systemctl daemon-reload sudo systemctl enable node_exporter sudo systemctl start node_exporter sudo systemctl status node_exporter
By default, Node Exporter listens on port 9100. You’ll need to configure Prometheus to scrape this endpoint. In your prometheus.yml configuration file, add a scrape job:
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ['YOUR_LINODE_IP_1:9100', 'YOUR_LINODE_IP_2:9100'] # Replace with your Linode IPs
Redis Exporter: Deep Dive into Redis Cluster Health
Monitoring Redis requires specific metrics beyond what Node Exporter provides. The Redis Exporter is essential for understanding Redis performance, memory usage, command latency, and cluster status. For a Redis cluster, you’ll typically run one Redis Exporter instance per Redis node, or a single instance configured to connect to your cluster.
Download and install Redis Exporter:
wget https://github.com/oliver006/redis_exporter/releases/download/v1.57.0/redis_exporter-v1.57.0.linux-amd64.tar.gz tar xvfz redis_exporter-v1.57.0.linux-amd64.tar.gz sudo mv redis_exporter-v1.57.0.linux-amd64/redis_exporter /usr/local/bin/ sudo chown prometheus:prometheus /usr/local/bin/redis_exporter
Create a systemd service for Redis Exporter. This example assumes Redis is running on the default port 6379 and is accessible locally. For a cluster, you might need to adjust the --redis.addr flag or use a sentinel configuration.
[Unit] Description=Redis Exporter Wants=network-online.target After=network-online.target [Service] User=prometheus Group=prometheus Type=simple ExecStart=/usr/local/bin/redis_exporter --redis.addr=redis://localhost:6379 --namespace=redis_cluster_node1 # Adjust namespace per node [Install] WantedBy=multi-user.target
Save this as /etc/systemd/system/redis_exporter.service and enable/start it:
sudo systemctl daemon-reload sudo systemctl enable redis_exporter sudo systemctl start redis_exporter sudo systemctl status redis_exporter
Add a scrape job to your prometheus.yml for Redis Exporter. If you have multiple Redis nodes, you’ll have multiple scrape targets, each potentially with a distinct namespace for clarity in Grafana.
scrape_configs:
- job_name: 'redis'
static_configs:
- targets: ['YOUR_REDIS_NODE_IP_1:9121', 'YOUR_REDIS_NODE_IP_2:9121'] # Default port for redis_exporter
Laravel Application Metrics with Prometheus Client
To gain insight into your Laravel application’s performance, integrate the Prometheus PHP client. This allows you to expose custom metrics directly from your application, such as request counts, response times, and queue lengths.
First, install the client via Composer:
composer require promphp/prometheus_client_php
Create a metrics endpoint in your Laravel application. A common practice is to create a dedicated controller or route.
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Prometheus\CollectorRegistry;
use Prometheus\Render\RenderTextFormat;
use Prometheus\Storage\InMemory;
class MetricsController extends Controller
{
public function index()
{
// Use Redis for persistence if needed, otherwise InMemory is fine for simple cases
$adapter = new InMemory();
$registry = new CollectorRegistry($adapter);
// Example: Request Counter
$counter = $registry->registerCounter(
'app', 'requests_total', 'Total number of requests', ['method', 'uri']
);
// In a middleware or controller method, you'd increment this:
// $counter->inc(['GET', '/api/users']);
// Example: Response Time Histogram
$histogram = $registry->registerHistogram(
'app', 'request_duration_seconds', 'Duration of HTTP requests in seconds', ['method', 'uri']
);
// In a middleware or controller method, you'd observe this:
// $startTime = microtime(true);
// ... process request ...
// $duration = microtime(true) - $startTime;
// $histogram->observe($duration, ['GET', '/api/users']);
// Example: Queue Size Gauge (requires custom logic to fetch from Redis)
// $queueSize = $registry->registerGauge('app', 'queue_size', 'Current number of jobs in the queue');
// $queueSize->set(Redis::llen('your_queue_name'));
$renderer = new RenderTextFormat();
header('Content-Type: ' . RenderTextFormat::MIME_TYPE);
echo $renderer->render($registry->getMetricFamilySamples());
exit;
}
}
Register this in your routes/web.php or routes/api.php:
use App\Http\Controllers\MetricsController;
Route::get('/metrics', [MetricsController::class, 'index']);
Finally, configure Prometheus to scrape your application’s metrics endpoint:
scrape_configs:
- job_name: 'laravel_app'
static_configs:
- targets: ['YOUR_LARAVEL_APP_IP:80'] # Or the specific IP/port your app is served on
Grafana Dashboards: Visualizing Your Data
Grafana is where you’ll visualize the metrics collected by Prometheus. Install Grafana on a separate server or on one of your existing Linode instances (ensure proper firewall rules).
Add Prometheus as a data source in Grafana. Navigate to Configuration -> Data Sources -> Add data source -> Prometheus. Enter the URL of your Prometheus server (e.g., http://YOUR_PROMETHEUS_IP:9090).
Import pre-built dashboards for Node Exporter and Redis Exporter. You can find excellent community dashboards on Grafana.com. Search for “Node Exporter Full” (Dashboard ID: 1860) and “Redis” (Dashboard ID: 763).
For your custom Laravel application metrics, you’ll need to create your own dashboard panels. Here are some essential queries:
Total Requests (Laravel App):
sum(rate(app_requests_total[5m])) by (method, uri)
Average Request Duration (Laravel App):
sum(rate(app_request_duration_seconds_sum[5m])) by (method, uri) / sum(rate(app_request_duration_seconds_count[5m])) by (method, uri)
Redis Memory Usage (per node):
redis_memory_used_bytes
Redis Command Latency (average per second):
avg(rate(redis_commands_duration_seconds_sum[5m])) by (command) / avg(rate(redis_commands_duration_seconds_count[5m])) by (command)
CPU Usage (per Linode):
100 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100
Alerting with Alertmanager
Effective monitoring isn’t complete without proactive alerting. Prometheus integrates with Alertmanager to handle alerts generated by Prometheus rules.
Set up Alertmanager similarly to Prometheus and Node Exporter, including a systemd service. Configure Prometheus to send alerts to Alertmanager in its prometheus.yml:
alerting:
alertmanagers:
- static_configs:
- targets: ['YOUR_ALERTMANAGER_IP:9093'] # Replace with your Alertmanager address
Define alerting rules in Prometheus. For example, to alert if a Redis node is unreachable or if CPU usage is consistently high:
groups:
- name: redis_alerts
rules:
- alert: RedisDown
expr: up{job="redis"} == 0
for: 5m
labels:
severity: critical
annotations:
summary: "Redis instance {{ $labels.instance }} is down."
description: "Prometheus could not scrape Redis at {{ $labels.instance }} for 5 minutes."
- name: node_alerts
rules:
- alert: HighCpuUsage
expr: 100 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100 > 90
for: 10m
labels:
severity: warning
annotations:
summary: "High CPU usage on {{ $labels.instance }}"
description: "CPU usage on {{ $labels.instance }} is above 90% for 10 minutes."
Configure Alertmanager’s alertmanager.yml to define receivers (e.g., Slack, PagerDuty, email) and routing rules. This ensures critical alerts reach the right people promptly.
Linode Specific Considerations
Firewall Rules: Ensure your Linode firewall (or UFW) allows traffic on the necessary ports: Prometheus (9090), Grafana (3000), Node Exporter (9100), Redis Exporter (9121), and Alertmanager (9093). Restrict access to these ports to only trusted IP addresses (e.g., your monitoring server, your office IP).
Resource Allocation: Monitoring components themselves consume resources. For busy applications, Prometheus can become resource-intensive. Allocate sufficient CPU, RAM, and disk space to your Prometheus and Grafana instances. Consider using a dedicated Linode for your monitoring stack as your application scales.
Persistent Storage: Prometheus stores time-series data. Ensure the disk where Prometheus writes its data has enough capacity and is backed by reliable storage. For long-term retention, configure Prometheus’s remote write capabilities to send data to a long-term storage solution like Thanos or VictoriaMetrics.
Redis Cluster Topology: When monitoring a Redis cluster, ensure your Redis Exporter configuration correctly targets all master and replica nodes. If using Redis Sentinel, configure the exporter to connect via Sentinel for high availability.
By implementing this layered monitoring approach, you gain deep visibility into your Laravel application and Redis cluster’s health and performance on Linode, enabling proactive issue detection and resolution.