• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Server Monitoring Best Practices: Keeping Your Laravel App and PostgreSQL Clusters Alive on AWS

Server Monitoring Best Practices: Keeping Your Laravel App and PostgreSQL Clusters Alive on AWS

Proactive PostgreSQL Monitoring with CloudWatch and RDS Performance Insights

Maintaining the health and performance of PostgreSQL clusters on AWS RDS is paramount for any production Laravel application. Relying solely on reactive alerts is a recipe for disaster. We need a multi-layered approach that combines AWS’s native monitoring tools with deep-dive analysis capabilities.

AWS CloudWatch provides the foundational metrics for RDS instances. Key metrics to monitor include:

  • CPUUtilization: High CPU can indicate inefficient queries or insufficient instance sizing.
  • FreeableMemory: Low freeable memory suggests memory pressure, impacting cache performance and potentially leading to swapping.
  • ReadIOPS and WriteIOPS: Spikes or sustained high IOPS can point to I/O bottlenecks.
  • ReadLatency and WriteLatency: Increasing latency is a direct indicator of performance degradation.
  • DatabaseConnections: A sudden surge or consistently high number of connections can exhaust resources.
  • DiskQueueDepth: High queue depth signifies that the storage subsystem cannot keep up with the I/O requests.

Setting up CloudWatch alarms for these metrics is the first line of defense. We’ll configure alarms to trigger at thresholds that indicate potential issues before they become critical. For instance, a CPUUtilization alarm at 80% for 15 minutes, or FreeableMemory below 20% for 10 minutes.

Configuring CloudWatch Alarms via AWS CLI

Automating alarm creation is crucial for consistency. Here’s how to set up an alarm for CPUUtilization using the AWS CLI:

aws cloudwatch put-metric-alarm \
    --alarm-name "RDS-MyLaravelDB-HighCPU" \
    --alarm-description "Alarm when CPU utilization exceeds 80% for 15 minutes" \
    --metric-name CPUUtilization \
    --namespace AWS/RDS \
    --statistic Average \
    --period 900 \
    --threshold 80 \
    --comparison-operator GreaterThanOrEqualToThreshold \
    --dimensions "Name=DBInstanceIdentifier,Value=my-laravel-rds-instance" \
    --evaluation-periods 1 \
    --datapoints-to-alarm 1 \
    --treat-missing-data notBreaching \
    --alarm-actions arn:aws:sns:us-east-1:123456789012:my-monitoring-sns-topic

Replace my-laravel-rds-instance and the SNS topic ARN with your specific values. Repeat this process for other critical metrics.

Beyond basic metrics, RDS Performance Insights offers invaluable granular insights into database load. It helps identify which SQL queries, wait events, and hosts are consuming the most resources. This is indispensable for diagnosing performance bottlenecks that CloudWatch alone might miss.

Leveraging RDS Performance Insights for Query Optimization

Once Performance Insights is enabled on your RDS instance, you can access its dashboard in the AWS console. Key areas to scrutinize include:

  • Top SQL by Load: Identify the most resource-intensive queries. Look for queries with high DB Load, Execution Count, and Avg Elapsed Time.
  • Top Wait Events: Understand what is causing the database to pause. Common culprits include IO/FileRead, Lock/Lock, and LWLock/WALWriteLock.
  • Top Hosts/Users: Pinpoint which applications or users are contributing most to the database load.

For instance, if you see a query like SELECT * FROM users WHERE email = ? dominating the “Top SQL by Load” and the wait event is primarily IO/FileRead, it strongly suggests a missing index on the email column. A quick addition of an index can dramatically improve performance.

Laravel Application Monitoring with Prometheus and Grafana

While RDS handles the database, your Laravel application instances (running on EC2, ECS, or EKS) require their own robust monitoring. Prometheus and Grafana are a powerful open-source combination for this purpose.

Instrumenting Laravel with Prometheus Exporters

To expose application metrics to Prometheus, you need to instrument your Laravel application. The promphp/prometheus_client_php library is an excellent choice.

<?php
require 'vendor/autoload.php';

use Prometheus\CollectorRegistry;
use Prometheus\Render\CallbackRenderer;
use Prometheus\Storage\InMemory;

$adapter = new InMemory();
$registry = new CollectorRegistry($adapter);

// Example: Counter for HTTP requests
$counter = $registry->registerCounter('myapp_http_requests_total', 'Total number of HTTP requests', ['method', 'code']);

// Example: Gauge for current active users
$gauge = $registry->registerGauge('myapp_active_users', 'Number of currently active users', ['type']);

// Example: Histogram for request duration
$histogram = $registry->registerHistogram('myapp_request_duration_seconds', 'HTTP request duration in seconds', ['method', 'route']);

// In your Laravel middleware or controller:
// $method = $request->getMethod();
// $route = $request->route() ? $request->route()->getName() : 'no_route';
// $counter->inc([$method, $response->getStatusCode()]);
// $histogram->observe(microtime(true) - LARAVEL_REQUEST_START_TIME, [$method, $route]);

// Endpoint to expose metrics (e.g., /metrics)
header('Content-type: text/plain');
$renderer = new CallbackRenderer($registry);
echo $renderer->render();
?>

You would typically create a dedicated route (e.g., /metrics) in your Laravel application that serves these metrics. This route should be accessible by your Prometheus server.

Configuring Prometheus Scrape Targets

Your Prometheus server needs to know where to find these metrics endpoints. Edit your prometheus.yml configuration file.

scrape_configs:
  - job_name: 'laravel_app'
    static_configs:
      - targets: ['app-instance-1.example.com:80', 'app-instance-2.example.com:80'] # Replace with your app instance IPs/hostnames
        labels:
          env: 'production'
          app: 'laravel'

  - job_name: 'laravel_app_metrics'
    metrics_path: '/metrics' # The path where your app exposes metrics
    static_configs:
      - targets: ['app-instance-1.example.com:80', 'app-instance-2.example.com:80'] # Same instances, but hitting the /metrics endpoint
        labels:
          env: 'production'
          app: 'laravel'

  - job_name: 'postgres_exporter'
    static_configs:
      - targets: ['postgres-exporter.example.com:9187'] # Assuming you run postgres_exporter
        labels:
          env: 'production'
          db: 'postgres'

For PostgreSQL, consider running the postgres_exporter alongside your database or on a dedicated instance. This exporter provides detailed PostgreSQL metrics that can be scraped by Prometheus.

Visualizing Data with Grafana Dashboards

Grafana connects to your Prometheus data source and allows you to build rich, interactive dashboards. You can import pre-built dashboards for PostgreSQL and create custom ones for your Laravel application metrics.

A good Grafana dashboard for your Laravel app should include:

  • HTTP request rates and error rates (using myapp_http_requests_total).
  • Request latency distributions (using myapp_request_duration_seconds).
  • Active user counts (using myapp_active_users).
  • PHP-FPM pool statistics (if applicable).
  • Server-level metrics (CPU, memory, network) from node_exporter.

For PostgreSQL, a dashboard visualizing metrics from postgres_exporter and RDS Performance Insights (if you can integrate it, though direct integration is complex and often involves custom solutions or third-party tools) is essential. Key PostgreSQL metrics to visualize include:

  • Replication lag.
  • Connection counts.
  • Query throughput and latency.
  • Cache hit ratios.
  • Disk I/O and utilization.
  • Transaction rates.

Alerting with Alertmanager

Prometheus itself doesn’t handle alerting; it relies on Alertmanager. Alertmanager deduplicates, groups, and routes alerts to the correct notification channels (Slack, PagerDuty, email, etc.).

Defining Alerting Rules in Prometheus

Alerting rules are defined in separate YAML files that Prometheus loads. Here are examples for Laravel and PostgreSQL:

groups:
- name: laravel_alerts
  rules:
  - alert: HighHttpRequestRate
    expr: sum(rate(myapp_http_requests_total{env="production"}[5m])) by (app) > 1000
    for: 10m
    labels:
      severity: warning
    annotations:
      summary: "High HTTP request rate detected for {{ $labels.app }}"
      description: "The application {{ $labels.app }} is experiencing a high request rate ({{ $value | humanize }} req/s)."

  - alert: HighHttpRequestLatency
    expr: histogram_quantile(0.95, sum(rate(myapp_request_duration_seconds_bucket{env="production"}[5m])) by (le, method, route)) > 2.0
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "High 95th percentile request latency for {{ $labels.method }} {{ $labels.route }}"
      description: "95% of requests for {{ $labels.method }} {{ $labels.route }} are taking longer than 2.0 seconds."

- name: postgres_alerts
  rules:
  - alert: HighPostgresCPU
    expr: avg by (instance) (rate(pg_stat_activity_numbackends{state="active"}[5m])) > 100 # Example, adjust based on your instance type
    for: 15m
    labels:
      severity: warning
    annotations:
      summary: "High CPU utilization on PostgreSQL instance {{ $labels.instance }}"
      description: "PostgreSQL instance {{ $labels.instance }} has high CPU utilization."

  - alert: ReplicationLagging
    expr: pg_replication_lag_seconds{master_replica="replica"} > 60
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "PostgreSQL replication lag detected on replica {{ $labels.replica_name }}"
      description: "Replication lag on {{ $labels.replica_name }} is {{ $value }} seconds, exceeding the 60-second threshold."

These rules are then configured in Prometheus to be sent to Alertmanager.

Configuring Alertmanager Routing

The alertmanager.yml file defines how alerts are routed. A typical configuration might route critical alerts to PagerDuty and warnings to Slack.

global:
  resolve_timeout: 5m

route:
  group_by: ['alertname', 'cluster', 'service']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  receiver: 'default-receiver' # Default receiver if no specific routes match

  routes:
  - match:
      severity: 'critical'
    receiver: 'pagerduty-critical'
    continue: true # Allows further routing if needed

  - match:
      severity: 'warning'
    receiver: 'slack-warnings'
    continue: true

receivers:
- name: 'default-receiver'
  slack_configs:
  - api_url: 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX'
    channel: '#monitoring-alerts'

- name: 'pagerduty-critical'
  pagerduty_configs:
  - service_key: 'YOUR_PAGERDUTY_INTEGRATION_KEY'

- name: 'slack-warnings'
  slack_configs:
  - api_url: 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX'
    channel: '#monitoring-warnings'

Ensure your Alertmanager is configured to receive alerts from Prometheus and that the notification integrations (Slack webhooks, PagerDuty keys) are correctly set up.

System-Level Monitoring with EC2/ECS/EKS Agents

For infrastructure-level metrics, we rely on AWS CloudWatch Agent (for EC2) or the CloudWatch Container Insights agents (for ECS/EKS). These agents collect system-level metrics and logs that are crucial for understanding the overall health of your compute resources.

CloudWatch Agent Configuration for EC2

The CloudWatch Agent can be configured to collect system metrics (CPU, memory, disk, network) and application logs. The configuration is typically stored in a JSON file.

{
  "agent": {
    "metrics_collection_interval": 60,
    "run_as_user": "cwagent"
  },
  "metrics": {
    "namespace": "MyLaravelApp/EC2",
    "metrics_collected": {
      "cpu": {
        "resources": [
          "*"
        ],
        "measurement": [
          "cpu_usage_idle",
          "cpu_usage_iowait",
          "cpu_usage_user",
          "cpu_usage_system"
        ],
        "totalcpu_time_metrics": true
      },
      "mem": {
        "measurement": [
          "mem_used_percent",
          "mem_used",
          "mem_total"
        ]
      },
      "disk": {
        "resources": [
          "/",
          "/var/log"
        ],
        "measurement": [
          "used_percent",
          "inodes_free"
        ]
      },
      "net": {
        "resources": [
          "eth0"
        ],
        "measurement": [
          "bytes_sent",
          "bytes_recv",
          "packets_sent",
          "packets_recv"
        ]
      }
    }
  },
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_path": "/var/www/html/storage/logs/laravel.log",
            "log_group_name": "MyLaravelApp/LaravelLogs",
            "log_stream_name": "{instance_id}/laravel",
            "timezone": "UTC"
          }
        ]
      }
    }
  }
}

Install the CloudWatch Agent on your EC2 instances and point it to this configuration file. You can then create CloudWatch Alarms based on these custom metrics (e.g., MyLaravelApp/EC2/mem_used_percent).

CloudWatch Container Insights for ECS/EKS

For containerized applications, CloudWatch Container Insights simplifies the collection of performance metrics and logs from your ECS or EKS clusters. It automatically collects:

  • Cluster-level metrics (CPU, memory utilization).
  • Service-level metrics (task counts, desired vs. running tasks).
  • Task-level metrics (individual container CPU/memory usage).
  • Pod-level metrics (for EKS).
  • Container logs.

Enabling Container Insights is done via the AWS console or AWS CLI when creating or updating your ECS cluster or EKS cluster configuration. Once enabled, you can view these metrics and logs directly within the CloudWatch console under the “Container Insights” section.

You can also create CloudWatch Alarms based on Container Insights metrics, such as high CPU or memory utilization for specific services or tasks.

Conclusion: A Holistic Monitoring Strategy

A robust server monitoring strategy for a Laravel application on AWS involves a layered approach. It starts with foundational RDS metrics and Performance Insights for database health, extends to application-level instrumentation with Prometheus and Grafana for deep visibility into Laravel’s performance, and is complemented by system-level metrics from CloudWatch Agents or Container Insights. Proactive alerting via Alertmanager ensures that your team is notified of issues before they impact users. This comprehensive strategy is key to maintaining high availability and performance for your critical applications.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • How to securely integrate Firebase Realtime DB endpoints into WordPress custom plugins using Shortcode API
  • Step-by-Step Guide to building a custom dynamic lead collector block for Gutenberg using HTMX dynamic attributes
  • How to securely integrate Zapier dynamic webhooks endpoints into WordPress custom plugins using Metadata API (add_post_meta)
  • Troubleshooting nonce validation collisions in production when using modern Sage Roots modern environments wrappers
  • How to securely integrate Algolia Search API endpoints into WordPress custom plugins using Block Patterns API

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (586)
  • Desktop Applications (14)
  • DevOps (7)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (4)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (809)
  • PHP (5)
  • PHP Development (23)
  • Plugins & Themes (244)
  • Programming Languages (9)
  • Python (20)
  • Ruby on Rails (1)
  • Security & Compliance (546)
  • SEO & Growth (492)
  • Server (23)
  • Ubuntu (9)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (22)
  • WordPress Plugin Development (16)
  • WordPress Theme Development (357)

Recent Posts

  • How to securely integrate Firebase Realtime DB endpoints into WordPress custom plugins using Shortcode API
  • Step-by-Step Guide to building a custom dynamic lead collector block for Gutenberg using HTMX dynamic attributes
  • How to securely integrate Zapier dynamic webhooks endpoints into WordPress custom plugins using Metadata API (add_post_meta)

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (809)
  • Debugging & Troubleshooting (586)
  • Security & Compliance (546)
  • SEO & Growth (492)
  • Business & Monetization (390)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala