WebService之nginx+(php-fpm)结构模型剖析及优化

  随着php脚本语言使用的普及,目前webserice服务大部分都在用nginx+(php-fpm)的结构,了解了其工作过程后才可以在各个方面想办法做调整优化和故障排查,从以下几点总结一下这种模型。


一、nginxphp-fpm的关系和分工

nginxweb服务器,php-fpm是一个PHPFastCGI进程管理器,两者遵循fastcgi的协议进行通信,nginx负责静态类似html文件的处理,php-fpm负责php脚本语言的执行,这么设计的目的是为了解耦前端nginx和后端的php,不至于让容易出问题的php脚本堵塞整个nginx的业务处理,影响用户体验,因为php脚本语言的执行是会比较容易出问题的。nginx之所以能处理成千上万高并发业务,除其本身的异步非阻塞模式,在与和其他模块的耦合扩展方法也是分不开的,在nginx的设计里不能接受的就是阻塞,不过并非完全没有梗,比如说用到的最多的多进程单线程的模式,由于nginx日志没有单独的处理进程,如果收集日志时处理不当就会把worker进程堵死。

  对应nginx+php-fpm的模型结构图如下:


wKioL1fOU-fiLC8nAAEc-FGrRjo932.png

(图 1)


1、nginx的工作简介(对应图1看)

在接到php的脚本请求后,nginx通过fastcgi_pass指令将请求传递给后端php-fpmworker进程处理,在此过程中,nginx做了各种超时机制、缓存机制、buffer机制和长连接机制等来保障与后端的php-fpm能够良性高效的合作。

在超时机制方面控制nginx对后端php的等待时间,通过各种timeout指令进行控制,例如:

fastcgi_connect_timeout   后端链接时间

fastcgi_send_timeout    数据发送时间,两次成功发送时间差,不是整个发送时间

fastcgi_read_timeout    数据接收时间,两次成功接收时间差,不是整个接收时间

  当超时后会返回504超时的状态码,在buffer机制指令也有很多,例如:

fastcgi_buffer_size 存放fastcgi传过来的响应头,一般设置为分页大小

fastcgi_buffers 存放fastcgi传过来的相应内容,一般设置分页的倍数,格式例如 8  4k|8k

  另外还有一些其它的缓存、长连接机制不做介绍,当设置不合理时也会出现5XX错误,nginx的文章介绍写了有很多的,不再做过多的说明。

 

2、php-fpm工作介绍(对应图1看)

Php-fpm是一个PHPfastcgi进程管理器,在启动后会有masterworker两种进程,master负责接收外部信号和管理worker进程,worker进程是负责干活的,处理nginx传过来的任务。

master进程只有一个,负责监听端口和管理worker进程,每次传来任务,与前端的nginx建立3次握手后放入连接队列,供worker进程进行accept,当worker进程出现错误或执行超时时,负责将worker进程重启或者杀掉,是php-fpm模型中的大内总管。

Worker进程是工作进程,每个worker进程都独立的执行php程序脚本,然后把执行的结果通过fastcgi协议交给nginx,执行过程中受master的管理。在工作中,worker进程去竞争accept管理进程master的链接队列,accept函数将从连接请求队列中获得连接信息,创建新的socket,并返回该套接字的fd,新创建的socket用于服务器与nginx的通信,而原来的套接字仍然处于监听状态。

php-fpm可以配置多个pool,所有poolmaster统一管理监听不同端口并分配不同worker进程池,worker进程池支持动态prefork同时也支持静态开启,服务器内存较大时建议直接计算后配置静态资源池,可以减少频繁prefork进程所带来的开销,提高服务质量,由于进程模型越跑程序耗费越大,因为每个worker进程可以配置执行多少个请求后进行重启,对应的池子的指令和执行多少个请求的指令如下:

pm = static | dynamic | ondemand 静态池、服务优先、内存优先

pm.max_children = 256  开启的最大php进程数

pm.max_requests = 1024   在执行了1024个请求后重启worker进程

   这也是我们线上服务器的配置,我们线上用的web服务的机器是12cpu16G内存,nginx开启12worker进程,php开启256个进程,跑起来后每个进程大概占用30M内存,也就是(256+12*30=8G ,另外还跑了一些配管、监控、统计、日志收集等七七八八的软件,整体业务是比较轻松的,这种静态池的配置大大减少了prefork进程带来的开销,RT时间100ms以内的占到90%以上(这个与程序写的如何有关),运行一段时间后的开销截图如下:


wKiom1fOVyGwRrByAAB0HEoKVdw112.png

 


二、此模型结构常见的5XX服务器端错误及优化(对应图1看) 


1、nginx日志里产生502错误

  第一种情况,php-fpm的worker进程执行php程序脚本时,超过了配置的最长执行时间,master进程将worker进程杀掉,直接返回502

返回502nginx对应的error日志是104: Connection reset by peer

对应的php执行时间的配置如下,一些版本中php-fpm的配置会覆盖php.ini的配置,使php.ini的配置不起作用:

php.ini中默认30smax_execution_time =

php-fpm中:request_terminate_timeout =

  第二种情况,连接请求数(accpet之前)超出了端口所能监听的tcp连接的最大值(backlog的值),进不了fpm等待accept的链接队列,直接返回502,这里可能会产生tcp重传;

返回502nginx对应的error日志是111: Connection refused

   backlog的值是半连接和全连接的总和,他的存在也有短时间缓冲解耦nginx请求与fpm处理的作用,半连接指收到了syn请求,3次握手尚未建立,全连接指的是3次握手已经成功,不过尚未被accpet的请求,fpm里面有调节的参数,如果fpm的参数设置为-1,则默认走的是系统内核参数net.core.somaxconn的设置值,如果不设置可以在/proc/sys/net/core/somaxconn里查看,默认值是128,所以在连接请求较高的业务里要增大这个值。

  

  • 减少避免502报错优化建议

502主要从php-fpm的配置方考虑,根据服务器情况,适量增大php-fpm的工作进程数,适当增加php的执行时间,适当增加backlog

php的工作进程数也不是越大越好,这种进程模型运行时间长了占的内存会增大,一般一个php进程是占到30M左右的内存,开多少合适自己算吧,nginxworker进程一般也能跑到30M的内存,综合计算一下;php的执行时间可以根据你的服务标准来设定,超过服务时间浏览器返回的是502错误,这个按照实际的情况处理吧,反正我是觉得执行的慢有返回结果总比直接返回502错误的强;至于backlog值,当程序写的比较好时,建议设置其数量为php工作进程的12倍。

  

2、nginx日志里产生504错误

  第一种情况,phpworker进程池处理慢,无法尽快处理等待accept的链接队列,导致3次握手后的链接队列长时间没有被acceptnginx链接等待超时;

返回504nginx对应的error日志是110: Connection timed out

  第二种情况,后端php-fpm执行脚本的时间太长,超过了nginx配置的超时机制,这个时候也是会报出504错误的。

  • 减少避免504报错的优化建议

504主要从nginx的配置方考虑,根据业务情况配置好超时的各种机制,包含但不限于下属参数:

fastcgi_connect_timeout

fastcgi_send_timeout 

fastcgi_read_timeout 

。。。。。。。。


另外:在配置过程中,比如遇到大并发或者是特殊业务的场景,不合理的fd、buffer等设置也会带来5XX错误,比如说大并发连接的业务要增大系统和单个程序的fd数量,如果是上传业务要增大头buffer等,这些要视情况而做优化,正所谓道法自然,术变万千,要以不变应万变。




本文出自 “奔跑的linux” 博客,请务必保留此出处http://benpaozhe.blog.51cto.com/10239098/1846784

本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。
数据库的运维中,经常会遇到delete drop truncate的操作,那么如何去把握它们的用法和区别呢? 比如当数据库空间爆满,已经增长到存储空间单个存储文件的最大值 32G 。你需要通过一些办法释放掉表空间或者扩容表空间来解决问题。 一般当系统中大量使用分区表,而针对分区表清除数据,是不会释放表空间的,必须把分区 drop 掉,才会释放空间。 下面我们具体了解一下这三个命令: 一、delete 1、delete是DML,执行delete操作时,每次从表中删除一行,并且同时将该行的的删除操作记录在re
最近有一个服务器升级的项目,得知用户需求是03服务器上的文件、DNS、DHCP要迁移到Server 2012上,文件服务器最重要的当然是保留权限的设置,DHCP和DNS服务器实现迁移相对来说很简单 于是我便模拟了以下环境先进行测试,项目完成之后再做总结 = = 环境介绍 DC 192.168.124.250 Migration 192.168.124.251(Server 2012 R2 Datacenter,将03的服务器迁移到此服务器) FDDS 192.168.124.252(Server 2003
CentOS6中关于网络配置的命令有很多,本文将介绍几个平时最长用的几个命令,以及网卡IP地址的配置和简单路由配置。 1、经常使用的查看IP地址命令为 ifconfig,不跟参数的情况下默认查看所有已启用的网卡信息,如下图所示: 如果想查看具体某块网卡信息,则可以在ifconfig后面跟上网卡设备,如只查看eth0的信息则执行:ifconfig eht0 即可。 禁用某块网卡:结合down命令可以禁用某块网卡,如要禁用eth0网卡,则执行:ifconfig eth0 down 即可,这种禁用只是临时性的,
为Windows Server 2012 R2指定授权服务器 在Windows Server 2008 R2的终端服务中,可以手动指定授权服务器,而在Windows Server 2012 R2中,默认只能通过"远程桌面连接服务"管理器,指定授权服务器,而要使用远程桌面连接服务管理器,则需要安装一系列的组件,但大多数的时候,我们只是想配置一台"远程桌面会话主机",不想要安装"远程桌面网关服务"、"远程桌面Web代理"这些组件,那么,有没有办法和Windows Server 2008 R2一样,为Windo
移除VMware View桌面中孤立的主机与桌面池 在使用VMware View桌面的过程中,如果由于多种因为(例如重新安装了vCenter Server)导致View桌面池丢失,想要在View Administrator中删除这些孤立的虚拟机与桌面池,可以使用如下的方法。 图1-1 停留在"正在删除" 图1-2 停止在"正在删除" 1 登录View Composer删除孤立虚拟机 进入View Composer的服务器,打开View Composer安装位置,复制该路径,如图1-3所示。默认情况下,此路
今天发现有一台线上的服务器内存报警,最近报警发现有好几次了,慎是恼火,想一探究竟,看了一下是一台16G内存的服务器,free 了一下看了一下确实是没有多少内存可用了,再看了一下都跑了一些什么应用,结果发现只跑了一个数据库跟一个跨服,当时心里就感觉16G内存不可能用完, [root@hqg-222-99.logs]#psaux|awk'{sum=sum+$6};END{printsum/1024"M"}'4363.01M才使用了4g多一点#也可以通过这段在网上找到的脚本查看#/bin/bashforPROC
之前在上linux课的时候,老师说,vim使用的好的网络管理员比普通的效率快好多。 合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。撸基础吧。 linux编辑工具 VI VIM EMACS vim 是vi的升级版本,它不仅兼容vi的所有指令,而且还有一些新的特性在里面。vim的这些优势主要体现在以下几个方面: 易用性 vi只能运行于unix中,而vim不仅可以运行于unix,windows ,mac等多操作平台。 语法加亮 vim可以用不同的颜色来加亮你的代码。 可视化操作( ESC+V) 就
CentOS 6.8 GRUB加密和破解密码实战指南 案例1:服务器在公共场合,为了防止随便有人进入单用户破解root密码,先对GRUB引导进行加密,为了更加安全对启动内核时也加密 1、编辑grub配置文件 [root@localhost~]#opensslpasswd-1//MD5加密转换Password:Verifying-Password:$1$X8cVMw5v$AH0aUHVNix7Tx6wmHAXsf1[root@localhost~]#vim/etc/grub.conf#grub.confge
故障: 在HP 785G6(服务器有2个集成网卡,4个独立网卡)上装centos6.5后配置网卡信息后,重启网卡报错,提示Bringing uo interface eth0:bnx2 0000:02:03.0:etho:register_cnicfailed Determining if ip address isalready in use for device eth0,网络不通,截图如下 排查经过 :查看配置文件, [root@HGJ0205 ~]# cat /etc/sysconfig/netw
之前的话我们的项目都是跑在windows上,今天我们要将我们的程序跑到linxu机器上。在看linux部署之前,我们先看一下node.js类似于asp.net mvc的过滤器或者叫拦截器。在app.js中我们加入如下代码 varbeforeRequest=function(req,res,next){if(req.originalUrl=='/'||req.originalUrl=='/login'||req.originalUrl=='/config'||req.originalUrl=='/user'