你确定你真的懂 Nginx 与 PHP 的交互?

简介: 你确定你真的懂 Nginx 与 PHP 的交互?

Nginx 是俄国人最早开发的 Webserver,现在已经风靡全球,相信大家并不陌生。PHP 也通过二十多年的发展来到了 7 系列版本,更加关注性能。这对搭档在最近这些年,叱咤风云,基本上 LNMP 成了当下的标配。可是,你用了这么多年的 Nginx+PHP 的搭配,你真正知道他们之间是怎么交互怎么通信的么?作为一道常常用来面试的考题,从过往经验看,情况并不乐观。更多的同学是知道 PHP-FPM、知道 FastCGI,但不晓得 Nginx、PHP 这对老搭档具体的交互细节。那么,今天我们就来一起学习一下,做一回认真的 PHP 工程师。

前菜

为了讲解的有理有据,我们先来准备一个纯净精简的 Nginx+PHP 环境,这里我们使用 Docker 拉取 Centos 最新版本环境,来快速通过编译安装方式搭建一个 Nginx+PHP 环境。(图 1,通过 docker 启动一台 CentOS 机器并进入)

 

有了 Linux 环境,我们来源码编译安装 Nginx、PHP,这个过程网络里有很多的教程,我们就不细说了。当然你也可以安装 lnmp 一键安装包来快速搭建。通过安装 nginx、php,我们的 Linux 环境里就有了今天的这两位主角了。我们稍加配置,让 Nginx 可以接收请求并转发给 PHP-FPM,我们目标是输出一个 phpinfo () 的信息。(图 2,phpinfo () 的输出内容)

我们通过对 Nginx 新增 Server 配置实现了 nginx 与 PHP 的一次通信,配置文件非常简单,如下图:(图 3,一份 nginx server 配置)

有了上面的一个 sample 示例,我们开始深入 Nginx 与 FastCGI 协议。

主食

从上图的 Nginx 配置中可以注意到 fastcgi* 开头的一些配置,以及引入的 fastcgi.conf 文件。其实在 fastcgi.conf 中,也是一堆 fastcgi* 的配置项,只是这些配置项相对不常变,通常单独文件保管可以在多处引用。(图 4,fastcgi.conf 文件中的内容)

可以看到在 fastcgi.conf 中,有很多的 fastcgi_param 配置,结合 nginx server 配置中的 fastcgi_pass、fastcgi_index,通常我们的同学已经能够想到 Nginx 与 PHP 之间打交道就是用的 FastCGI,但再深问 FastCGI 是什么?它起到衔接 Nginx、PHP 的什么作用?等等深入的问题的时候,很多同学就卡壳了。那么,我们就来一探究竟。

CGI 是通用网关协议,FastCGI 则是一种常住进程的 CGI 模式程序。我们所熟知的 PHP-FPM 的全称是 PHP FastCGI Process Manager,即 PHP-FPM 会通过用户配置来管理一批 FastCGI 进程,例如在 PHP-FPM 管理下的某个 FastCGI 进程挂了,PHP-FPM 会根据用户配置来看是否要重启补全,PHP-FPM 更像是管理器,而真正衔接 Nginx 与 PHP 的则是 FastCGI 进程。(图 5,FastCGI 在请求流中的位置)

如上图所示,FastCGI 的下游,是 CGI-APP,在我们的 LNMP 架构里,这个 CGI-APP 就是 PHP 程序。而 FastCGI 的上游是 Nginx,他们之间有一个通信载体,即图中的 socket。在我们上文图 3 的配置文件中,fastcgi_pass 所配置的内容,便是告诉 Nginx 你接收到用户请求以后,你该往哪里转发,在我们图 3 中是转发到本机的一个 socket 文件,这里 fastcgi_pass 也常配置为一个 http 接口地址(这个可以在 php-fpm.conf 中配置)。而上图 5 中的 Pre-fork,则对应着我们 PHP-FPM 的启动,也就是在我们启动 PHP-FPM 时便会根据用户配置启动诸多 FastCGI 触发器(FastCGI Wrapper)。

对 FastCGI 在 Nginx+PHP 的模式中的定位有了一定了解后,我们再来了解下 Nginx 中为何能写很多 fastcgi_* 的配置项。这是因为 Nginx 的一个默认内置 module 实现了 FastCGI 的 Client。关于 Module ngx_http_fastcgi_module 的详细文档可以查看这里: http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html 。我们关心一下我们图 4 中的这些 fastcgi_param 都是些什么吧,详细描述见下图。(图 6,nginx 模块中 fastcgi_param 的介绍)

从图 6 中可以看到,fastcgi_param 所声明的内容,将会被传递给 “FastCGI server”,那这里指的就是 fastcgi_pass 所指向的 server,也就是我们 Nginx+PHP 模式下的 PHP-FPM 所管理的 FastCGI 进程,或者说是那个 socket 文件载体。这时,有的同学会问:“为什么 PHP-FPM 管理的那些 FastCGI 进程要关心这些参数呢?”,好问题,我们一起想想我们做 PHP 应用开发时候有没有用到 $_SERVER 这个全局变量,它里面包含了很多服务器的信息,比如包含了用户的 IP 地址。同学们不想想我们的 PHP 身处 socket 文件之后,为什么能得到远端用户的 IP 呢?聪明的同学应该注意到图 4 中的一个 fastcgi_param 配置 REMOTE_ADDR ,这不正是我们在 PHP 中用 $_SERVER [‘REMOTE_ADDR’] 取到的用户 IP 么。的确,Nginx 这个模块里 fastcgi_param 参数,就是考虑后端程序有时需要获取 Webserver 外部的变量以及服务器情况,那么 ngx_http_fastcgi_module 就帮我们做了这件事。真的是太感谢它啦!

那么我们已经说清了 FastCGI 是个什么东东,并且它在 Nginx+PHP 中的定位。我们回到前面提出的问题,“它起到衔接 Nginx、PHP 的什么作用?”。

对 PHP 有一定了解的同学,应该会知道 PHP 提供 SAPI 面向 Webserver 来提供扩展编程。但是这样的方式意味着你要是自主研发一套 Webserver,你就需要学习 SAPI,并且在你的 Webserver 程序中实现它。这意味着你的 Webserver 与 PHP 产生了耦合。在互联网的大趋势下,一般大家都不喜欢看到耦合。譬如 Nginx 在最初研发时候也不是为了和 PHP 组成黄金搭档而研发的,相信早些年的 Nginx 后端程序可能是其他语言开发。那么解决耦合的办法,比较好的方式是有一套通用的规范,上下游都兼容它。那么 CGI 协议便成了 Nginx、PHP 都愿意接受的一种方式,而 FastCGI 常住进程的模式又让上下游程序有了高并发的可能。那么,FastCGI 的作用是 Nginx、PHP 的接口载体,就像插座与插销,让流行的 WebServer 与 “世界上最好的语言” 有了合作的可能。

有了这些基础背景知识与他们的缘由,我们就可以举一反三的做更多有意思的事情。譬如我在前年曾实现了 Java 程序中按照 FastCGI Client 的方式(替代 Nginx)与 PHP-FPM 通信,实现 Java 项目 + PHP 的一种组合搭配,解决的问题是 Java 程序一般来说在代码调整后需要编译过程,而 PHP 可以随时调整代码随时生效,那么让 Java 作为项目外壳,一些易变的代码由 PHP 实现,在需要的时候 Java 程序通过 FastCGI 与 PHP 打交道就好。这套想法也是基于对 Nginx+PHP 交互模式的理解之上想到的。

网络中也有一些借助 FastCGI 的尝试与实践,譬如《Writing Hello World in FCGI with C++》这篇文章,用 C++ 实现一个 FastCGI 的程序,外部依然是某款 Webserver 来处理 HTTP 请求,但具体功能则有 C++ 来实现,他们的中间交互同样适用的 FastCGI。同学们有兴趣了也可以做些 Geek 尝试。(图 7,C++ 实现一个 FastCGI 程序)

甜品

通过本文的讲解,我们希望让大家看到,Nginx+PHP 的工程模式下,两位主角分工明确,Nginx 负责承载 HTTP 请求的响应与返回,以及超时控制记录日志等 HTTP 相关的功能,而 PHP 则负责处理具体请求要做的业务逻辑,它们俩的这种合作模式也是常见的分层架构设计中的一种,在它们各有专注面的同时,FastCGI 又很好的将两块衔接,保障上下游通信交互,这种通过某种协议或规范来衔接好上下游的模式,在我们日常的 PHP 应用开发中也有这样的思想落地,譬如我们所开发的高性能 API,具体的 Client 到底是 PC、APP 还是某个其他程序,我们不关心,而这些 PC、APP、第三方程序也不关心我们的 PHP 代码实现,他们按照 API 的规范来请求做处理即可。同学们是不是发现技术思想是可以在各个环节融会贯通的,是不是很兴奋?很刺激?哈,同学们开心就好,祝大家在工作学习过程中,能挖掘到更多的好知识,提升自己的同时造福身边小伙伴

相关文章
|
2月前
|
安全 关系型数据库 MySQL
PHP与MySQL交互:从入门到实践
【9月更文挑战第20天】在数字时代的浪潮中,掌握PHP与MySQL的互动成为了开发动态网站和应用程序的关键。本文将通过简明的语言和实例,引导你理解PHP如何与MySQL数据库进行对话,开启你的编程之旅。我们将从连接数据库开始,逐步深入到执行查询、处理结果,以及应对常见的挑战。无论你是初学者还是希望提升技能的开发者,这篇文章都将为你提供实用的知识和技巧。让我们一起探索PHP与MySQL交互的世界,解锁数据的力量!
|
1月前
|
存储 SQL 关系型数据库
PHP与数据库交互:从基础到进阶
【10月更文挑战第9天】在编程的世界里,数据是流动的血液,而数据库则是存储这些珍贵资源的心脏。PHP作为一门流行的服务器端脚本语言,其与数据库的交互能力至关重要。本文将带你从PHP与数据库的基本连接开始,逐步深入到复杂查询的编写和优化,以及如何使用PHP处理数据库结果。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供宝贵的知识和技巧,让你在PHP和数据库交互的道路上更加从容不迫。
|
3月前
|
存储 SQL 关系型数据库
PHP与MySQL交互的奥秘
【8月更文挑战第29天】在编程的世界里,PHP和MySQL就像是一对默契的舞伴,共同演绎着数据的交响曲。本文将带你探索它们之间的互动,从连接数据库到执行查询,再到处理结果,每一步都充满了节奏与和谐。我们将一起走进这段代码的旅程,感受数据流动的魅力。
|
1月前
|
tengine 应用服务中间件 Linux
Tengine、Nginx安装PHP命令教程
要在阿里云Linux上安装PHP,请先更新YUM源并启用PHP 8.0仓库,然后安装PHP及相关扩展。通过`php -v`命令验证安装成功后,需修改Nginx配置文件以支持PHP,并重启服务。最后,创建`phpinfo.php`文件测试安装是否成功。对于CentOS系统,还需安装EPEL源和Remi仓库,其余步骤类似。完成上述操作后,可通过浏览器访问`http://IP地址/phpinfo.php`测试安装结果。
|
3月前
|
SQL 关系型数据库 MySQL
PHP与数据库交互的艺术:深入探讨PDO扩展
【8月更文挑战第28天】在数字信息时代的海洋里,PHP作为一艘灵活的帆船,承载着无数网站和应用的梦想。而PDO扩展,则是这艘帆船上不可或缺的导航仪,指引着数据安全与效率的航向。本文将带你领略PHP与数据库交互的艺术,深入浅出地探索PDO的世界,从连接数据库到执行复杂的查询,每一步都清晰可见。我们将一起航行在这段奇妙的旅程上,解锁数据的奥秘,体验编程的乐趣。
49 1
|
3月前
|
SQL 关系型数据库 MySQL
PHP与MySQL交互之基础教程
【8月更文挑战第31天】 在数字世界中,数据是推动一切的核心力量。本文将引导你探索PHP与MySQL的协同工作,通过实际代码示例,展示如何建立连接、执行查询以及处理结果集。无论你是初学者还是希望巩固知识的开发者,这篇文章都将为你提供宝贵的实践知识。
|
3月前
|
应用服务中间件 Linux PHP
Linux搭建tengine2.0<Nginx>+php7环境
本文介绍了在Linux系统上搭建Tengine 2.0(一个Nginx的增强版本)和PHP 7环境的详细步骤,包括创建安装目录、下载源码包及依赖库、编译安装Nginx、配置Nginx、安装PHP及其依赖、设置PHP-FPM、配置环境变量、安装Git和Composer,以及服务管理和日志查看等。
88 0
|
3月前
|
Ubuntu 应用服务中间件 Linux
如何在Ubuntu 14.04上使用Nginx和Php-fpm安全地托管多个网站
如何在Ubuntu 14.04上使用Nginx和Php-fpm安全地托管多个网站
28 0
|
5月前
|
NoSQL 关系型数据库 MySQL
linux服务器重启php,nginx,redis,mysql命令
linux服务器重启php,nginx,redis,mysql命令
118 1
|
5月前
|
存储 SQL PHP
PHP中的PDO与数据库交互
PHP的PDO扩展提供了一种方式来统一访问多种数据库