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

Vengala Vinay

Having 9+ Years of Experience in Software Development

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

Server Monitoring Best Practices: Keeping Your PHP App and DynamoDB Clusters Alive on AWS

Proactive PHP Application Health Checks

A robust monitoring strategy for PHP applications on AWS begins with comprehensive health checks. These aren’t just about whether the web server is responding; they need to probe the application’s core functionality and dependencies. For a typical PHP application, this means checking database connectivity, critical API endpoints, and potentially background job queues.

We’ll implement a simple PHP script that acts as our health check endpoint. This script will perform several checks and return a standardized JSON response. This allows external monitoring services (like AWS CloudWatch, Datadog, or Prometheus) to easily parse the status.

PHP Health Check Script

<?php
header('Content-Type: application/json');

$response = [
    'status' => 'error',
    'checks' => [],
    'timestamp' => time(),
];

// --- Database Check ---
$db_host = getenv('DB_HOST') ?: 'localhost';
$db_name = getenv('DB_NAME') ?: 'myapp_db';
$db_user = getenv('DB_USER') ?: 'db_user';
$db_pass = getenv('DB_PASS') ?: 'db_password';
$db_port = getenv('DB_PORT') ?: '3306';

try {
    // Using PDO for broad compatibility
    $dsn = "mysql:host={$db_host};port={$db_port};dbname={$db_name};charset=utf8mb4";
    $options = [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_TIMEOUT => 5, // 5-second timeout
    ];
    $pdo = new PDO($dsn, $db_user, $db_pass, $options);
    // Perform a simple query to verify connection and basic functionality
    $stmt = $pdo->query("SELECT 1");
    $stmt->fetch();
    $response['checks']['database'] = ['status' => 'ok', 'message' => 'Successfully connected to database.'];
} catch (PDOException $e) {
    $response['checks']['database'] = ['status' => 'error', 'message' => 'Database connection failed: ' . $e->getMessage()];
}

// --- External API Check (Example) ---
$api_url = getenv('EXTERNAL_API_URL') ?: 'https://api.example.com/health';
$api_timeout = 5; // seconds

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $api_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, $api_timeout);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $api_timeout);
// For HTTPS, you might need to handle certificates, but for a basic check:
// curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Use with caution in production

$api_response_body = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curl_error = curl_error($ch);
curl_close($ch);

if ($curl_error) {
    $response['checks']['external_api'] = ['status' => 'error', 'message' => 'cURL error: ' . $curl_error];
} elseif ($http_code >= 200 && $http_code < 300) {
    // Optionally parse the API response body if it's JSON and has a status field
    $api_data = json_decode($api_response_body, true);
    if (json_last_error() === JSON_ERROR_NONE && isset($api_data['status']) && $api_data['status'] === 'ok') {
        $response['checks']['external_api'] = ['status' => 'ok', 'message' => 'External API is healthy.'];
    } else {
        $response['checks']['external_api'] = ['status' => 'warning', 'message' => "External API responded with HTTP {$http_code} but status was not 'ok' or response was not valid JSON."];
    }
} else {
    $response['checks']['external_api'] = ['status' => 'error', 'message' => "External API responded with HTTP status: {$http_code}"];
}

// --- Overall Status Determination ---
$overall_status = 'ok';
foreach ($response['checks'] as $check) {
    if ($check['status'] === 'error') {
        $overall_status = 'error';
        break;
    } elseif ($check['status'] === 'warning') {
        // If any check is a warning, the overall status is warning unless an error is found
        if ($overall_status !== 'error') {
            $overall_status = 'warning';
        }
    }
}
$response['status'] = $overall_status;

// --- Output JSON ---
echo json_encode($response, JSON_PRETTY_PRINT);

exit(0); // Ensure script exits cleanly
?>

Deploy this script to a publicly accessible (or internally accessible if using private monitoring) path on your web server, e.g., /healthcheck.php. Ensure your web server (Nginx/Apache) is configured to execute PHP scripts. For production, it’s crucial to configure the database credentials and external API URL via environment variables for security and flexibility. This script should be placed in a location that is not easily discoverable by unauthenticated users if it exposes sensitive information.

AWS CloudWatch Alarms for PHP App Metrics

CloudWatch is the foundational monitoring service on AWS. For PHP applications, we need to monitor key performance indicators (KPIs) and set up alarms to notify us of potential issues before they impact users.

Key Metrics to Monitor

  • CPU Utilization: High CPU can indicate inefficient code, traffic spikes, or resource contention.
  • Memory Utilization: PHP’s memory usage can creep up, especially with long-running processes or memory leaks.
  • Network In/Out: Useful for understanding traffic patterns and potential network bottlenecks.
  • Disk I/O: Important if your application performs significant disk operations (logging, caching).
  • HTTP 5xx Errors: Directly indicates server-side application failures.
  • Latency: Measures the time it takes for your application to respond to requests.
  • Request Count: Tracks the volume of incoming traffic.

These metrics are typically available for EC2 instances (via the CloudWatch agent) and container services like ECS/EKS. For Elastic Beanstalk, many of these are automatically collected.

Setting Up CloudWatch Alarms via AWS CLI

Let’s configure an alarm for high CPU utilization on an EC2 instance. Replace YOUR_EC2_INSTANCE_ID and YOUR_SNS_TOPIC_ARN with your actual values.

aws cloudwatch put-metric-alarm \
    --alarm-name "High-CPU-Utilization-PHP-App-$(date +%Y-%m-%d-%H-%M-%S)" \
    --alarm-description "Alarm when CPU utilization exceeds 80% for 15 minutes" \
    --metric-name CPUUtilization \
    --namespace AWS/EC2 \
    --statistic Average \
    --period 300 \
    --threshold 80 \
    --comparison-operator GreaterThanThreshold \
    --dimensions Name=InstanceId,Value=YOUR_EC2_INSTANCE_ID \
    --evaluation-periods 3 \
    --datapoints-to-alarm 3 \
    --treat-missing-data notBreaching \
    --alarm-actions YOUR_SNS_TOPIC_ARN

To monitor HTTP 5xx errors, you’ll typically need to configure your web server (Nginx/Apache) to send logs to CloudWatch Logs, and then create metric filters based on those logs. For example, an Nginx access log entry indicating a 500 error might look like:

192.168.1.10 - - [10/Oct/2023:10:30:00 +0000] "GET /api/users HTTP/1.1" 500 123 "-" "curl/7.68.0"

You would then create a CloudWatch Logs metric filter like this (using AWS CLI):

aws logs put-metric-filter \
    --log-group-name "/aws/nginx/access-logs" \
    --filter-name "Http5xxErrors" \
    --filter-pattern '(?<!-)5\d{2}' \
    --metric-transformations metricName=Http5xxErrors,metricNamespace=MyPHPApp,metricValue=1,defaultValue=0

And then create an alarm on the Http5xxErrors metric from the MyPHPApp namespace.

DynamoDB Cluster Monitoring Best Practices

DynamoDB, being a fully managed NoSQL database, shifts the monitoring focus from infrastructure to performance and capacity. Key metrics revolve around throughput, latency, and errors.

Essential DynamoDB Metrics

  • ConsumedReadCapacityUnits: The number of read units consumed by your operations.
  • ConsumedWriteCapacityUnits: The number of write units consumed.
  • ReadThrottleEvents: Number of read requests that were throttled because they exceeded provisioned throughput.
  • WriteThrottleEvents: Number of write requests that were throttled.
  • SuccessfulRequestLatency: The time taken for successful requests. Monitor the 95th or 99th percentile.
  • SystemErrors: Number of requests that failed due to internal DynamoDB errors.

Setting Up DynamoDB Alarms

Throttling is a critical indicator that your provisioned throughput is insufficient or that your application’s access patterns are not well-distributed. Alarms on throttled events are essential.

# Alarm for Read Throttling on a specific table
aws cloudwatch put-metric-alarm \
    --alarm-name "DynamoDB-Read-Throttling-MyTable-$(date +%Y-%m-%d-%H-%M-%S)" \
    --alarm-description "Alarm when read throttling events exceed 0 for 5 minutes on MyTable" \
    --metric-name ReadThrottleEvents \
    --namespace AWS/DynamoDB \
    --statistic Sum \
    --period 60 \
    --threshold 0 \
    --comparison-operator GreaterThanThreshold \
    --dimensions Name=TableName,Value=MyTable \
    --evaluation-periods 5 \
    --datapoints-to-alarm 5 \
    --treat-missing-data notBreaching \
    --alarm-actions YOUR_SNS_TOPIC_ARN

# Alarm for High Latency (95th percentile)
aws cloudwatch put-metric-alarm \
    --alarm-name "DynamoDB-High-Latency-MyTable-$(date +%Y-%m-%d-%H-%M-%S)" \
    --alarm-description "Alarm when 95th percentile latency exceeds 100ms for 10 minutes on MyTable" \
    --metric-name SuccessfulRequestLatency \
    --namespace AWS/DynamoDB \
    --statistic p95 \
    --period 60 \
    --threshold 100 \
    --comparison-operator GreaterThanThreshold \
    --dimensions Name=TableName,Value=MyTable \
    --evaluation-periods 10 \
    --datapoints-to-alarm 10 \
    --treat-missing-data notBreaching \
    --alarm-actions YOUR_SNS_TOPIC_ARN

It’s also vital to monitor ConsumedReadCapacityUnits and ConsumedWriteCapacityUnits relative to your provisioned capacity. If consumption consistently hovers near provisioned limits, consider enabling Auto Scaling for DynamoDB or proactively increasing provisioned capacity.

Integrating Application Health Checks with CloudWatch

The PHP health check script we created can be integrated with CloudWatch using the CloudWatch Agent. This allows us to ingest custom metrics and logs, and trigger alarms based on application-level health.

Configuring the CloudWatch Agent

First, ensure the CloudWatch Agent is installed on your EC2 instances. Then, configure its amazon-cloudwatch-agent.json file. We’ll set it up to scrape our health check endpoint and send the results as custom metrics.

{
  "agent": {
    "metrics_collection_interval": 60,
    "run_as_user": "cwagent"
  },
  "metrics": {
    "namespace": "MyPHPApp/HealthCheck",
    "append_dimensions": {
      "InstanceId": "${aws:InstanceId}"
    },
    "metrics_collected": {
      "http_listener": {
        "url": "http://localhost/healthcheck.php",
        "interval": 60,
        "metrics": [
          {
            "name": "HealthStatus",
            "unit": "Count",
            "dimensions": [["Status"]]
          }
        ]
      }
    }
  },
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_path": "/var/log/httpd/access_log",
            "log_group_name": "/aws/apache/access_log",
            "log_stream_name": "{instance_id}/access_log"
          },
          {
            "file_path": "/var/log/nginx/access.log",
            "log_group_name": "/aws/nginx/access_log",
            "log_stream_name": "{instance_id}/access_log"
          }
        ]
      }
    }
  }
}

After applying this configuration (e.g., using sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json -s), you'll see custom metrics like MyPHPApp/HealthCheck/HealthStatus in CloudWatch. You can then create alarms based on this metric. For instance, an alarm that triggers if the HealthStatus metric is 0 (indicating an error) for 3 consecutive 60-second intervals.

aws cloudwatch put-metric-alarm \
    --alarm-name "PHP-App-Unhealthy-$(date +%Y-%m-%d-%H-%M-%S)" \
    --alarm-description "Alarm when PHP application health check reports an error" \
    --metric-name HealthStatus \
    --namespace "MyPHPApp/HealthCheck" \
    --statistic Sum \
    --period 60 \
    --threshold 0 \
    --comparison-operator EqualToThreshold \
    --dimensions Name=Status,Value=error \
    --evaluation-periods 3 \
    --datapoints-to-alarm 3 \
    --treat-missing-data notBreaching \
    --alarm-actions YOUR_SNS_TOPIC_ARN

This approach provides a layered monitoring strategy, combining infrastructure-level metrics with application-specific health checks, ensuring comprehensive visibility into your PHP application and DynamoDB cluster's operational status on AWS.

Primary Sidebar

A little about the Author

Having 9+ Years of Experience in Software Development.
Expertised in Php Development, WordPress Custom Theme Development (From scratch using underscores or Genesis Framework or using any blank theme or Premium Theme), Custom Plugin Development. Hands on Experience on 3rd Party Php Extension like Chilkat, nSoftware.

Recent Posts

  • Step-by-Step: Diagnosing thread pools deadlock during concurrent ActiveRecord transaction processing on Linode Servers
  • Securing Your E-commerce APIs: Preventing SQL Injection (SQLi) in customized checkout queries in WooCommerce Implementations
  • Disaster Recovery 101: Architecting Auto-Failovers for MySQL and Ruby Deployments on Linode
  • High-Throughput Caching Strategies: Scaling MySQL for Perl Application APIs
  • Disaster Recovery 101: Architecting Auto-Failovers for DynamoDB and Laravel Deployments on DigitalOcean

Copyright © 2026 · Vinay Vengala