本文概述
- 什么是php-fpm?
- 为什么要优化php-fpm?
- 如何优化PHP-FPM?
但是, 它并不是以其高性能而著称, 特别是在高度并发的系统中。这就是为什么在这样的特殊用例中, 诸如Node(是的, 我知道, 这不是一种语言), Go和Elixir之类的语言正在接管的原因。
也就是说, 你可以采取很多措施来改善服务器上的PHP性能。本文侧重于php-fpm方面, 如果你使用的是Nginx, 这是在服务器上进行配置的自然方法。
如果你知道php-fpm是什么, 请随时跳至优化部分。
什么是php-fpm? 很少有开发人员对DevOps方面感兴趣, 即使是在开发人员中, 也很少有人知道幕后的情况。有趣的是, 当浏览器向运行PHP的服务器发送请求时, 不是PHP构成了第一个联系点。而是HTTP服务器, 其中主要的是Apache和Nginx。然后, 这些” Web服务器” 必须决定如何连接到PHP, 并将请求类型, 数据和标头传递给它。
文章图片
在PHP的情况下, 请求-响应周期(图片来源:ProinerTech)
在现代PHP应用程序中, 上面的” 查找文件” 部分是index.php, 该服务器配置为将所有请求委派给该文件。
现在, Web服务器与PHP的连接方式已经发生了精确的演变, 如果我们要深入研究所有细节, 这篇文章的长度将激增。但粗略地说, 在Apache成为首选Web服务器的时期, PHP是服务器内部包含的模块。
因此, 每当收到请求时, 服务器就会启动一个新进程, 该进程将自动包含PHP, 并使其执行。该方法称为mod_php, 是” php as a module” 的缩写。这种方法有其局限性, Nginx用php-fpm克服了它。
在php-fpm中, 管理PHP的责任在于服务器内部的PHP程序。换句话说, 只要知道如何发送和接收数据, 网络服务器(在我们的例子中为Nginx)就不会在意PHP的位置及其加载方式。如果需要, 在这种情况下, 你可以将PHP视为本身的另一台服务器, 它管理传入请求的某些子PHP进程(因此, 我们将请求到达服务器, 该请求由服务器接收并传递到服务器— —太疯狂了!
如果你已经完成了Nginx的任何设置, 甚至只是将它们撬了进去, 就会遇到以下类似情况:
location ~ \.php$ {try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_paramSCRIPT_FILENAME $document_root$fastcgi_script_name;
}
我们感兴趣的行是:fastcgi_pass unix:/run/php/php7.2-fpm.sock ; , 它告诉Nginx通过名为php7.2-fpm.sock的套接字与PHP进程进行通信。因此, 对于每个传入的请求, Nginx都会通过该文件写入数据, 并在接收到输出后将其发送回浏览器。
再一次, 我必须强调, 这并不是所发生事情的最完整或最准确的描述, 但是对于大多数DevOps任务来说是完全准确的。
除此之外, 让我们回顾一下到目前为止所学到的东西:
- PHP不会直接接收浏览器发送的请求。像Nginx这样的Web服务器首先会拦截这些。
- Web服务器知道如何连接到PHP流程, 并将所有请求数据传递(将所有内容粘贴到PHP上)。
- PHP完成其职责后, 会将响应发送回Web服务器, 然后将其发送回客户端(在大多数情况下为浏览器)。
文章图片
PHP和Nginx如何一起工作(图片来源:DataDog)
到目前为止, 还不错, 但是现在出现了上百万美元的问题:PHP-FPM到底是什么?
PHP中的” FPM” 部分代表” Fast Process Manager” , 这只是一种很好的说法, 它表示在服务器上运行的PHP不是单个进程, 而是某些衍生, 控制和杀死的PHP进程。由该FPM流程经理关闭。 Web服务器就是将请求传递给该进程管理器。
PHP-FPM本身就是一个完整的兔子洞, 因此, 如果你愿意, 可以随时进行探索, 但是出于我们的目的, 可以做很多解释。 ????
为什么要优化php-fpm? 那么, 在一切正常的情况下, 为什么还要担心这种舞蹈呢?为什么不将事物保持原样。
具有讽刺意味的是, 这正是我为大多数用例提供的建议。如果你的设置运行良好且没有特殊的用例, 请使用默认设置。但是, 如果你希望扩展到一台机器之外, 那么从一台机器中挤出最大容量是必不可少的, 因为它可以将服务器费用减少一半(甚至更多!)。
要意识到的另一件事是, Nginx是为处理巨大的工作负载而构建的。它能够同时处理成千上万的连接, 但是如果你的PHP设置不一样, 那么你将浪费资源, 因为Nginx必须等待PHP完成当前过程并接受接下来, 最终否定Nginx所提供的任何优势!
因此, 让我们来看看尝试优化php-fpm时我们到底要更改什么。
如何优化PHP-FPM? php-fpm的配置文件位置在服务器上可能会有所不同, 因此你需要做一些研究才能找到它。如果在UNIX上, 则可以使用find命令。在我的Ubuntu上, 路径为/etc/php/7.2/fpm/php-fpm.conf。当然, 7.2是我正在运行的PHP版本。
该文件的前几行如下所示:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
FPM Configuration ;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
All relative paths in this configuration file are relative to PHP's install;
prefix (/usr). This prefix can be dynamically changed by using the;
'-p' argument from the command line.;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
Global Options ;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
[global];
Pid file;
Note: the default prefix is /var;
Default Value: nonepid = /run/php/php7.2-fpm.pid;
Error log file;
If it's set to "syslog", log is sent to syslogd instead of being written;
into a local file.;
Note: the default prefix is /var;
Default Value: log/php-fpm.logerror_log = /var/log/php7.2-fpm.log
一些事情应该立即显而易见:pid = /run/php/php7.2-fpm.pid行告诉我们哪个文件包含php-fpm进程的进程ID。
我们还看到/var/log/php7.2-fpm.log是php-fpm存储其日志的位置。
在此文件中, 再添加三个变量, 如下所示:
emergency_restart_threshold 10emergency_restart_interval 1mprocess_control_timeout 10s
前两个设置是谨慎的, 它们告诉php-fpm进程, 如果一分钟内有十个子进程失败, 则主php-fpm进程应自行重启。
这听起来可能不够健壮, 但是PHP是一个短暂的进程, 它确实会泄漏内存, 因此在发生高故障的情况下重新启动主进程可以解决很多问题。
第三个选项process_control_timeout告诉子进程在执行从父进程接收到的信号之前要等待这么长时间。例如, 当父进程发送KILL信号时, 如果子进程位于某个中间, 则此功能很有用。只需十秒钟, 他们就有更大的机会完成任务并优雅地退出。
令人惊讶的是, 这不是php-fpm配置的重点!这是因为php-fpm为处理网络请求而创建了一个新的进程池, 该池将具有单独的配置。在我的情况下, 池名称竟然是www, 而我要编辑的文件是/etc/php/7.2/fpm/pool.d/www.conf。
让我们看看这个文件的开头是什么:
;
Start a new pool named 'www'.;
the variable $pool can be used in any directive and will be replaced by the;
pool name ('www' here)[www];
Per pool prefix;
It only applies on the following directives:;
- 'access.log';
- 'slowlog';
- 'listen' (unixsocket);
- 'chroot';
- 'chdir';
- 'php_values';
- 'php_admin_values';
When not set, the global prefix (or /usr) applies instead.;
Note: This directive can also be relative to the global prefix.;
Default Value: none;
prefix = /path/to/pools/$pool;
Unix user/group of processes;
Note: The user is mandatory. If the group is not set, the default user's group;
will be used.user = www-datagroup = www-data
快速浏览以上代码片段的结尾, 可以解决为什么服务器进程以www-data的形式运行的困惑。如果在设置网站时遇到文件许可问题, 则可能已将目录的所有者或组更改为www-data, 从而使PHP进程能够写入日志文件和上传文档等。 。
最后, 我们得出问题的根源, 即流程管理器(pm)设置。通常, 你会看到默认值, 如下所示:
pm = dynamicpm.max_children = 5pm.start_servers = 3pm.min_spare_servers = 2pm.max_spare_servers = 4pm.max_requests = 200
那么, “ 动态” 在这里是什么意思?我认为官方文档可以最好地解释这一点(我的意思是, 该文件应该已经在你正在编辑的文件中, 但是为了防止万一没有被复制, 请在此处进行复制):
;
Choose how the process manager will control the number of child processes.;
Possible Values:;
static- a fixed number (pm.max_children) of child processes;
;
dynamic - the number of child processes are set dynamically based on the;
following directives. With this process management, there will be;
always at least 1 children.;
pm.max_children- the maximum number of children that can;
be alive at the same time.;
pm.start_servers- the number of children created on startup.;
pm.min_spare_servers - the minimum number of children in 'idle';
state (waiting to process). If the number;
of 'idle' processes is less than this;
number then some children will be created.;
pm.max_spare_servers - the maximum number of children in 'idle';
state (waiting to process). If the number;
of 'idle' processes is greater than this;
number then some children will be killed.;
ondemand - no children are created at startup. Children will be forked when;
new requests will connect. The following parameter are used:;
pm.max_children- the maximum number of children that;
can be alive at the same time.;
pm.process_idle_timeout- The number of seconds after which;
an idle process will be killed.;
Note: This value is mandatory.
因此, 我们看到存在三个可能的值:
- 静态的:无论如何, 都会保留一定数量的PHP进程。
- 动态的:我们可以指定在任何给定时间点php-fpm保持活动的最小和最大进程数。
- 按需:流程是按需创建和销毁的。
简而言之, 如果你的网站访问量很少, 那么” 动态” 设置通常会浪费资源。假设你将pm.min_spare_servers设置为3, 即使网站上没有流量, 也将创建并维护三个PHP进程。在这种情况下, “ 按需” 是一个更好的选择, 让系统决定何时启动新流程。
另一方面, 在这种情况下, 处理大量流量或必须快速响应的网站将受到惩罚。最好避免创建新的PHP流程, 使其成为池的一部分并进行监视, 这是额外的开销。
使用pm = static可以固定子进程的数量, 从而可以将最大的系统资源用于服务请求而不是管理PHP。如果你确实走这条路, 请注意它有其指导原则和陷阱。关于它的一篇相当密集但非常有用的文章在这里。
最后的话
由于有关网络性能的文章可能会引发战争或使人们感到困惑, 因此在结束本文之前, 我觉得需要讲几句话。性能调优既涉及系统知识, 也涉及猜测和技巧。
即使你完全了解所有php-fpm设置, 也无法保证成功。如果你对php-fpm的存在一无所知, 则无需浪费时间担心它。继续做你已经在做的事情并继续。
同时, 避免成为表演迷。是的, 你可以通过从头重新编译PHP并删除所有不需要的模块来获得更好的性能, 但是这种方法在生产环境中不够明智。优化某些内容的整个想法是查看你的需求是否与默认值不同(它们很少这样做!), 并根据需要进行较小的更改。
【优化PHP-FPM以实现高性能】如果你还没有准备好花时间优化PHP服务器, 那么你可以考虑利用诸如Kinsta之类的可靠平台来处理性能优化和安全性。
推荐阅读
- 如何使用Flood Element在实际浏览器中执行负载测试()
- 如何使用Google Lighthouse测试你的网站()
- API监测与趋势的重要性的7个原因
- 11种在线业务的综合监控工具
- 在15分钟内使用StackPath增强并保护你的网站
- 9个最佳的真实用户监控工具,可改善用户体验
- 8个Mac优化软件,可提供更好的性能和安全性
- 7个使你的网站快速加载的技巧
- Attempt to invoke virtual method 'void com.loopj.android.image.SmartImageView.setImageUrl(java.l