php与nginx如何通信,聊聊Nginx与php-fpm的通信机制

现在网站的搭建技术成本是非常非常的低了,很多系统都是现在的,常见的就是nginx和php,当然还有很多,只是nginx和php是我们在搭建网站的时候经常用到的程序系统,毕竟这两款程序系统都是免费开源的,搭建网站的成本低,很多同学也就不知道nginx和php的通信底层逻辑到底是怎么运行的,今天小编就来和大伙说道说道。

本篇文章带大家聊聊Nginx与php-fpm的通信机制,介绍一下两种通信方式的不同,看看Nginx 与 php-fpm 的结合要怎么配置,分析一下应用中如何选择通信方式,希望能够给大家提供帮助!

PHP-FPM介绍

CGI协议与FastCGI协议

每种动态语言(PHP,Python等)的代码文件需要通过对应的解析器才能被服务器识别,而CGI协议就是用来使解释器与服务器可以互相通信。PHP文件在服务器上的解析需要用到PHP解释器,再加上对应的CGI协议,从而使服务器可以解析到PHP文件。

由于CGI的机制是每处理一个请求需要fork一个CGI进程,请求结束再kill掉这个进程,在实际应用上比较浪费资源,于是就出现了CGI的改良版本FastCGI,FastCGI在请求处理完后,不会kill掉进程,而是继续处理多个请求,这样就大大提高了效率。

PHP-FPM是什么

PHP-FPM即PHP-FastCGIProcessManager,它是FastCGI的实现,并提供了进程管理的功能。进程包含master进程和worker进程两种;master进程只有一个,负责监听端口,接收来自服务器的请求,而worker进程则一般有多个(具体数量根据实际需要进行配置),每个进程内部都会嵌入一个PHP解释器,是代码真正执行的地方。

Nginx与php-fpm通信机制

当我们访问一个网站(如www.test.com)的时候,处理流程是这样的:

 www.test.com
        |
        |
      Nginx
        |
        |
路由到 www.test.com/index.php
        |
        |
加载 nginx 的 fast-cgi 模块
        |
        |
fast-cgi 监听 127.0.0.1:9000 地址
        |
        |
www.test.com/index.php 请求到达 127.0.0.1:9000
        |
        |
     等待处理...

Nginx 与 php-fpm 的结合

Linux 上,nginx 与 php-fpm 的通信有 tcp socket 和 unix socket 两种方式。

tcp socket 的优点是可以跨服务器,当 nginx 和 php-fpm 不在同一台机器上时,只能使用这种方式。

Unix socket 又叫 IPC(inter-process communication 进程间通信) socket,用于实现同一主机上的进程间通信,这种方式需要在 nginx配置文件中填写 php-fpm 的 socket 文件位置。

两种方式的数据传输过程如下图所示:

聊聊Nginx与php-fpm的通信机制
聊聊Nginx与php-fpm的通信机制

二者的不同:

由于 Unix socket 不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。所以其效率比 tcp socket 的方式要高,可减少不必要的 tcp 开销。不过,unix socket 高并发时不稳定,连接数爆发时,会产生大量的长时缓存,在没有面向连接协议的支撑下,大数据包可能会直接出错不返回异常。而 tcp 这样的面向连接的协议,可以更好的保证通信的正确性和完整性。

Nginx 与 php-fpm 结合只需要在各自的配置文件中做设置即可:

1) Nginx 中的配置

以 tcp socket通信为例

server {
    listen       80; #监听 80 端口,接收http请求
    server_name  www.test.com; #就是网站地址
    root /usr/local/etc/nginx/www/huxintong_admin; # 准备存放代码工程的路径
    #路由到网站根目录 www.test.com 时候的处理
    location / {
        index index.php; #跳转到 www.test.com/index.php
        autoindex on;
    }  
    #当请求网站下 php 文件的时候,反向代理到 php-fpm
    location ~ \.php$ {
        include /usr/local/etc/nginx/fastcgi.conf; #加载 nginx 的 fastcgi 模块
        fastcgi_intercept_errors on;
        fastcgi_pass   127.0.0.1:9000; # tcp 方式,php-fpm 监听的 IP 地址和端口
       # fasrcgi_pass /usr/run/php-fpm.sock # unix socket 连接方式
    }
}

2) php-fpm 的配置

listen = 127.0.0.1:9000
# 或者下面这样
listen = /var/run/php-fpm.sock

注意,在使用 unix socket 方式连接时,由于 socket 文件本质上是一个文件,存在权限控制的问题,所以需要注。

nginx 进程的权限与 php-fpm 的权限问题,不然会提示无权限访问。(在各自的配置文件里设置用户)

通过以上配置即可完成 php-fpm 与 nginx 的通信。

在应用中的选择

如果是在同一台服务器上运行的 nginx 和 php-fpm,且并发量不高(不超过1000),选择unix socket,以提高 nginx 和 php-fpm 的通信效率。
如果是面临高并发业务,则考虑选择使用更可靠的 tcp socket,以负载均衡、内核优化等运维手段维持效率。

若并发较高但仍想用 unix socket 时,可通过以下方式提高 unix socket 的稳定性。

1)将sock文件放在 /dev/shm 目录下,此目录下将 sock 文件放在内存里面,内存的读写更快。

2)提高 backlog

backlog 默认位 128,1024 这个值最好换算成自己正常的 QPS,配置如下。

nginx.conf 文件中

server {
        listen 80 default backlog = 1024;
       }

php-fpm.conf 文件中

listen.backlog = 1024

3)增加 sock 文件和 php-fpm 实例

在 /dev/shm 新建一个 sock 文件,在 nginx 中通过 upstream 模块将请求负载均衡到两个 sock 文件,并且将两个 sock 文件分别对应到两套 php-fpm 实例上。

nginx和php如何进行通信的

先来看一下搭建好PHP运行环境的Nginx配置文件。

非常重要的就是 fastcgi_pass 指令了,这个指令用于指定 fpm 进程监听的地址,Nginx 会把所有的 php 请求翻译成 fastcgi 请求之后再发送到这个地址。

聊聊Nginx与php-fpm的通信机制
聊聊Nginx与php-fpm的通信机制

看了上面的图,接下来我们开始深入Nginx与FastCGI协议

从上图的Nginx配置中可以注意到 fastcgi* 开头的一些配置,以及引入的 fastcgi.conf 文件。其实在fastcgi.conf中,也是一堆fastcgi*的配置项,只是这些配置项相对不常变,通常单独文件保管可以在多处引用。在这个配置文件中,我们新建了一个虚拟主机,监听在 80 端口,Web 根目录为 /data/wwwroot/default。然后我们通过 location 指令,将所有的以 .php 结尾的请求都交给 fastcgi 模块处理,从而把所有的 php 请求都交给了 fpm 处理,从而完成 Nginx 到 fpm 的闭环。

聊聊Nginx与php-fpm的通信机制
聊聊Nginx与php-fpm的通信机制

可以看到在fastcgi.conf中,有很多的fastcgi_param配置,结合nginx server配置中的fastcgi_pass、fastcgi_index,通常我们的同学已经能够想到Nginx与PHP之间打交道就是用的FastCGI,但再深问FastCGI是什么?它起到衔接Nginx、PHP的什么作用?慢慢了解

要说 Nginx 与 PHP 是如何协同工作的,首先得说 CGI (Common Gateway Interface) 和 FastCGI 这两个协议。

CGI 是 Web Server 与后台语言交互的协议,有了这个协议,开发者可以使用任何语言处理 Web Server 发来的请求,动态的生成内容。但 CGI 有一个致命的缺点,那就是每处理一个请求都需要 fork 一个全新的进程,随着 Web 的兴起,高并发越来越成为常态,这样低效的方式明显不能满足需求。就这样,FastCGI 诞生了,CGI 很快就退出了历史的舞台。FastCGI,顾名思义为更快的 CGI,它允许在一个进程内处理多个请求,而不是一个请求处理完毕就直接结束进程,性能上有了很大的提高。

至于 FPM (FastCGI Process Manager),它是 FastCGI 的实现,任何实现了 FastCGI 协议的 Web Server 都能够与之通信。

FPM 是一个 PHP 进程管理器,包含 master 进程和 worker 进程两种进程:master 进程只有一个,负责监听端口,接收来自 Web Server 的请求,而 worker 进程则一般有多个 (具体数量根据实际需要配置),每个进程内部都嵌入了一个 PHP 解释器,是 PHP 代码真正执行的地方,下图是我本机上 fpm 的进程情况,1一个 master 进程,好多个 worker 进程:

聊聊Nginx与php-fpm的通信机制
聊聊Nginx与php-fpm的通信机制

从FPM接收到请求,到处理完毕,其具体的流程如下:

FPM的master进程接收到请求

master进程根据配置指派特定的worker进程进行请求处理,如果没有可用进程,返回错误,这也是我们配合Nginx遇到502错误比较多的原因。

worker进程处理请求,如果超时,返回504错误

请求处理结束,返回结果

FPM从接收到处理请求的流程就是这样了,那么Nginx又是如何发送请求给fpm的呢?这就需要从Nginx层面来说明了。

我们知道,Nginx不仅仅是一个Web服务器,也是一个功能强大的Proxy服务器,除了进行http请求的代理,也可以进行许多其他协议请求的代理,包括本文与fpm相关的fastcgi协议。为了能够使Nginx理解fastcgi协议,Nginx提供了fastcgi模块来将http请求映射为对应的fastcgi请求。

Nginx+PHP的工程模式下,两位主角分工明确,Nginx负责承载HTTP请求的响应与返回,以及超时控制记录日志等HTTP相关的功能,而PHP则负责处理具体请求要做的业务逻辑,它们俩的这种合作模式也是常见的分层架构设计中的一种,在它们各有专注面的同时,FastCGI又很好的将两块衔接,保障上下游通信交互。

Nginx+php-fpm实现原理

Nginx本身不会对PHP进行解析,终端对PHP页面的请求将会被Nginx交给FastCGI进程监听的IP地址及端口,由php-fpm作为动态解析服务器处理,最后将处理结果再返回给nginx。其实,Nginx就是一个反向代理服务器。Nginx通过反向代理功能将动态请求转向后端php-fpm,从而实现对PHP的解析支持,这就是Nginx实现PHP动态解析的原理。

Nginx不支持对外部程序的直接调用或者解析,所有的外部程序(包括PHP)必须通过FastCGI接口来调用。FastCGI接口在Linux下是socket(这个socket可以是文件socket,也可以是ipsocket)。为了调用CGI程序,还需要一个FastCGI的wrapper(wrapper可以理解为用于启动另一个程序的程序),这个wrapper绑定在某个固定socket上,如端口或者文件socket。当Nginx将CGI请求发送给这个socket的时候,通过FastCGI接口,wrapper接收到请求,然后派生出一个新的线程,这个线程调用解释器或者外部程序处理脚本并读取返回数据;接着,wrapper再将返回的数据通过FastCGI接口,沿着固定的socket传递给Nginx;最后,Nginx将返回的数据发送给客户端。

Nginx简单配置

location ~ \.php$ {
root /data/wwwroot/default/nginx/html/;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/admin/web/nginx/html/$fastcgi_script_name;
include fastcgi_params;
}

FastCGI原理

FastCGI是一个运用于Http Server和动态脚本语言间通信的接口,多数流行的Http Server都支持FastCGI,包括Apache、Nginx和lighttpd等。同时,FastCGI也被许多脚本语言支持,其中就有PHP。

FastCGI接口方式采用C/S结构,可以将HttP服务器和脚本解析服务器分开,同时在脚本解析服务器上启动一个或者多个脚本解析守护进程。当HttP服务器每次遇到动态程序时,可以将其直接交付给FastCGI进程来执行,然后将得到的结果返回给客户端。这种方式可以让HttP服务器专一地处理静态请求或者将动态脚本服务器的结果返回给客户端,这在很大程度上提高了整个应用系统的性能。

当nginx接收到一个http请求时,通过配置文件找到对应的server。然后匹配server中的所有location,找到最匹配的。而在location中的命令会启动不同的模块去完成工作,比如rewrite模块、index模块。因此在nginx中模块可以看作真正的劳动工作者。nginx的模块是被编译到nginx中的,属于静态方式。启动nginx时,模块被自动加载。不像apache,把模块单独编译成so文件,在配置文件中指定是否加载。所以,单比模块加载方面,nginx也比apache速度上有提升。

nginx是怎么调用php的呢?先看下面的nginx中关于php的配置

location ~ \.php$ {
root /webpath;
fastcgi_pass 127.0.0.1:9000;
....
}

这个location指令把以php为文件后缀的请求,交给127.0.0.1:9000处理。我想你看到这个应该猜到了,这是一个C/S架构东西。 而这里的IP地址和端口(127.0.0.1:9000)就是fastcgi进程监听的IP地址和端口。fastcgi是一个可伸缩地、高速地在http server和动态脚本语言间通信的接口。多数流行的http server都支持fastcgi,包括apache、nginx和lighttpd等。同时,fastcgi也被许多脚本语言支持,其中就有php。

那这个fastcgi的配置IP和端口从何而来呢?在php-fpm.conf中可以看到如下:

listen = 127.0.0.1:9000 #这个表示php的fastcgi进程监听的ip地址以及端口
pm.start_servers = 2

php-fpm作为fastcgi的进程管理器,可以有效控制内存和进程,并且平滑重载php配置。php5.3以后,php-fpm被集成到php的core中,默认安装,无须配置。

fastcgi进程管理器php-fpm自身初始化,启动主进程php-fpm和启动start_servers个fastcgi子进程。主进程php-fpm主要是管理fastcgi子进程,监听9000端口,fastcgi子进程等待请求。当客户端请求到达nginx时,nginx通过location指令,将所有以php为后缀的文件都交给 127.0.0.1:9000 来处理。php-fpm选择并连接到一个fastcgi子进程,并将环境变量和标准输入发送到fastcgi子进程。fastcgi子进程完成处理后将标准输出和错误信息返回。当fastcgi子进程关闭连接时,请求便告处理完成,等待下次处理。

总结:关于nginx和php的通信机制就介绍到这里,php和nginx是我们做网站经常会用到的程序与系统,当然了,中间还有很多技术上面的细节值得我们去学习与交流。

版权声明:本文(即:原文链接:https://www.qin1qin.com/catagory/648/)内容由互联网用户自发投稿贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 630367839@qq.com 举报,一经查实,本站将立刻删除。

(1)
上一篇 2022-06-30 4:06:37
下一篇 2022-07-01 12:01:25

软件定制开发公司

相关阅读

发表回复

登录后才能评论
通知:禁止投稿所有关于虚拟货币,币圈类相关文章,发现立即永久封锁账户ID!