php-fpm详解(转过来给对fpm接触不深的朋友加深基础)

zh7314

2022年9月27日15:45:04

FastCGI(Fast Common Gateway Interface)快速通用网关接口,是 CGI 的增强版本,为了提升 CGI 的性能而生。
PHP-FPM(FastCGI Process Manager for PHP)PHP 的 FastCGI 进程管理器。FastCGI 只是一个协议规范,需要某个程序去具体实现,而 PHP-FPM 就是这个具体实现。

ps -ef|grep php

root       2178      1  0 13:28 ?        00:00:00 php-fpm: master process (/usr/local/php80/etc/php-fpm.conf)
www        2179   2178  0 13:28 ?        00:00:00 php-fpm: pool www
www        2180   2178  0 13:28 ?        00:00:00 php-fpm: pool www
root       2248      1  0 13:29 ?        00:00:00 php-fpm: master process (/usr/local/php74/etc/php-fpm.conf)
www        2250   2248  0 13:29 ?        00:00:00 php-fpm: pool www
www        2251   2248  0 13:29 ?        00:00:00 php-fpm: pool www

这里可以看到fpm是一个常驻内存的master -> worker的多进程工作模式

fpm是一个php的工作方式,请注意!

PHP的SAPI模块 方式目前有以下几种:
  1. CGI(通用网关接口/ Common Gateway Interface)
  2. FastCGI(常驻型CGI / Long-Live CGI)
  3. CLI(命令行运行 / Command Line Interface)
  4. Web模块模式(Apache等Web服务器运行的模式)
  5. ISAPI(Internet Server Application Program Interface)
  6. LSAPI

强调一下,工作模式和php语言本身实现任何功能基本毫无影响,以上都是通过通信协议互相通信而已

https://www.php.net/manual/zh/function.php-sapi-name.php
返回接口类型的小写字符串, 或者在失败时返回 false。

对应的fpm代码的如下:

D:\SRC_CODE\20220824\PHP-SRC_1\SAPI
├─apache2handler
├─cgi
│  └─tests
├─cli
│  └─tests
├─embed
├─fpm
│  ├─fpm
│  │  └─events
│  └─tests
├─fuzzer
│  ├─corpus
│  │  ├─exif
│  │  ├─json
│  │  └─unserialize
│  └─dict
├─litespeed
└─phpdbg
    └─tests
        └─bug73615

fpm自身是什么呢?

PS D:\src_code\20220824\php-src_1\sapi\fpm\fpm\events> ls
    目录: D:\src_code\20220824\php-src_1\sapi\fpm\fpm\events

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         2022/9/28     14:04           5872 devpoll.c
-a----         2022/9/28     14:04           1228 devpoll.h
-a----         2022/9/28     14:04           5192 epoll.c
-a----         2022/9/28     14:04           1220 epoll.h
-a----         2022/9/28     14:04           4876 kqueue.c
-a----         2022/9/28     14:04           1224 kqueue.h
-a----         2022/9/28     14:04           6465 poll.c
-a----         2022/9/28     14:04           1216 poll.h
-a----         2022/9/28     14:04           4931 port.c
-a----         2022/9/28     14:04           1216 port.h
-a----         2022/9/28     14:04           4187 select.c
-a----         2022/9/28     14:04           1224 select.h

PS D:\src_code\20220824\php-src_1\sapi\fpm\fpm> ls
    目录: D:\src_code\20220824\php-src_1\sapi\fpm\fpm

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----         2022/9/28     14:04                events
-a----         2022/9/28     14:04           2966 fpm.c
-a----         2022/9/28     14:04           1160 fpm.h
-a----         2022/9/28     14:04           1951 fpm_arrays.h
-a----         2022/9/28     14:04           4127 fpm_atomic.h
-a----         2022/9/28     14:04          12090 fpm_children.c
-a----         2022/9/28     14:04            901 fpm_children.h
........省略

fpm是c实现了epoll kqueue poll select的event,的master worker的进程管理器,照理来说不会慢,才对

为什么大多数会认为fpm会慢,吃内存呢?

参考:https://www.workerman.net/doc/webman/others/performance.html

  1. php-fpm请求开始初始化一切,请求结束销毁一切的开销
  2. php-fpm每次请求从磁盘读取多个php文件,反复词法语法解析、反复编译成opcode开销
  3. 框架反复创建框架相关类实例及初始化的开销
  4. 框架反复连接断开数据库、redis等开销
  5. nginx/apache自身开销以及与php-fpm通讯开销
  6. fpm是常驻类型,为什么维持worker的运行数量,不会归还内存给系统

其实主要是因为composer的出现,导致框架的vendor越来越庞大,一个简单laravel web项目vendor

[root@ vendor]# ls -lR| grep "^-" | wc -l
7066
[root@ vendor]# du -sh
57M

每次启动就需要加载57M大小的7K+的文件,消耗很多磁盘IO和创建框架实例,消耗巨大
就导致laravel这么“重”的框架,访问速度就很慢

有什么解决办法呢?
开启opcache
ops性能提升至少5-10倍左右,可以看下你的php.ini是否开启(api请求,混编的页面性能提升更小)
php -m
是否包含Zend OPcache

设置pm.max_requests=0,就是不归还,你可以把这个设置成pm.max_requests=50,就请求了50个之后,就释放内存给系统
如果max_requests太小,就会不停的请求内存,释放内存性能有影响
设置成0,就会不释放内存,造成系统工作内存资源太小,导致系统越来越卡

如何设置合理的配置呢?
1,pm = dynamic,这样由fpm自己调整
2,需要更高性能的ops,根据自己大小简单计算一下,比如4核8G内存,8G至少留1g给系统,php单个变量大小是128M,以此为最大基准,(7*1024)/128 = 56,这里是纯fpm的机器,不包含nginx redis等服务,如果在同一个服务器就扣除其他运行内存

pm = static
pm.max_children = 56
pm.start_servers = 20
pm.max_requests = 200

这里全部是理论数值

cat /proc/1197/status
cat /proc/$(pid)/status

查看

VmPeak:   247844 kB
VmSize:   234784 kB ——进程占用的虚拟内存大小
VmLck:         0 kB
VmPin:         0 kB
VmHWM:     34296 kB
VmRSS:     21660 kB ——占用的物理内存 约21M

通常一个fpm的工作内存是几十M,上诉的设置是很宽松的,但是设置过多的children数量会受cpu的影响,频繁切换cpu上下文的去执行会造成一些性能影响,可以通过观察服务器的访问量,服务器内存和cpu的使用量去了解最适合你业务系统的配置,需要一个过程。

比如你的业务系统查询多,或者计算多,或者业务系统不同会对fpm设置都会需要微调

那么避免上述的所有的问题,开发一个常驻内存,不需要频繁加载文件,一个master worker的和其他组件通信可以是常驻内存连接
的框架,那么php的性能是不是可以有非常大的提升,答案是:完全可以

一个完全由php开发的常驻内存的mvc框架 基于workerman的webman就是一个很强大的php高性能框架,完美的避开了fpm的缺点

FastCGI的通信协议:

nginx和fpm通信协议是FastCGI,fpm有两种对接模式,端口和sock

location ~ \.php(.*)$ {
            fastcgi_pass   unix:/usr/local/php80/php-fpm.sock;
            #fastcgi_pass   127.0.0.1:9001;
            fastcgi_index  index.php;
            fastcgi_split_path_info  ^((?U).+\.php)(/?.+)$;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            fastcgi_param  PATH_INFO  $fastcgi_path_info;
            fastcgi_param  PATH_TRANSLATED  $document_root$fastcgi_path_info;
            include        fastcgi_params;
        }

如果可以使用sock性能当然是更好的,但是nginx和fpm是分离的监听端口模式会更好一点,因为安全也是一个很大的因素

workerman也实现了FastCGI协议

php实现fastcgi
https://github.com/lisachenko/protocol-fcgi
nginx对接fastcgi
https://www.nginx.com/resources/wiki/start/topics/examples/phpfcgi/
FastCGI协议标准
https://www.infoq.cn/article/vicwtitzvk7b4ynoej3e

https://www.mit.edu/~yandros/doc/specs/fcgi-spec.html
https://www.myway5.com/index.php/2018/07/19/fastcgi-%E8%A7%84%E8%8C%83%E4%B8%AD%E6%96%87%E7%BF%BB%E8%AF%91/
https://www.imooc.com/article/details/id/45163
源码
https://github.com/php/php-src/blob/master/main/fastcgi.c

如果你想对fastcgi有更多的了解
https://www.leavesongs.com/PENETRATION/fastcgi-and-php-fpm.html
你就会发现,nginx想的配置文件 fastcgi.conf fastcgi_params里面参数的意思

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  REQUEST_SCHEME     $scheme;
fastcgi_param  HTTPS              $https if_not_empty;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;

剩下就是最重要的配置文件,下面是基于php8.0的中文翻译版
php-fpm.conf

;;;;;;;;;;;;;;;;;;;;;
; FPM 配置 ;
;;;;;;;;;;;;;;;;;;;;;

; 此配置文件中的所有相对路径都是相对于 PHP 的安装
; 前缀 (/usr/local/php80)。 这个前缀可以通过使用
; 命令行中的“-p”参数。

;;;;;;;;;;;;;;;;;;
; 全局 选项 ;
;;;;;;;;;;;;;;;;;;

[global]
; pid文件
; 注意:默认前缀是 /usr/local/php80/var
; 默认值:无
;pid = 运行/php-fpm.pid

pid = /usr/local/php80/php-fpm.pid

; 错误日志文件
; 如果它设置为“syslog”,日志将被发送到 syslogd 而不是被写入
; 到本地文件中。
; 注意:默认前缀是 /usr/local/php80/var
; 默认值:log/php-fpm.log
;error_log = log/php-fpm.log

error_log = /data/log/php80/php-fpm.log

; syslog_facility 用于指定什么类型的程序正在记录
; 信息。 这让 syslogd 指定来自不同设施的消息
; 会以不同方式处理。
; 请参阅 syslog(3) 以获取可能的值(例如 daemon equiv LOG_DAEMON)
; 默认值:daemon
;syslog.facility = daemon

; syslog_ident 附加在每条消息之前。 如果您有多个 FPM
; 在同一台服务器上运行的实例,您可以更改默认值
; 这必须满足共同的需求。
; 默认值:php-fpm
;syslog.ident = php-fpm

; 日志级别
; 可能的值:alert, error, warning, notice, debug
; 默认值: notice
;log_level = notice

; 单行中字符数的日志限制(日志条目)。 如果
; 行超过限制,它被包裹在多行上。 限制是为了
; 所有记录的字符,包括消息前缀和后缀(如果存在)。 然而
; 换行符不计入其中,因为它仅在
; 记录到文件描述符。 这意味着新行字符不存在
; 登录到系统日志时。
; 默认值: 1024
;log_limit = 4096

; 日志缓冲指定日志行是否被缓冲,这意味着
; 行在单个写入操作中写入。 如果该值为 false,则
; 数据直接写入文件描述符。 这是一个实验
; 可以潜在地提高日志记录性能和内存使用的选项
; 对于一些繁重的日志记录场景。 如果记录到 syslog,则忽略此选项
; 因为它必须始终被缓冲。
; 默认值: yes
;log_buffering = no

; 如果此数量的子进程在此时间内以 SIGSEGV 或 SIGBUS 退出
; 由 Emergency_restart_interval 设置的时间间隔,然后 FPM 将重新启动。 一个值
; “0”表示“关闭”。
; 默认值: 0
;emergency_restart_threshold = 0

; Emergency_restart_interval 使用的时间间隔来确定何时
; 将启动正常重启。 这对于解决问题很有用
; 加速器共享内存中的意外损坏。
; 可用单位:s(秒)、m(整数)、h(我们的)或 d(ays)
; 默认单位:秒
; 默认值: 0
;emergency_restart_interval = 0

; 子进程等待主进程对信号做出反应的时间限制。
; 可用单位:s(秒)、m(整数)、h(我们的)或 d(ays)
; 默认单位:秒
; 默认值:0
;process_control_timeout = 0

; FPM 将分叉的最大进程数。 这是为了控制
; 在许多池中使用动态 PM 时的全局进程数。
; 谨慎使用。
; 注意:值为 0 表示没有限制
; 默认值:0
; process.max = 128

; 指定 nice(2) 优先级以应用于主进程(仅当设置时)
; 该值可以从 -19(最高优先级)到 20(最低优先级)变化
; 注意: - 仅当 FPM 主进程以 root 身份启动时才有效
; - 池进程将继承主进程优先级
; 除非另有说明
; 默认值: no set
; process.priority = -19

; 将 FPM 发送到后台。 设置为“否”以将 FPM 保持在前台进行调试。
; 默认值: yes
;daemonize = yes

; 为主进程设置打开文件描述符 rlimit。
; 默认值: system defined value
;rlimit_files = 1024

; 为主进程设置最大核心大小 rlimit。
; 可能的值:“无限”或大于或等于 0 的整数
; 默认值: system defined value
;rlimit_core = 0

; 指定 FPM 将使用的事件机制。 以下是可用的:
; - select     (any POSIX os)
; - poll       (any POSIX os)
; - epoll      (linux >= 2.5.44)
; - kqueue     (FreeBSD >= 4.1, OpenBSD >= 2.9, NetBSD >= 2.0)
; - /dev/poll  (Solaris >= 7)
; - port       (Solaris >= 10)
; Default Value: not set (auto detection)
;events.mechanism = epoll

; 当 FPM 使用 systemd 集成构建时,指定间隔,
; 在几秒钟内,在向 systemd 的健康报告通知之间。
; 设置为 0 以禁用。
; 可用单位:s(秒)、m(整数)、h(我们的)
; 默认单位:秒
; 默认值: 10
;systemd_interval = 10

;;;;;;;;;;;;;;;;;;;;
; 线程池定义        ;
;;;;;;;;;;;;;;;;;;;;

; 可以使用不同的侦听方式启动多个子进程池
; 端口和不同的管理选项。 池的名称将是
; 用于日志和统计信息。 池的数量没有限制
; FPM可以处理。 无论如何,您的系统会告诉您:)

; 包括一个或多个文件。 如果 glob(3) 存在,它用于包含一堆
; 来自 glob(3) 模式的文件。 该指令可以在任何地方使用
; 文件。
; 也可以使用相对路径。 它们的前缀为:
; - 全局前缀(如果已设置)(-p 参数)
;  - /usr/local/php80 otherwise
include=/usr/local/php80/etc/php-fpm.d/*.conf

www.conf

; 启动一个名为“www”的新池。
; 变量 $pool 可以在任何指令中使用,并将被替换为
; 池名称(此处为“www”)
[www]

; 每个池前缀
; 它仅适用于以下指令:
; - 'access.log'
; - 'slowlog'
; - 'listen' (unixsocket)
; - 'chroot'
; - 'chdir'
; - 'php_values'
; - 'php_admin_values'
; 如果未设置,则应用全局前缀(或 /usr/local/php80)。
; 注意:该指令也可以相对于全局前缀。
; 默认值: none
;prefix = /path/to/pools/$pool

; Unix 用户/进程组
; 注意:用户是强制性的。 如果未设置组,则默认用户的组
; 将会被使用。
user = www
group = www

; 接受 FastCGI 请求的地址。
; 有效的语法是:
; 'ip.add.re.ss:port' - 在 TCP 套接字上侦听特定 IPv4 地址
; 特定端口;
; '[ip:6:addr:ess]:port' - 在 TCP 套接字上监听特定 IPv6 地址
; 特定端口;
; 'port' - 在 TCP 套接字上侦听所有地址
; (IPv6 和 IPv4 映射)在特定端口上;
; '/path/to/unix/socket' - 监听 unix 套接字。
; 注意:此值是强制性的。
;listen = 127.0.0.1:9000

listen = /usr/local/php80/php-fpm.sock

; 设置listen(2) 积压的任务。
; 默认值:511(FreeBSD 和 OpenBSD 上为 -1)
;listen.backlog = 511

; 设置 unix 套接字的权限,如果使用的话。 在 Linux 中,读/写
; 必须设置权限才能允许来自 Web 服务器的连接。 许多
; BSD 派生系统允许连接而不管权限。 主人
; 和组可以通过名称或它们的数字 ID 来指定。
; 默认值:用户和组设置为运行用户
; 模式设置为 0660

listen.owner = www
listen.group = www
listen.mode = 0660

; 当支持 POSIX 访问控制列表时,您可以使用
; 在这些选项中,value 是用户/组名称的逗号分隔列表。
; 设置后,listen.owner 和 listen.group 将被忽略
;listen.acl_users =
;listen.acl_groups =

; 允许连接的 FastCGI 客户端的地址列表(IPv4/IPv6)。
; 相当于原来的FCGI_WEB_SERVER_ADDRS环境变量
; PHP FCGI (5.2.2+)。 仅对 tcp 侦听套接字才有意义。 每个地址
; 必须用逗号分隔。 如果此值留空,则连接将是
; 从任何 IP 地址接受。
; 默认值: any
;listen.allowed_clients = 127.0.0.1

; 指定 nice(2) 优先级以应用于池进程(仅当设置时)
; 该值可以从 -19(最高优先级)到 20(较低优先级)变化
; 注意: - 仅当 FPM 主进程以 root 身份启动时才有效
; - 池进程将继承主进程优先级
; 除非另有说明
; 默认值: no set
; process.priority = -19

; 设置进程可转储标志 (PR_SET_DUMPABLE prctl) 即使进程用户
; 或组不同于主进程用户。 它允许创建进程
; 池用户的核心转储和 ptrace 进程。
; 默认值: no
; process.dumpable = yes

;选择进程管理器将如何控制子进程的数量。
;可能的值:
;   static  - 固定数量(pm.max_children)的子进程;
;   dynamic - 子进程的数量是根据以下指令动态设置的。 使用此流程管理,将始终至少有 
;             1 个子进程。
;             pm.max_children      - 可以同时存活的子进程的最大数量
;             pm.start_servers     - 启动子进程的数量.
;             pm.min_spare_servers - 处于“空闲”状态(等待处理)的最小孩子数。 ;  
;                           如果 “空闲”进程的数量少于此数量,则将创建一些子进程。
;             pm.max_spare_servers - 处于“空闲”状态的最大子节点数(等待处理)。 
;                       如果“空闲”进程的数量大于这个数量,那么一些子进程将被杀死。
;  ondemand - 启动时不创建子级。当新请求连接时,子进程才会被forked创建.使用以下参数:
;             pm.max_children           - 可以同时活着的子进程的最大数量。
;             pm.process_idle_timeout   - 空闲进程将被终止的秒数。
;注意:此值是强制性的。
pm = dynamic

; 当 pm 设置为 'static' 和
; pm 设置为“动态”或“按需”时的最大子进程数。
; 此值设置将同时请求的数量限制
; 服务。 等效于带有 mpm_prefork 的 ApacheMaxClients 指令。
; 等效于原始 PHP 中的 PHP_FCGI_CHILDREN 环境变量
; 电脑动画。 以下默认值基于没有太多资源的服务器。 别
; 忘记调整 pm.* 以满足您的需求。
; 注意:当 pm 设置为“静态”、“动态”或“按需”时使用
; 注意:此值是强制性的。
pm.max_children = 20

; 启动时创建的子进程数。
; 注意:仅在 pm 设置为“动态”时使用
; 默认值:(min_spare_servers + max_spare_servers) / 2
pm.start_servers = 2

; 所需的最小空闲服务器进程数。
; 注意:仅在 pm 设置为“动态”时使用
; 注意:当 pm 设置为“动态”时为必填项
pm.min_spare_servers = 1

; 所需的最大空闲服务器进程数。
; 注意:仅在 pm 设置为“动态”时使用
; 注意:当 pm 设置为“动态”时为必填项
pm.max_spare_servers = 3

; 空闲进程将被杀死的秒数。
; 注意:仅在 pm 设置为 'ondemand' 时使用
; 默认值: 10s
;pm.process_idle_timeout = 10s;

; 每个子进程在重生之前应执行的请求数。
; 这对于解决 3rd 方库中的内存泄漏问题很有用。 为了
; 无休止的请求处理指定“0”。 等效于 PHP_FCGI_MAX_REQUESTS。
; 默认值: 0
pm.max_requests = 200

; 查看 FPM 状态页面的 URI。 如果未设置此值,则不会有 URI
; 识别为状态页面。 它显示以下信息:
;   pool                 - 池的名称
;   process manager      - static, dynamic or ondemand;
;   start time           - FPM 开始的日期和时间;
;   start since          - 自 FPM 开始以来的秒数;
;   accepted conn        - 池接受的请求数;
;   listen queue         - 待处理队列中的请求数 连接(参见listen(2)中的积压任务);
;   max listen queue     - 自 FPM 启动以来,待处理连接队列中的最大请求数
;   listen queue len     - 挂起连接的套接字队列的大小;
;   idle processes       - 空闲进程的数量;
;   active processes     - 活动进程的数量;
;   total processes      - 空闲+活动进程的数量;
;   max active processes - 自 FPM 启动以来的最大活动进程数;
;   max children reached - 当 pm 尝试启动更多子进程时,已达到进程限制的次数(仅适用于
;                            pm 'dynamic' 和 'ondemand');
; 值实时更新。
; Example output:
;   pool:                 www
;   process manager:      static
;   start time:           01/Jul/2011:17:53:49 +0200
;   start since:          62636
;   accepted conn:        190460
;   listen queue:         0
;   max listen queue:     1
;   listen queue len:     42
;   idle processes:       4
;   active processes:     11
;   total processes:      15
;   max active processes: 12
;   max children reached: 0
;
; 默认情况下,状态页面输出格式为 text/plain。 通过任一
; 查询字符串中的'html'、'xml'或'json'会返回对应的
; output syntax. Example:
;   http://www.foo.bar/status
;   http://www.foo.bar/status?json
;   http://www.foo.bar/status?html
;   http://www.foo.bar/status?xml
;
; 默认情况下,状态页面只输出简短的状态。 传递“完整”
; 查询字符串还将返回每个池进程的状态。
; Example:
;   http://www.foo.bar/status?full
;   http://www.foo.bar/status?json&full
;   http://www.foo.bar/status?html&full
;   http://www.foo.bar/status?xml&full
; 每个进程的完整状态返回:
;   pid                  - 进程的PID;
;   state                - 进程的状态(空闲,运行,...);
;   start time           - 流程开始的日期和时间;
;   start since          - 自进程开始以来的秒数;
;   requests             - 进程已处理的请求数;
;   request duration     - 请求的持续时间(以 µs 为单位);
;   request method       - 请求方法(GET,POST,...);
;   request URI          - 带有查询字符串的请求 URI;
;   content length       - 请求的内容长度(仅限 POST)
;   user                 - 用户(PHP_AUTH_USER)(如果未设置,则为“-”);
;   script               - 调用的主脚本(如果未设置,则为“-”);
;   last request cpu     - 如果进程未处于空闲状态,则最后一个请求消耗的 %cpu 始终为 0,
;                           因为 CPU 计算是在请求处理终止时完成的;
;   last request memory  - 最后一个请求消耗的最大内存量,如果进程不处于空闲状态,
;                           则它始终为 0,因为在请求处理终止时完成了内存计算;
; 如果进程处于空闲状态,则信息与
; 进程服务的最后一个请求。 否则信息与
; 当前正在处理的请求。
; Example output:
;   ************************
;   pid:                  31330
;   state:                Running
;   start time:           01/Jul/2011:17:53:49 +0200
;   start since:          63087
;   requests:             12808
;   request duration:     1250261
;   request method:       GET
;   request URI:          /test_mem.php?N=10000
;   content length:       0
;   user:                 -
;   script:               /home/fat/web/docs/php/test_mem.php
;   last request cpu:     0.00
;   last request memory:  0
;
; 注意:有一个实时 FPM 状态监控示例网页可用
; 它位于:/usr/local/php80/share/php/fpm/status.html
;
; 注意:该值必须以斜杠 (/) 开头。 该值可以是
; 任何东西,但使用 .php 扩展名或它可能不是一个好主意
; 可能与真实的 PHP 文件冲突。
; 默认值: not set
;pm.status_path = /status

; 接受 FastCGI 状态请求的地址。 这创造了一个新的
; 可以独立处理请求的隐形池。 这很有用
; 如果主池忙于长时间运行的请求,因为它仍然可能
; 在完成长时间运行的请求之前获取状态。
;
; 有效的语法是:
;   'ip.add.re.ss:port'    - 在 TCP 套接字上侦听特定端口上的特定 IPv4 地址;
;   '[ip:6:addr:ess]:port' - 在 TCP 套接字上侦听特定端口上的特定 IPv6 地址;
;   'port'                 - 在 TCP 套接字上侦听特定端口上的所有地址(IPv6和IPv4 映射);
;   '/path/to/unix/socket' - 在 Unix 套接字上监听。
; 默认值: value of the listen option
;pm.status_listen = 127.0.0.1:9001

; 调用FPM监控页面的ping URI。 如果未设置此值,则否
; URI 将被识别为 ping 页面。 这可以用来从外部测试
; FPM 是活跃的并且正在响应,或者
; - 创建 FPM 可用性图表(rrd 等);
; - 如果服务器没有响应(负载平衡),则从组中删除它;
; - 为运营团队触发警报 (24/7)。
; 注意:该值必须以斜杠 (/) 开头。 该值可以是
; 任何东西,但使用 .php 扩展名或它可能不是一个好主意
; 可能与真实的 PHP 文件冲突。
; 默认值: not set
;ping.path = /ping

; 该指令可用于自定义 ping 请求的响应。 这
; 响应格式为文本/纯文本,响应代码为 200。
; 默认值: pong
;ping.response = pong

; 访问日志文件
; Default: not set
;access.log = log/$pool.access.log

; 访问日志格式。
; 允许使用以下语法
;  %%: the '%' character
;  %C: %CPU used by the request
;      it can accept the following format:
;      - %{user}C for user CPU only
;      - %{system}C for system CPU only
;      - %{total}C  for user + system CPU (default)
;  %d: time taken to serve the request
;      it can accept the following format:
;      - %{seconds}d (default)
;      - %{milliseconds}d
;      - %{mili}d
;      - %{microseconds}d
;      - %{micro}d
;  %e: an environment variable (same as $_ENV or $_SERVER)
;      it must be associated with embraces to specify the name of the env
;      variable. Some examples:
;      - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e
;      - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e
;  %f: script filename
;  %l: content-length of the request (for POST request only)
;  %m: request method
;  %M: peak of memory allocated by PHP
;      it can accept the following format:
;      - %{bytes}M (default)
;      - %{kilobytes}M
;      - %{kilo}M
;      - %{megabytes}M
;      - %{mega}M
;  %n: pool name
;  %o: output header
;      it must be associated with embraces to specify the name of the header:
;      - %{Content-Type}o
;      - %{X-Powered-By}o
;      - %{Transfert-Encoding}o
;      - ....
;  %p: PID of the child that serviced the request
;  %P: PID of the parent of the child that serviced the request
;  %q: the query string
;  %Q: the '?' character if query string exists
;  %r: the request URI (without the query string, see %q and %Q)
;  %R: remote IP address
;  %s: status (response code)
;  %t: server time the request was received
;      it can accept a strftime(3) format:
;      %d/%b/%Y:%H:%M:%S %z (default)
;      The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag
;      e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t
;  %T: time the log has been written (the request has finished)
;      it can accept a strftime(3) format:
;      %d/%b/%Y:%H:%M:%S %z (default)
;      The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag
;      e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t
;  %u: remote user
;
; Default: "%R - %u %t \"%m %r\" %s"
;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"

; 慢请求的日志文件
; 默认值:未设置
; 注意:如果设置了 request_slowlog_timeout,slowlog 是强制性的
;slowlog = log/$pool.log.slow

slowlog = /data/log/php80/slow.log

; 服务单个请求的超时时间,之后 PHP 回溯将是
; 转储到“慢日志”文件。 值“0s”表示“关闭”。
; 可用单位:s(econds)(默认)、m(inutes)、h(ours) 或 d(ays)
; 默认值: 0
;request_slowlog_timeout = 0

; 慢日志堆栈跟踪的深度。
; 默认值: 20
;request_slowlog_trace_depth = 20

; 服务单个请求的超时时间,之后工作进程将
; 被杀。 当 'max_execution_time' ini 选项时应使用此选项
; 由于某种原因不会停止脚本执行。 值“0”表示“关闭”。
; 可用单位:s(econds)(默认)、m(inutes)、h(ours) 或 d(ays)
; 默认值: 0
;request_terminate_timeout = 0

; 'request_terminate_timeout' ini 选项设置的超时后未使用
; 应用程序调用“fastcgi_finish_request”或应用程序完成时
; 正在调用关闭函数(通过 register_shutdown_function 注册)。
; 此选项将启用无条件应用超时限制
; 即使在这种情况下。
; 默认值: no
;request_terminate_timeout_track_finished = no

; 设置打开文件描述符 rlimit。
; 默认值: system defined value
;rlimit_files = 1024

; 设置最大核心尺寸 rlimit。
; 可能的值:“无限”或大于或等于 0 的整数
; 默认值: system defined value
;rlimit_core = 0

; chroot 到这个目录开始。 该值必须定义为
; 绝对路径。 如果未设置此值,则不使用 chroot。
; 注意:您可以使用 '$prefix' 作为前缀来 chroot 到池前缀或一个
; 的子目录。 如果未设置池前缀,则使用全局前缀
; 将被使用。
; 注意:chrooting 是一个很好的安全功能,应该在任何时候使用
; 可能的。 但是,所有 PHP 路径都将相对于 chroot
; (error_log,sessions.save_path,...)。
; 默认值: not set
;chroot =

; chdir 到这个目录开始。
; 注意:可以使用相对路径。
; 默认值: current directory or / when chroot
;chdir = /var/www

; 将工作人员标准输出和标准错误重定向到主错误日志。 如果未设置,stdout 和
; 根据 FastCGI 规范,stderr 将被重定向到 /dev/null。
; 注意:在高负载环境下,这可能会导致页面延迟
; 处理时间(几毫秒)。
; 默认值: no
;catch_workers_output = yes

; 使用包含有关信息的前缀和后缀装饰工作人员输出
; 写入日志的孩子以及是否使用了 stdout 或 stderr
; 日志级别和时间。 仅当 catch_workers_output 为 yes 时才使用此选项。
; 设置为“no”将输出写入 stdout 或 stderr 的数据。
; 默认值: yes
;decorate_workers_output = no

; FPM 工作人员的清晰环境
; 防止任意环境变量到达 FPM 工作进程
; 通过在此指定的环境变量之前清除工作人员中的环境
; 添加池配置。
; 设置为“no”将使所有环境变量都可用于 PHP 代码
; 通过 getenv()、$_ENV 和 $_SERVER。
; 默认值: yes
;clear_env = no

; 限制 FPM 允许解析的主脚本的扩展。 这个可以
; 防止Web服务器端的配置错误。 你应该只限制
; FPM转.php扩展名,防止恶意用户使用其他扩展名
; 执行php代码。
; 注意:设置一个空值以允许所有扩展。
; 默认值: .php
;security.limit_extensions = .php .php3 .php4 .php5 .php7

; 传递环境变量,如 LD_LIBRARY_PATH。 所有 $VARIABLEs 都取自
; 当前环境。
; 默认值: clean env
;env[HOSTNAME] = $HOSTNAME
;env[PATH] = /usr/local/bin:/usr/bin:/bin
;env[TMP] = /tmp
;env[TMPDIR] = /tmp
;env[TEMP] = /tmp

; 附加的 php.ini 定义,特定于这个工人池。 这些设置
; 覆盖之前在 php.ini 中定义的值。 这些指令是
; 与 PHP SAPI 相同:
;   php_value/php_flag       - 您可以设置可以从 PHP 调用 'ini_set' 覆盖的经典 ini 定义。
;   php_admin_value/php_admin_flag - 这些指令不会被 PHP 调用 'ini_set' 覆盖
; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no.

; 定义“扩展”将加载相应的共享扩展
; 扩展目录。 定义 'disable_functions' 或 'disable_classes' 不会
; 覆盖以前定义的 php.ini 值,但会附加新值
; 反而。

; 注意:路径 INI 选项可以是相对的,并且将使用前缀进行扩展
; (pool, global or /usr/local/php80)

; 默认值:除了 php.ini 和
; 在启动时使用 -d 参数指定
;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com
;php_flag[display_errors] = off
;php_admin_value[error_log] = /var/log/fpm-php.www.log
;php_admin_flag[log_errors] = on
;php_admin_value[memory_limit] = 32M

最后谈几点关于配置fpm的线程池的问题:

  1. pm的配置模式是 static dynamic ondemand哪个最好,是根据你的业务模式需求来定,你可以通过fpm的slowlog,access.log /status 来判断那种适合你的业务系统,比如查询多的业务,需要大量计算,比如需要很多其他组件通信有延迟的,各种各样的业务,通过不断尝试选择最适合自己的
  2. 有没有最优解? 没有最优解,只能建议:static适合大并发,整体请求平稳的,dynamic适合请求变化大,但是总体请求并不大,ondemand适合对fpm并不清楚怎么配置,最简单
  3. fpm配合opcache使用性能并不差,慢的原因多半是因为框架本身很重,多使用缓存来提供热数据查询,不要频繁直接把请求打到数据层,写入才做保证原子性操作尽量少使用锁,多用事务,频繁使用锁会造成数据库的阻塞,数据库的返回越慢,也会拖慢fpm的返回,因为php的大部分请求都是阻塞的,当然现在也有很多异步非阻塞的框架。
    2022年10月12日15:12:39 补充几点
  4. 并不是worker线程开的越多越好,要适当冗余硬件资源给系统,因为fpm没有做cpu亲和性,太多的执行worker线程,cpu要疯狂的切换cpu执行的上下文,一般8核16G内存,开200-220比较适合,建议最好开启max_requests,适当释放内存给系统,避免系统跑一段时间系统资源越来越少,变得卡顿,因为现在多数都是虚拟服务器,8核16G内存实际性能就损失了大约5%,如果你在同样配置的硬件机器和虚拟服务器性能测试,硬件服务器会比虚拟服务器性能好10%-20%,比如腾讯,阿里的服务器都存在这个问题,有时间可以做下压测就知道了,比如服务器分通用型 计算型 内存型大 数据型 GPU型 本地SSD型 高主频型 FPGA型 弹性裸金属型都是在婉转的告诉性能差距
2500 5 11
5个评论

PHP甩JAVA一条街

请问webman是什么原理呢?老大写的比较笼统

  • zh7314 2023-06-20

    本质和webman基本一样,但是workerman是基于php实现的,不需要在吧请求由fpm转给php执行,直接由nginx交给workerman

喵了个咪

绝对好文

  • 暂无评论
lcmg

厉害了

  • 暂无评论
初心by

  • 暂无评论
charlescc

这个很详细,好文。

  • 暂无评论

zh7314

790
积分
0
获赞数
0
粉丝数
2021-12-13 加入
×
🔝