Benjamin Benjamin 20.12.2016

Seperate your slow backend from the important frontend traffic with PHP-FPM

If you are using Magento, Shopware, Oxid, a CMS or any other off the shelf software, then usually they ship both the frontend and the backend in a single application. For self-developed applications with Symfony or other frameworks this is often the case as well.

The backend/admin may then include several slow reporting, administrative operations and data exports that can take a long time. This could congest the webservers processing queue by lowering the throughput for your customers that might just click on the checkout button and see a 502 Gateway error. We described this behaviour in the last blog post on What is the best value of PHPs max_execution_time?.

Putting frontend and backend on different servers is one solution, but this can be to costly for most use-cases.

A simple solution for this problem is using different PHP-FPM pools for the frontend and backend, each with their own configuration for the maximum number of allowed requests. This is also a solution for some of the problems discussed in the post on "What is the best value for max execution time?".

Magento Admin and Frontend Example

How does this look like? Lets use Magento as an example, you can configure two pools in php-fpm.conf:

; php-fpm.conf
[frontend]
listen = /var/run/php-fpm-frontend.sock
pm = static
pm.max_children = 50

[backend]
listen = /var/run/php-fpm-backend.sock
pm = ondemand
pm.max_children = 5
pm.process_idle_timeout = 5

The frontend is configured for maximum of 50 simultaneous requests and the backend for a maximum of 5 simultaneous requests. The backend workers are created on demand and the frontend workers are static to avoid forking overhead. I will discuss the differences between PHP-FPM pool configurations in a future blog post.

You can then modify the Nginx vhost configuration for the Magento installation with the following switch:

server {
    // ....

    set $fpm_socket = "unix:/var/run/php-fpm-frontend.sock";

    if ($uri ~* "^/admin/") {
        set $fpm_socket "unix:/var/run/php-fpm-backend.sock";
    }

    location ~ .php$ {
        // ...

        fastcgi_pass $fpm_socket;
    }
}

Based on the ^/admin path in the request uri it will select the different PHP FPM pool now and frontend and backend will not compete and steal each other resources anymore.