Skip to content

Instantly share code, notes, and snippets.

@andreyserdjuk
Last active March 6, 2026 13:48
Show Gist options
  • Select an option

  • Save andreyserdjuk/930d773fdb45ebbbab90b76b89191173 to your computer and use it in GitHub Desktop.

Select an option

Save andreyserdjuk/930d773fdb45ebbbab90b76b89191173 to your computer and use it in GitHub Desktop.
php-fpm docker tuning

Make sure RAM is enough for php-fpm

IMPORTANT: first add docker container capabilities to allow smem exec ptrace and see php-fpm child processes:

# in docker-compose.yml
  my_app:
    container_name: my_app
    cap_add:
      - SYS_PTRACE

in aws ecs ec2:

{
  "containerDefinitions": [
    {
      "name": "app-service",
      "image": "",
      "cpu": 128,
      "memory": 256,
      "linuxParameters": {
        "capabilities": {
          "add": [
            "SYS_PTRACE"
          ]
        }
      },

install smem https://www.selenic.com/smem/

apt update && apt install smem -y
# use -a flag to see expanded path
smem -akt -P php-fpm

smem -k -c 'user command pss' -P php-fpm
User     Command                          PSS
root     php-fpm: master process (/u    14.2M
www-data php-fpm: pool app              15.2M
www-data php-fpm: pool app              15.7M
www-data php-fpm: pool app              16.5M

RAM is needed for caching filesystem

First see docker stats Block I/O - high (growing) values show insufficient RAM for filesystem cache. If system cannot put files to residet pages - it will continiously read them from block/disk storage. vmtouch shows the percentage of files cached in RAM:

apt install vmtouch -y
vmtouch test.php
           Files: 1
     Directories: 0
  Resident Pages: 1/1  4K/4K  100%
         Elapsed: 7e-05 seconds

htop MAJFLT column: $$\text{Disk Read} = \text{MAJFLT event} \rightarrow \text{Large Sequential I/O Volume}$$

apt install htop -y
# then goto Setup -> Columns -> PID -> MJFLT

See MAJFLT using htop, for example: 1,151 MAJFLT New Relic New Relic is instrumented inside the PHP application. This number represents the sum of all faults generated by the PHP process, plus any other related workers or modules, over the same time period.

enable php-fpm monitoring, slowlog, request_terminate_timeout

IMPORTANT: slowlog can add trace with php line caused slowlog - it uses ptrace, which requires SYS_PTRACE container capability (see above how to enable).

php-fpm -tt to see actual fpm config
php-fpm -i to see actual php config

[app]
pm.status_path = /status

; The timeout for serving a single request after which the worker process will
; be killed. This option should be used when the 'max_execution_time' ini option
; does not stop script execution for some reason. A value of '0' means 'off'.
; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
; Default Value: 0
request_terminate_timeout = 35s

; The timeout for serving a single request after which a PHP backtrace will be
; dumped to the 'slowlog' file. A value of '0s' means 'off'.
; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
; Default Value: 0
request_slowlog_timeout = 5s

; The log file for slow requests
; Default Value: not set
; Note: slowlog is mandatory if request_slowlog_timeout is set
; /proc/1/fd/2 means docker main stream - show in docker logs output stderr
slowlog = /proc/1/fd/2

nginx config

location = /status {
  access_log off;
  allow 127.0.0.1;
  allow 1.2.3.4 #your-ip;
  deny all;
  fastcgi_pass                      unix:/var/run/php_fpm_app.sock;
  # or
  #  fastcgi_pass 127.0.0.1:9000;

  include fastcgi_params;

  # very important
  fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

do request:

curl http://localhost:80/status?full
curl 'http://localhost:80/status?json&full'

pool:                 app
process manager:      dynamic
start time:           20/Dec/2025:19:29:11 +0000
start since:          540
accepted conn:        24
listen queue:         0
max listen queue:     0
listen queue len:     0
idle processes:       8
active processes:     1
total processes:      9
max active processes: 2
max children reached: 0
slow requests:        0

************************
pid:                  265
state:                Idle
start time:           20/Dec/2025:19:29:11 +0000
start since:          540
requests:             3
request duration:     130540
request method:       GET
request URI:          /index.php?_url=/v1/notifications/unread/count
content length:       0
user:                 -
script:               /var/www/current/public/index.php
last request cpu:     76.60
last request memory:  8388608
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment