• 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 » Scaling PHP on OVH to Handle 50,000+ Concurrent Requests

Scaling PHP on OVH to Handle 50,000+ Concurrent Requests

Architectural Foundation: Load Balancing and PHP-FPM Configuration

Achieving 50,000+ concurrent requests for a PHP application on OVH necessitates a robust, multi-layered architecture. At its core, this involves intelligent load balancing and meticulously tuned PHP-FPM configurations. We’ll leverage HAProxy for load balancing due to its performance and flexibility, and dive deep into optimizing PHP-FPM for high concurrency.

HAProxy Configuration for High Throughput

Our HAProxy setup will distribute traffic across multiple PHP-FPM backend servers. Key to this is configuring HAProxy to handle a large number of concurrent connections efficiently. We’ll focus on the `frontend` and `backend` sections, emphasizing connection pooling and health checks.

HAProxy Frontend Configuration

The frontend listens for incoming connections. We’ll set appropriate timeouts and enable connection queuing to prevent overload during traffic spikes. The `maxconn` directive is crucial here.

frontend http_in
    bind *:80
    bind *:443 ssl crt /etc/ssl/private/your_domain.pem
    mode http
    option httplog
    option forwardfor
    # Increase max connections to handle high concurrency. Adjust based on server resources.
    maxconn 60000
    # Queue connections if backend servers are overloaded.
    # This prevents HAProxy from dropping connections directly.
    # The 'timeout queue' prevents clients from waiting indefinitely.
    queue 10000 timeout 5s

    acl is_static       url_static       -i .jpg .jpeg .png .gif .css .js .ico .svg .woff .woff2
    acl is_api          path_beg         /api/
    acl is_app          path_beg         /

    # Route static assets directly to a web server (e.g., Nginx)
    use_backend static_servers if is_static
    # Route API requests to PHP-FPM backend
    use_backend php_app_servers if is_api
    # Route general app requests to PHP-FPM backend
    use_backend php_app_servers if is_app

    default_backend php_app_servers

HAProxy Backend Configuration

The backend defines the pool of PHP-FPM servers. We’ll use the `httpchk` directive for robust health checks and configure connection pooling to minimize latency. The `server` line specifies the IP address and port of each PHP-FPM instance.

backend php_app_servers
    mode http
    balance roundrobin
    # Use HTTP check for PHP-FPM health. A simple /healthz endpoint is recommended.
    # Ensure your PHP application has a /healthz endpoint that returns 200 OK.
    option httpchk GET /healthz HTTP/1.1\r\nHost:\ localhost
    http-check expect status 200

    # Configure connection pooling. 'maxconn' here is per server.
    # This should be tuned based on PHP-FPM's 'pm.max_children'.
    maxconn 1000

    # List your PHP-FPM backend servers.
    # Assuming PHP-FPM is running on port 9000 on these IPs.
    # Adjust 'check port' if your health check endpoint is on a different port.
    server php1 192.168.1.10:9000 check port 9000 inter 2s fall 3 rise 2 maxconn 1000
    server php2 192.168.1.11:9000 check port 9000 inter 2s fall 3 rise 2 maxconn 1000
    server php3 192.168.1.12:9000 check port 9000 inter 2s fall 3 rise 2 maxconn 1000
    server php4 192.168.1.13:9000 check port 9000 inter 2s fall 3 rise 2 maxconn 1000
    # Add more servers as needed.

backend static_servers
    mode http
    balance roundrobin
    # Assuming Nginx is serving static files on port 8080
    server static1 192.168.1.20:8080 check
    server static2 192.168.1.21:8080 check

PHP-FPM Tuning for High Concurrency

PHP-FPM’s process manager (`pm`) is critical. For high concurrency, the `dynamic` or `ondemand` process managers are generally preferred over `static` to conserve resources when idle, but `static` can offer lower latency if you have predictable, high load and sufficient RAM. We’ll focus on `dynamic` with aggressive tuning.

PHP-FPM Pool Configuration (`www.conf`)

Locate your PHP-FPM pool configuration file (e.g., `/etc/php/8.1/fpm/pool.d/www.conf`). The following directives are key:

; Use 'dynamic' to allow PHP-FPM to scale processes based on demand.
; 'ondemand' can save memory but might introduce slight latency on initial requests.
pm = dynamic

; The maximum number of children that can be started.
; This should be tuned based on your server's RAM and CPU.
; A common starting point is (total RAM in MB / average process size in MB).
; For 50k+ concurrent requests, this will be high.
pm.max_children = 500

; The number of *additional* processes that will be spawned when the number of
; requests per second reaches this value.
; This helps to handle sudden traffic spikes.
pm.max_requests = 5000

; The initial number of children that will be created on startup.
pm.start_servers = 20

; The minimum number of children that will be kept active.
pm.min_spare_servers = 10

; The maximum number of children that will be kept active.
pm.max_spare_servers = 50

; The number of requests each child process should execute before respawning.
; This helps to free up memory leaks. Set to a high value if memory leaks are minimal.
; pm.max_requests = 0 ; Uncomment to disable respawning based on requests

; Set to 'on' to enable slow log for debugging performance issues.
; slowlog = /var/log/php-fpm/slow.log
; request_slowlog_timeout = 10s ; Define what is considered a slow request

; Set to 'on' to enable process group management for better resource isolation.
; pm.process_group = www-data
; pm.username = www-data
; pm.groupname = www-data

; Set to 'on' to enable TCP socket for PHP-FPM communication.
; This is often preferred over Unix sockets for performance and scalability across multiple servers.
; listen = 192.168.1.10:9000 ; Replace with your server's IP and desired port
; listen.owner = www-data
; listen.group = www-data
; listen.mode = 0660
; listen.acl_users = www-data
; listen.acl_groups = www-data

; If using Unix sockets (less common for distributed setups):
; listen = /run/php/php8.1-fpm.sock
; listen.owner = www-data
; listen.group = www-data
; listen.mode = 0660

Important Considerations for `pm.max_children`:

  • Each PHP-FPM child process consumes RAM. Monitor your server’s memory usage closely. If `pm.max_children` is too high, you’ll experience OOM (Out Of Memory) killer events.
  • The value of `pm.max_children` should align with HAProxy’s `maxconn` and the `maxconn` on each backend server. A common ratio is `HAProxy maxconn / number of backend servers = per-server maxconn`. Then, `per-server maxconn` should be less than or equal to `PHP-FPM pm.max_children`.
  • If using `dynamic`, `pm.max_requests` is crucial to prevent memory leaks from accumulating over time. Tune it based on your application’s memory footprint.

Application-Level Optimizations

Even with a perfectly tuned infrastructure, a poorly optimized PHP application will bottleneck. Focus on database query optimization, efficient caching, and minimizing external API calls.

Database Query Optimization

Slow database queries are a common performance killer. Use tools like MySQL’s `EXPLAIN` to analyze query plans and add appropriate indexes. Consider using a connection pooler like ProxySQL if your database becomes a bottleneck.

-- Example: Analyzing a query with EXPLAIN
EXPLAIN SELECT u.id, u.name, COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.registration_date > '2023-01-01'
GROUP BY u.id, u.name
ORDER BY order_count DESC
LIMIT 10;

-- Potential Indexing Strategy:
-- CREATE INDEX idx_users_registration_date ON users (registration_date);
-- CREATE INDEX idx_orders_user_id ON orders (user_id);

Caching Strategies

Implement multiple layers of caching:

  • Opcode Cache (OPcache): Ensure OPcache is enabled and properly configured in `php.ini`. This is non-negotiable for PHP performance.
  • Object Caching (Redis/Memcached): Cache frequently accessed data, API responses, and computed results.
  • HTTP Caching (Varnish/CDN): Cache full page responses or static assets at the edge.

OPcache Configuration

; Ensure OPcache is enabled
opcache.enable=1
opcache.enable_cli=1 ; Enable for CLI scripts too

; Set the memory buffer size. Adjust based on your application's code size.
opcache.memory_consumption=256 ; in MB

; How long to keep scripts for which no changes were detected.
; For production, a higher value is generally better to reduce file stat calls.
opcache.revalidate_freq=60

; Enable OPcache error logging
opcache.error_log=/var/log/php/opcache.log

; Enable OPcache's built-in session handler (if applicable)
; opcache.save_comments=1
; opcache.load_comments=1

; Use this if you have very large codebases and need more memory
; opcache.huge_code_pages=1

Object Caching with Redis

Example using Predis library in PHP:

<?php
require 'vendor/autoload.php'; // Assuming Predis is installed via Composer

use Predis\Client;

// Configure Redis connection
$redis = new Client([
    'scheme' => 'tcp',
    'host'   => '192.168.1.30', // Your Redis server IP
    'port'   => 6379,
]);

// Example: Caching a database query result
$cacheKey = 'user_data:' . $userId;
$cachedData = $redis->get($cacheKey);

if ($cachedData) {
    $userData = json_decode($cachedData, true);
    echo "Data served from cache.\n";
} else {
    // Fetch data from database (replace with your actual DB query)
    $userData = fetchUserDataFromDatabase($userId);

    if ($userData) {
        // Cache the data for 1 hour (3600 seconds)
        $redis->set($cacheKey, json_encode($userData), 'EX', 3600);
        echo "Data fetched from DB and cached.\n";
    }
}

function fetchUserDataFromDatabase($userId) {
    // Simulate database fetch
    sleep(1); // Simulate latency
    return ['id' => $userId, 'name' => 'John Doe', 'email' => '[email protected]'];
}

?>

Monitoring and Diagnostics

Continuous monitoring is essential to identify bottlenecks and ensure stability. Implement comprehensive logging and use monitoring tools.

Key Metrics to Monitor

  • HAProxy Stats: Active connections, queue length, backend server health, request rates, error rates. Access HAProxy’s stats page (configured via `stats enable` and `stats uri`).
  • PHP-FPM Stats: Number of active processes, idle processes, requests per second, memory usage per process. Use PHP-FPM’s status page (requires `pm.status_path` in `www.conf`).
  • Server Resources: CPU utilization, memory usage, disk I/O, network traffic.
  • Application Performance Monitoring (APM): Tools like New Relic, Datadog, or custom solutions to trace requests through your application and identify slow code paths.
  • Database Performance: Slow query logs, connection counts, query latency.

Troubleshooting Common Issues

Issue: High Latency / Slow Responses

  • Check HAProxy Queue: If the HAProxy queue is consistently high, your backend servers are overloaded.
  • Check PHP-FPM Process Count: Are `pm.max_children` reached? If so, increase it or optimize the application.
  • Analyze Slow Logs: Check PHP-FPM slow logs and APM data for specific slow requests or database queries.
  • Database Load: Monitor database CPU, memory, and slow query logs.

Issue: 5xx Errors (Server Errors)

  • HAProxy Error Logs: Check HAProxy logs for backend connection failures or health check failures.
  • PHP-FPM Logs: Examine PHP-FPM error logs for fatal errors, memory exhaustion, or segmentation faults.
  • Application Errors: Ensure robust error handling in your PHP application and log all exceptions.
  • Resource Exhaustion: Monitor server memory and CPU. If OOM killer is active, reduce `pm.max_children` or add more resources.

Deployment and Scaling Strategy

To handle 50,000+ concurrent requests, a static configuration is insufficient. Implement a strategy for dynamic scaling.

Infrastructure as Code (IaC)

Use tools like Terraform or Ansible to automate the provisioning and configuration of your servers, HAProxy, and PHP-FPM instances. This ensures consistency and allows for rapid deployment of new resources.

Auto-Scaling Groups

Leverage OVH’s cloud capabilities (or equivalent) to implement auto-scaling groups for your PHP-FPM servers. Configure scaling policies based on metrics like CPU utilization or request queue length. When thresholds are breached, new PHP-FPM instances are automatically provisioned, configured, and added to the HAProxy backend pool.

Database Scaling

As your application scales, your database will likely become the next bottleneck. Consider:

  • Read Replicas: Offload read traffic to replica databases.
  • Sharding: Partition your data across multiple database instances for very large datasets.
  • Managed Database Services: Utilize OVH’s managed database offerings for easier scaling and maintenance.

By combining a well-configured HAProxy load balancer, meticulously tuned PHP-FPM processes, application-level optimizations, and a robust monitoring and auto-scaling strategy, you can effectively scale your PHP application on OVH to handle upwards of 50,000 concurrent requests.

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

  • Disaster Recovery 101: Architecting Auto-Failovers for Redis and PHP Deployments on OVH
  • How We Audited a High-Traffic WooCommerce Enterprise Stack on Google Cloud and Mitigated Race conditions during high-concurrency payment processing
  • Disaster Recovery 101: Architecting Auto-Failovers for Elasticsearch and Magento 2 Deployments on DigitalOcean
  • An Auditor’s Checklist for Securing WordPress Backends on OVH
  • Step-by-Step: Diagnosing Perl script high CPU throttling due to unoptimized regular expressions on AWS Servers

Copyright © 2026 · Vinay Vengala