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的规范来请求做处理即可。同学们是不是发现技术思想是可以在各个环节融会贯通的,是不是很兴奋?很刺激?哈,同学们开心就好,祝大家在工作学习过程中,能挖掘到更多的好知识,提升自己的同时造福身边小伙伴!

你确定你真的懂Nginx与PHP的交互?的更多相关文章

  1. [C#] C# 知识回顾 - 你真的懂异常(Exception)吗?

    你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...

  2. 【转】was mutated while being enumerated 你是不是以为你真的懂For...in... ??

    原文网址:http://www.jianshu.com/p/ad80d9443a92 支持原创,如需转载, 请注明出处你是不是以为你真的懂For...in... ??哈哈哈哈, 我也碰到了这个报错 . ...

  3. javascript的语法作用域你真的懂了吗

    原文:javascript的语法作用域你真的懂了吗 有段时间没有更新了,思绪一下子有点转不过来.正应了一句古话“一天不读书,无人看得出:一周不读书,开始会爆粗:一月不读书,智商输给猪.”.再加上周五晚 ...

  4. 你真的懂ajax吗?

    前言 总括: 本文讲解了ajax的历史,工作原理以及优缺点,对XMLHttpRequest对象进行了详细的讲解,并使用原生js实现了一个ajax对象以方便日常开始使用. damonare的ajax库: ...

  5. “三次握手,四次挥手”你真的懂吗?TCP

    “三次握手,四次挥手”你真的懂吗?  mp.weixin.qq.com 来源:码农桃花源 解读:“拼多多”被薅的问题出在哪儿?损失将如何买单? 之前有推过一篇不错的干货<TCP之三次握手四次挥手 ...

  6. 你真的懂 ajax 吗?

    前言 总括: 本文讲解了ajax的历史,工作原理以及优缺点,对XMLHttpRequest对象进行了详细的讲解,并使用原生js实现了一个ajax对象以方便日常开始使用. damonare的ajax库: ...

  7. 【转】先说IEnumerable,我们每天用的foreach你真的懂它吗?

    [转]先说IEnumerable,我们每天用的foreach你真的懂它吗? 我们先思考几个问题: 为什么在foreach中不能修改item的值? 要实现foreach需要满足什么条件? 为什么Linq ...

  8. 程序猿修仙之路--数据结构之你是否真的懂数组? c#socket TCP同步网络通信 用lambda表达式树替代反射 ASP.NET MVC如何做一个简单的非法登录拦截

    程序猿修仙之路--数据结构之你是否真的懂数组?   数据结构 但凡IT江湖侠士,算法与数据结构为必修之课.早有前辈已经明确指出:程序=算法+数据结构  .要想在之后的江湖历练中通关,数据结构必不可少. ...

  9. C# 知识回顾 - 你真的懂异常(Exception)吗?

    你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...

随机推荐

  1. 如何用node命令和webpack命令传递参数 转载

    1. 比如在项目中我们的publicPath需要根据服务器环境的变化而变化,这时我们会写一个配置文件,在webpack.config.js中读取,可以 如何才能 取到变量呢? 这里介绍一种方法: 如果 ...

  2. 通过 JDK 自带的 javap 命令查看 SynchronizedDemo 类的相关字节码信息

    首先切换到类的对应目录执行 javac SynchronizedDemo.java 命令生成编译后的 .class 文件 然后执行 javap -c -s -v -l SynchronizedDemo ...

  3. windows与linux换行规则

    在计算机还没有出现之前,有一种叫做电传打字机(Teletype Model 33)的玩意,每秒钟可以打10个字符.但是它有一个问题,就是打完一行换行的时候,要用去0.2秒,正好可以打两个字符.要是在这 ...

  4. Excel技巧--文件批处理

    先认识几个dos命令: ren 旧文件名 新文件名:更改文件名: dir 文件路径 /b > 目标路径/表名.xls:查询指定文件路径下的所有文件,写入到目标路径下的excel文件中: md 新 ...

  5. Linux Bash Shell字符串分割substring等(转)

    原文https://blog.csdn.net/wuyinggui10000/article/details/52779364 脚本开发中遇到的问题是:原java中的字符串分割操作(substring ...

  6. 2017-2018-2 20165312 实验四《Android程序设计》实验报告

    2017-2018-2 20165312 实验四<Android程序设计>实验报告 一.安装Android Studio并进行Hello world测试和调试程序 安装Android St ...

  7. 10-安装es

    1.安装jdk(jdk要求1.8.20或1.7.55以上) 2.上传es安装包 3.解压es tar -zxvf elasticsearch-2.3.1.tar.gz -C /opt/app/ 4.e ...

  8. Python字符串格式化 (%操作符)

    在许多编程语言中都包含有格式化字符串的功能,比如C和Fortran语言中的格式化输入输出.Python中内置有对字符串进行格式化的操作%. 模板 格式化字符串时,Python使用一个字符串作为模板.模 ...

  9. leetcode169

    public class Solution { public int MajorityElement(int[] nums) { Dictionary<int, int> dic = ne ...

  10. Django之前后端交互使用ajax的方式

    1. 在项目中前后端数据相互是一种常态, 前后端交互使用的是ajax请求和form表单的请求两种方式" ajax与form表单的区别在于: form 是整个页面刷新提交的,  但是ajax ...