nginx工做原理、优化、漏洞

1.  Nginx的模块与工做原理javascript

Nginx由内核和模块组成,其中,内核的设计很是微小和简洁,完成的工做也很是简单,仅仅经过查找配置文件将客户端请求映射到一个location block(location是Nginx配置中的一个指令,用于URL匹配),而在这个location中所配置的每一个指令将会启动不一样的模块去完成相应的工做。php

Nginx的模块从结构上分为核心模块、基础模块和第三方模块:css

核心模块:HTTP模块、EVENT模块和MAIL模块html

基础模块:HTTP Access模块、HTTP FastCGI模块、HTTP Proxy模块和HTTP Rewrite模块,前端

第三方模块:HTTP Upstream Request Hash模块、Notice模块和HTTP Access Key模块。java

用户根据本身的须要开发的模块都属于第三方模块。正是有了这么多模块的支撑,Nginx的功能才会如此强大。mysql

Nginx的模块从功能上分为以下三类。linux

Handlers(处理器模块)。此类模块直接处理请求,并进行输出内容和修改headers信息等操做。Handlers处理器模块通常只能有一个。nginx

Filters (过滤器模块)。此类模块主要对其余处理器模块输出的内容进行修改操做,最后由Nginx输出。web

Proxies (代理类模块)。此类模块是Nginx的HTTP Upstream之类的模块,这些模块主要与后端一些服务好比FastCGI等进行交互,实现服务代理和负载均衡等功能。

图1-1展现了Nginx模块常规的HTTP请求和响应的过程。


                       图1-1展现了Nginx模块常规的HTTP请求和响应的过程。

Nginx自己作的工做实际不多,当它接到一个HTTP请求时,它仅仅是经过查找配置文件将这次请求映射到一个location block,而此location中所配置的各个指令则会启动不一样的模块去完成工做,所以模块能够看作Nginx真正的劳动工做者。一般一个location中的指令会涉及一个handler模块和多个filter模块(固然,多个location能够复用同一个模块)。handler模块负责处理请求,完成响应内容的生成,而filter模块对响应内容进行处理。

Nginx的模块直接被编译进Nginx,所以属于静态编译方式。启动Nginx后,Nginx的模块被自动加载,不像Apache,首先将模块编译为一个so文件,而后在配置文件中指定是否进行加载。在解析配置文件时,Nginx的每一个模块都有可能去处理某个请求,可是同一个处理请求只能由一个模块来完成。 

在工做方式上,Nginx分为单工做进程和多工做进程两种模式。在单工做进程模式下,除主进程外,还有一个工做进程,工做进程是单线程的;在多工做进程模式下,每一个工做进程包含多个线程。Nginx默认为单工做进程模式。

2.  Nginx+FastCGI运行原理

一、什么是 FastCGI

FastCGI是一个可伸缩地、高速地在HTTP server和动态脚本语言间通讯的接口。多数流行的HTTP server都支持FastCGI,包括Apache、Nginx和lighttpd等。同时,FastCGI也被许多脚本语言支持,其中就有PHP。

FastCGI是从CGI发展改进而来的。传统CGI接口方式的主要缺点是性能不好,由于每次HTTP服务器遇到动态程序时都须要从新启动脚本解析器来执行解析,而后将结果返回给HTTP服务器。这在处理高并发访问时几乎是不可用的。另外传统的CGI接口方式安全性也不好,如今已经不多使用了。

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

二、Nginx+FastCGI运行原理

Nginx不支持对外部程序的直接调用或者解析,全部的外部程序(包括PHP)必须经过FastCGI接口来调用。FastCGI接口在Linux下是socket(这个socket能够是文件socket,也能够是ip socket)。

wrapper:为了调用CGI程序,还须要一个FastCGI的wrapper(wrapper能够理解为用于启动另外一个程序的程序),这个wrapper绑定在某个固定socket上,如端口或者文件socket。当Nginx将CGI请求发送给这个socket的时候,经过FastCGI接口,wrapper接收到请求,而后Fork(派生)出一个新的线程,这个线程调用解释器或者外部程序处理脚本并读取返回数据;接着,wrapper再将返回的数据经过FastCGI接口,沿着固定的socket传递给Nginx;最后,Nginx将返回的数据(html页面或者图片)发送给客户端。这就是Nginx+FastCGI的整个运做过程,如图1-3所示。

       


      因此,咱们首先须要一个wrapper,这个wrapper须要完成的工做:

  1. 经过调用fastcgi(库)的函数经过socket和ningx通讯(读写socket是fastcgi内部实现的功能,对wrapper是非透明的)
  2. 调度thread,进行fork和kill
  3. 和application(php)进行通讯

三、spawn-fcgi与PHP-FPM

       FastCGI接口方式在脚本解析服务器上启动一个或者多个守护进程对动态脚本进行解析,这些进程就是FastCGI进程管理器,或者称为FastCGI引擎。 spawn-fcgi与PHP-FPM就是支持PHP的两个FastCGI进程管理器。 所以HTTPServer彻底解放出来,能够更好地进行响应和并发处理。
       
       spawn-fcgi与PHP-FPM的异同:
       1)spawn-fcgi是HTTP服务器lighttpd的一部分,目前已经独立成为一个项目,通常与lighttpd配合使用来支持PHP。可是ligttpd的spwan-fcgi在高并发访问的时候,会出现内存泄漏甚至自动重启FastCGI的问题。即:PHP脚本处理器当机,这个时候若是用户访问的话,可能就会出现白页(即PHP不能被解析或者出错)。
       2)Nginx是个轻量级的HTTP server,必须借助第三方的FastCGI处理器才能够对PHP进行解析, 所以其实这样看来 nginx 是很是灵活的,它能够和任何第三方提供解析的处理器实现链接从而实现对 PHP 的解析 ( nginx.conf 中很容易设置 ) nginx也 可使用 spwan-fcgi( 须要一同安装 lighttpd ,可是须要为 nginx 避开端口,一些较早的 blog 有这方面安装的教程 ) ,可是因为 spawn-fcgi 具备上面所述的用户逐渐发现的缺陷,如今慢慢减小用 nginx+spawn-fcgi 组合了。

       因为spawn-fcgi的缺陷,如今出现了第三方(目前已经加入到PHP core中)的PHP的FastCGI处理器PHP-FPM,它和spawn-fcgi比较起来有以下优势:

       因为它是做为PHP的patch补丁来开发的,安装的时候须要和php源码一块儿编译,也就是说编译到php core中了,所以在性能方面要优秀一些;

同时它在处理高并发方面也优于spawn-fcgi,至少不会自动重启fastcgi处理器。所以,推荐使用Nginx+PHP/PHP-FPM这个组合对PHP进行解析。

      相对Spawn-FCGI,PHP-FPM在CPU和内存方面的控制都更胜一筹,并且前者很容易崩溃,必须用crontab进行监控,而PHP-FPM则没有这种烦恼。
       FastCGI 的主要优势是把动态语言和HTTP Server分离开来,因此Nginx与PHP/PHP-FPM常常被部署在不一样的服务器上,以分担前端Nginx服务器的压力,使Nginx专注处理静态请求和转发动态请求,而PHP/PHP-FPM服务器专注解析PHP动态请求。

四、Nginx+PHP-FPM

      PHP-FPM是管理FastCGI的一个管理器,它做为PHP的插件存在,在安装PHP要想使用PHP-FPM时在老php的老版本(php5.3.3以前)就须要把PHP-FPM以补丁的形式安装到PHP中,并且PHP要与PHP-FPM版本一致,这是必须的)

   PHP-FPM实际上是PHP源代码的一个补丁,旨在将FastCGI进程管理整合进PHP包中。必须将它patch到你的PHP源代码中,在编译安装PHP后才可使用。
   PHP5.3.3已经集成php-fpm了,再也不是第三方的包了。PHP-FPM提供了更好的PHP进程管理方式,能够有效控制内存和进程、能够平滑重载PHP配置,比spawn-fcgi具备更多优势,因此被PHP官方收录了。在./configure的时候带 –enable-fpm参数便可开启PHP-FPM。

      fastcgi已经在php5.3.5的core中了,没必要在configure时添加 --enable-fastcgi了。老版本如php5.2的须要加此项。

      当咱们安装Nginx和PHP-FPM完后,配置信息:

     PHP-FPM的默认配置php-fpm.conf
     listen_address  127.0.0.1:9000 #这个表示php的fastcgi进程监听的ip地址以及端口
      start_servers
      min_spare_servers
      max_spare_servers

      Nginx配置运行php: 编辑nginx.conf加入以下语句:
      location ~ \.php$ {
            root html;   
            fastcgi_pass 127.0.0.1:9000; 指定了fastcgi进程侦听的端口,nginx就是经过这里与php交互的
            fastcgi_index index.php;
            include fastcgi_params;
             fastcgi_param SCRIPT_FILENAME   /usr/local/nginx/html$fastcgi_script_name;
    }
    Nginx经过location指令,将全部以php为后缀的文件都交给127.0.0.1:9000来处理,而这里的IP地址和端口就是FastCGI进程监听的IP地址和端口。
   
     其总体工做流程:
     1)、FastCGI进程管理器php-fpm自身初始化,启动主进程php-fpm和启动 start_servers个CGI 子进程。
            主进程php-fpm主要是管理fastcgi子进程,监听9000端口。
            fastcgi子进程等待来自Web Server的链接。
     2)、当客户端请求到达Web Server Nginx是时, Nginx 经过location指令,将全部以php为后缀的文件都交给127.0.0.1:9000来处理,即Nginx经过location指令,将全部以php为后缀的文件都交给127.0.0.1:9000来处理。
      3)FastCGI进程管理器PHP-FPM选择并链接到一个子进程CGI解释器。Web server将CGI环境变量和标准输入发送到FastCGI子进程。
      4)、FastCGI子进程完成处理后将标准输出和错误信息从同一链接返回Web Server。当FastCGI子进程关闭链接时,请求便告处理完成。
      5)、FastCGI子进程接着等待并处理来自FastCGI进程管理器(运行在 WebServer中)的下一个链接。
 

3.   Nginx的IO模型

     首先nginx支持的事件模型以下(nginx的wiki):

       Nginx支持以下处理链接的方法(I/O复用方法),这些方法能够经过use指令指定。

  • select – 标准方法。 若是当前平台没有更有效的方法,它是编译时默认的方法。你可使用配置参数 –with-select_module 和 –without-select_module 来启用或禁用这个模块。
  • poll – 标准方法。 若是当前平台没有更有效的方法,它是编译时默认的方法。你可使用配置参数 –with-poll_module 和 –without-poll_module 来启用或禁用这个模块。
  • kqueue – 高效的方法,使用于 FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0 和 MacOS X. 使用双处理器的MacOS X系统使用kqueue可能会形成内核崩溃。
  • epoll – 高效的方法,使用于Linux内核2.6版本及之后的系统。在某些发行版本中,如SuSE 8.2, 有让2.4版本的内核支持epoll的补丁。
  • rtsig – 可执行的实时信号,使用于Linux内核版本2.2.19之后的系统。默认状况下整个系统中不能出现大于1024个POSIX实时(排队)信号。这种状况 对于高负载的服务器来讲是低效的;因此有必要经过调节内核参数 /proc/sys/kernel/rtsig-max 来增长队列的大小。但是从Linux内核版本2.6.6-mm2开始, 这个参数就再也不使用了,而且对于每一个进程有一个独立的信号队列,这个队列的大小能够用 RLIMIT_SIGPENDING 参数调节。当这个队列过于拥塞,nginx就放弃它而且开始使用 poll 方法来处理链接直到恢复正常。
  • /dev/poll – 高效的方法,使用于 Solaris 7 11/99+, HP/UX 11.22+ (eventport), IRIX 6.5.15+ 和 Tru64 UNIX 5.1A+.
  • eventport – 高效的方法,使用于 Solaris 10. 为了防止出现内核崩溃的问题, 有必要安装这个 安全补丁。

        在linux下面,只有epoll是高效的方法

        下面再来看看epoll究竟是如何高效的
       Epoll是
Linux内核为处理大批量句柄而做了改进的poll。 要使用epoll只须要这三个系统调用:epoll_create(2), epoll_ctl(2), epoll_wait(2)。它是在2.5.44内核中被引进的(epoll(4) is a new API introduced in Linux kernel 2.5.44),在2.6内核中获得普遍应用。

        epoll的优势

  • 支持一个进程打开大数目的socket描述符(FD)

        select 最不能忍受的是一个进程所打开的FD是有必定限制的,由FD_SETSIZE设置,默认值是2048。对于那些须要支持的上万链接数目的IM服务器来讲显 然太少了。这时候你一是能够选择修改这个宏而后从新编译内核,不过资料也同时指出这样会带来网络效率的降低,二是能够选择多进程的解决方案(传统的 Apache方案),不过虽然linux上面建立进程的代价比较小,但仍旧是不可忽视的,加上进程间数据同步远比不上线程间同步的高效,因此也不是一种完 美的方案。不过 epoll则没有这个限制,它所支持的FD上限是最大能够打开文件的数目,这个数字通常远大于2048,举个例子,在1GB内存的机器上大约是10万左 右,具体数目能够cat /proc/sys/fs/file-max察看,通常来讲这个数目和系统内存关系很大。

  • IO效率不随FD数目增长而线性降低

         传统的select/poll另外一个致命弱点就是当你拥有一个很大的socket集合,不过因为网络延时,任一时间只有部分的socket是”活跃”的,但 是select/poll每次调用都会线性扫描所有的集合,致使效率呈现线性降低。可是epoll不存在这个问题,它只会对”活跃”的socket进行操 做—这是由于在内核实现中epoll是根据每一个fd上面的callback函数实现的。那么,只有”活跃”的socket才会主动的去调用 callback函数,其余idle状态socket则不会,在这点上,epoll实现了一个”伪”AIO,由于这时候推进力在os内核。在一些 benchmark中,若是全部的socket基本上都是活跃的—好比一个高速LAN环境,epoll并不比select/poll有什么效率,相 反,若是过多使用epoll_ctl,效率相比还有稍微的降低。可是一旦使用idle connections模拟WAN环境,epoll的效率就远在select/poll之上了。

  • 使用mmap加速内核与用户空间的消息传递。

        这 点实际上涉及到epoll的具体实现了。不管是select,poll仍是epoll都须要内核把FD消息通知给用户空间,如何避免没必要要的内存拷贝就很 重要,在这点上,epoll是经过内核于用户空间mmap同一块内存实现的。而若是你想我同样从2.5内核就关注epoll的话,必定不会忘记手工 mmap这一步的。

  • 内核微调

         这一点其实不算epoll的优势了,而是整个linux平台的优势。也许你能够怀疑linux平台,可是你没法回避linux平台赋予你微调内核的能力。好比,内核TCP/IP协 议栈使用内存池管理sk_buff结构,那么能够在运行时期动态调整这个内存pool(skb_head_pool)的大小— 经过echo XXXX>/proc/sys/net/core/hot_list_length完成。再好比listen函数的第2个参数(TCP完成3次握手 的数据包队列长度),也能够根据你平台内存大小动态调整。更甚至在一个数据包面数目巨大但同时每一个数据包自己大小却很小的特殊系统上尝试最新的NAPI网卡驱动架构。

    (epoll内容,参考epoll_互动百科)

 

4.   Nginx优化

1. 编译安装过程优化

1).减少Nginx编译后的文件大小

在编译Nginx时,默认以debug模式进行,而在debug模式下会插入不少跟踪和ASSERT之类的信息,编译完成后,一个Nginx要有好几兆字节。而在编译前取消Nginx的debug模式,编译完成后Nginx只有几百千字节。所以能够在编译以前,修改相关源码,取消debug模式。具体方法以下:

在Nginx源码文件被解压后,找到源码目录下的auto/cc/gcc文件,在其中找到以下几行:

 

 
  1. # debug  
  2. CFLAGS=”$CFLAGS -g” 

注释掉或删掉这两行,便可取消debug模式。

2.为特定的CPU指定CPU类型编译优化

在编译Nginx时,默认的GCC编译参数是“-O”,要优化GCC编译,可使用如下两个参数:

 

 
  1. --with-cc-opt='-O3' 
  2. --with-cpu-opt=CPU  #为特定的 CPU 编译,有效的值包括:
    pentium, pentiumpro, pentium3, # pentium4, athlon, opteron, amd64, sparc32, sparc64, ppc64 

要肯定CPU类型,能够经过以下命令:

 

 
  1. [root@localhost home]#cat /proc/cpuinfo | grep "model name" 

2. 利用TCMalloc优化Nginx的性能

TCMalloc的全称为Thread-Caching Malloc,是谷歌开发的开源工具google-perftools中的一个成员。与标准的glibc库的Malloc相比,TCMalloc库在内存分配效率和速度上要高不少,这在很大程度上提升了服务器在高并发状况下的性能,从而下降了系统的负载。下面简单介绍如何为Nginx添加TCMalloc库支持。

要安装TCMalloc库,须要安装libunwind(32位操做系统不须要安装)和google-perftools两个软件包,libunwind库为基于64位CPU和操做系统的程序提供了基本函数调用链和函数调用寄存器功能。下面介绍利用TCMalloc优化Nginx的具体操做过程。

1).安装libunwind库

能够从http://download.savannah.gnu.org/releases/libunwind下载相应的libunwind版本,这里下载的是libunwind-0.99-alpha.tar.gz。安装过程以下:

 

 
  1. [root@localhost home]#tar zxvf libunwind-0.99-alpha.tar.gz  
  2. [root@localhost home]# cd libunwind-0.99-alpha/  
  3. [root@localhost libunwind-0.99-alpha]#CFLAGS=-fPIC ./configure  
  4. [root@localhost libunwind-0.99-alpha]#make CFLAGS=-fPIC  
  5. [root@localhost libunwind-0.99-alpha]#make CFLAGS=-fPIC install 

2).安装google-perftools

能够从http://google-perftools.googlecode.com下载相应的google-perftools版本,这里下载的是google-perftools-1.8.tar.gz。安装过程以下:

 

 
  1. [root@localhost home]#tar zxvf google-perftools-1.8.tar.gz  
  2. [root@localhost home]#cd google-perftools-1.8/  
  3. [root@localhost google-perftools-1.8]# ./configure  
  4. [root@localhost google-perftools-1.8]#make && make install  
  5. [root@localhost google-perftools-1.8]#echo "/usr/
    local/lib" 
    > /etc/ld.so.conf.d/usr_local_lib.conf  
  6. [root@localhost google-perftools-1.8]# ldconfig 

至此,google-perftools安装完成。

3).从新编译Nginx

为了使Nginx支持google-perftools,须要在安装过程当中添加“–with-google_perftools_module”选项从新编译Nginx。安装代码以下:

 

 
  1. [root@localhostnginx-0.7.65]#./configure \  
  2. >--with-google_perftools_module --with-http_stub_status_module  --prefix=/opt/nginx  
  3. [root@localhost nginx-0.7.65]#make  
  4. [root@localhost nginx-0.7.65]#make install 

到这里Nginx安装完成。

4).为google-perftools添加线程目录

建立一个线程目录,这里将文件放在/tmp/tcmalloc下。操做以下:

 

 
  1. [root@localhost home]#mkdir /tmp/tcmalloc  
  2. [root@localhost home]#chmod 0777 /tmp/tcmalloc 

5).修改Nginx主配置文件

修改nginx.conf文件,在pid这行的下面添加以下代码:

 

 
  1. #pid        logs/nginx.pid;  
  2. google_perftools_profiles /tmp/tcmalloc; 

接着,重启Nginx便可完成google-perftools的加载。

6).验证运行状态

为了验证google-perftools已经正常加载,可经过以下命令查看:

 

 
  1. [root@ localhost home]# lsof -n | grep tcmalloc  
  2. nginx      2395 nobody   9w  REG    8,8       0    1599440 /tmp/tcmalloc.2395  
  3. nginx      2396 nobody   11w REG   8,8       0    1599443 /tmp/tcmalloc.2396  
  4. nginx      2397 nobody   13w REG  8,8        0    1599441  /tmp/tcmalloc.2397  
  5. nginx     2398 nobody    15w REG  8,8     0    1599442 /tmp/tcmalloc.2398 

因为在Nginx配置文件中设置worker_processes的值为4,所以开启了4个Nginx线程,每一个线程会有一行记录。每一个线程文件后面的数字值就是启动的Nginx的pid值。

至此,利用TCMalloc优化Nginx的操做完成。

3.Nginx内核参数优化

内核参数的优化,主要是在Linux系统中针对Nginx应用而进行的系统内核参数优化。

下面给出一个优化实例以供参考。

 

 
  1. net.ipv4.tcp_max_tw_buckets = 6000 
  2. net.ipv4.ip_local_port_range = 1024 65000  
  3. net.ipv4.tcp_tw_recycle = 1 
  4. net.ipv4.tcp_tw_reuse = 1 
  5. net.ipv4.tcp_syncookies = 1 
  6. net.core.somaxconn = 262144 
  7. net.core.netdev_max_backlog = 262144 
  8. net.ipv4.tcp_max_orphans = 262144 
  9. net.ipv4.tcp_max_syn_backlog = 262144 
  10. net.ipv4.tcp_synack_retries = 1 
  11. net.ipv4.tcp_syn_retries = 1 
  12. net.ipv4.tcp_fin_timeout = 1 
  13. net.ipv4.tcp_keepalive_time = 30 

将上面的内核参数值加入/etc/sysctl.conf文件中,而后执行以下命令使之生效:

 
  1. [root@ localhost home]#/sbin/sysctl -p 

下面对实例中选项的含义进行介绍:

net.ipv4.tcp_max_tw_buckets :选项用来设定timewait的数量,默认是180 000,这里设为6000。

net.ipv4.ip_local_port_range:选项用来设定容许系统打开的端口范围。在高并发状况不然端口号会不够用。

net.ipv4.tcp_tw_recycle:选项用于设置启用timewait快速回收.

net.ipv4.tcp_tw_reuse:选项用于设置开启重用,容许将TIME-WAIT sockets从新用于新的TCP链接。

net.ipv4.tcp_syncookies:选项用于设置开启SYN Cookies,当出现SYN等待队列溢出时,启用cookies进行处理。

net.core.somaxconn:选项的默认值是128, 这个参数用于调节系统同时发起的tcp链接数,在高并发的请求中,默认的值可能会致使连接超时或者重传,所以,须要结合并发请求数来调节此值。

net.core.netdev_max_backlog:选项表示当每一个网络接口接收数据包的速率比内核处理这些包的速率快时,容许发送到队列的数据包的最大数目。

net.ipv4.tcp_max_orphans:选项用于设定系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上。若是超过这个数字,孤立链接将当即被复位并打印出警告信息。这个限制只是为了防止简单的DoS攻击。不能过度依靠这个限制甚至人为减少这个值,更多的状况下应该增长这个值。

net.ipv4.tcp_max_syn_backlog:选项用于记录那些还没有收到客户端确认信息的链接请求的最大值。对于有128MB内存的系统而言,此参数的默认值是1024,对小内存的系统则是128。

net.ipv4.tcp_synack_retries参数的值决定了内核放弃链接以前发送SYN+ACK包的数量。

net.ipv4.tcp_syn_retries选项表示在内核放弃创建链接以前发送SYN包的数量。

net.ipv4.tcp_fin_timeout选项决定了套接字保持在FIN-WAIT-2状态的时间。默认值是60秒。正确设置这个值很是重要,有时即便一个负载很小的Web服务器,也会出现大量的死套接字而产生内存溢出的风险。

net.ipv4.tcp_syn_retries选项表示在内核放弃创建链接以前发送SYN包的数量。

若是发送端要求关闭套接字,net.ipv4.tcp_fin_timeout选项决定了套接字保持在FIN-WAIT-2状态的时间。接收端能够出错并永远不关闭链接,甚至意外宕机。

net.ipv4.tcp_fin_timeout的默认值是60秒。须要注意的是,即便一个负载很小的Web服务器,也会出现由于大量的死套接字而产生内存溢出的风险。FIN-WAIT-2的危险性比FIN-WAIT-1要小,由于它最多只能消耗1.5KB的内存,可是其生存期长些。

net.ipv4.tcp_keepalive_time选项表示当keepalive启用的时候,TCP发送keepalive消息的频度。默认值是2(单位是小时)。

4. PHP-FPM的优化

若是您高负载网站使用PHP-FPMFastCGI,这些技巧也许对您有用:

1)增长FastCGI进程数

PHP FastCGI子进程数调到100或以上,4G内存的服务器上200就能够建议经过压力测试获取最佳值。

2)增长 PHP-FPM打开文件描述符的限制

标签rlimit_files用于设置PHP-FPM对打开文件描述符的限制,默认值为1024。这个标签的值必须和Linux内核打开文件数关联起来,例如,要将此值设置为65 535,就必须在Linux命令行执行“ulimit -HSn 65536”。

       而后 增长 PHP-FPM打开文件描述符的限制:
     # vi /path/to/php-fpm.conf
    找到
“<valuename="rlimit_files">1024</value>”
1024更改成 4096或者更高
.
重启 PHP-FPM.

       ulimit -n 要调整为65536甚至更大。如何调这个参数,能够参考网上的一些文章。命令行下执行 ulimit -n65536便可修改。若是不能修改,须要设置  /etc/security/limits.conf,加入

* hard nofile65536

* soft nofile 65536



         3)适当增长max_requests

    标签max_requests指明了每一个children最多处理多少个请求后便会被关闭,默认的设置是500。

    <value name="max_requests"> 500 </value>

   


4. nginx.conf的参数优化

nginx要开启的进程数 通常等于cpu的总核数 其实通常状况下开4个或8个就能够。

每一个nginx进程消耗的内存10兆的模样

worker_cpu_affinity
仅适用于linux,使用该选项能够绑定worker进程和CPU(2.4内核的机器用不了)

假如是8 cpu 分配以下:
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000

00100000 01000000 10000000

nginx可使用多个worker进程,缘由以下:

to use SMP 
to decrease latency when workers blockend on disk I/O 
to limit number of connections per process when select()/poll() is

used The worker_processes and worker_connections from the event sections

allows you to calculate maxclients value: k max_clients = worker_processes * worker_connections

worker_rlimit_nofile 102400;

每一个nginx进程打开文件描述符最大数目 配置要和系统的单进程打开文件数一致,linux 2.6内核下开启文件打开数为65535,worker_rlimit_nofile就相应应该填写65535 nginx调度时分配请求到进程并非那么的均衡,假如超过会返回502错误。我这里写的大一点

use epoll

Nginx使用了最新的epoll(Linux 2.6内核)和kqueue(freebsd)网络I/O模型,而Apache则使用的是传统的select模型。

处理大量的链接的读写,Apache所采用的select网络I/O模型很是低效。在高并发服务器中,轮询I/O是最耗时间的操做 目前Linux下可以承受高并发

访问的Squid、Memcached都采用的是epoll网络I/O模型。

worker_connections 65535;
每一个工做进程容许最大的同时链接数 (Maxclient = work_processes * worker_connections)

keepalive_timeout 75

keepalive超时时间

这里须要注意官方的一句话:
The parameters can differ from each other. Line Keep-Alive:

timeout=time understands Mozilla and Konqueror. MSIE itself shuts

keep-alive connection approximately after 60 seconds.


client_header_buffer_size 16k
large_client_header_buffers 4 32k

客户请求头缓冲大小 
nginx默认会用client_header_buffer_size这个buffer来读取header值,若是header过大,它会使用large_client_header_buffers来读取

若是设置太小HTTP头/Cookie过大 会报400 错误 nginx 400 bad request
求行若是超过buffer,就会报HTTP 414错误(URI Too Long) nginx接受最长的HTTP头部大小必须比其中一个buffer大,不然就会报400的HTTP错误(Bad Request)。

open_file_cache max 102400

使用字段:http, server, location 这个指令指定缓存是否启用,若是启用,将记录文件如下信息: ·打开的文件描述符,大小信息和修改时间. ·存在的目录信息. ·在搜索文件过程当中的错误信息 -- 没有这个文件,没法正确读取,参考open_file_cache_errors 指令选项:
·max - 指定缓存的最大数目,若是缓存溢出,最长使用过的文件(LRU)将被移除
例: open_file_cache max=1000 inactive=20s; open_file_cache_valid 30s; open_file_cache_min_uses 2; open_file_cache_errors on;

open_file_cache_errors
语法:open_file_cache_errors on | off 默认值:open_file_cache_errors off 使用字段:http, server, location 这个指令指定是否在搜索一个文件是记录cache错误.

open_file_cache_min_uses

语法:open_file_cache_min_uses number 默认值:open_file_cache_min_uses 1 使用字段:http, server, location 这个指令指定了在open_file_cache指令无效的参数中必定的时间范围内可使用的最小文件数,如 果使用更大的值,文件描述符在cache中老是打开状态.
open_file_cache_valid

语法:open_file_cache_valid time 默认值:open_file_cache_valid 60 使用字段:http, server, location 这个指令指定了什么时候须要检查open_file_cache中缓存项目的有效信息.


开启gzip
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_types text/plain application/x-javascript text/css

application/xml;
gzip_vary on;

缓存静态文件:

location ~* ^.+\.(swf|gif|png|jpg|js|css)$ {
root /usr/local/ku6/ktv/show.ku6.com/;
expires 1m;
}




5.   错误排查

一、Nginx 502 Bad Gateway

php-cgi进程数不够用、php执行时间长(mysql慢)、或者是php-cgi进程死掉,都会出现502错误

通常来讲Nginx 502 Bad Gateway和php-fpm.conf的设置有关,而Nginx 504 Gateway Time-out则是与nginx.conf的设置有关

1)、查看当前的PHP FastCGI进程数是否够用:

netstat -anpo | grep "php-cgi" | wc -l

  若是实际使用的“FastCGI进程数”接近预设的“FastCGI进程数”,那么,说明“FastCGI进程数”不够用,须要增大。

2)、部分PHP程序的执行时间超过了Nginx的等待时间,能够适当增长

     nginx.conf配置文件中FastCGI的timeout时间,例如:

http {
    ......
    fastcgi_connect_timeout 300;
    fastcgi_send_timeout 300;
    fastcgi_read_timeout 300;

    ......
}


二、413 Request Entity Too Large
     解决:增大client_max_body_size

    client_max_body_size:指令指定容许客户端链接的最大请求实体大小,它出如今请求头部的Content-Length字段. 若是请求大于指定的值,客户端将收到一个"Request Entity Too Large" (413)错误. 记住,浏览器并不知道怎样显示这个错误.

    php.ini中增大
post_max_size 和upload_max_filesize

3 Ngnix error.log出现:upstream sent too big header while reading response header from upstream错误

1)若是是nginx反向代理
   proxy是nginx做为client转发时使用的,若是header过大,超出了默认的1k,就会引起上述的upstream sent too big header (说白了就是nginx把外部请求给后端server,后端server返回的header  太大nginx处理不过来就致使了。

  server {
        listen       80;
        server_name  *.xywy.com ;

        large_client_header_buffers 4 16k;

        location / {

          #添加这3行 
           proxy_buffer_size 64k;
           proxy_buffers   32 32k;
           proxy_busy_buffers_size 128k;

           proxy_set_header Host $host;
           proxy_set_header X-Real-IP       $remote_addr;
           proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for;

    }

}         

 

2) 若是是 nginx+PHPcgi 

  错误带有 upstream: "fastcgi://127.0.0.1:9000"。就该 

  多加:

  fastcgi_buffer_size 128k;
  fastcgi_buffers 4 128k;

server {
        listen       80;
        server_name  ddd.com;
        index index.html index.htm index.php;
   
        client_header_buffer_size 128k;
        large_client_header_buffers 4 128k;
        proxy_buffer_size 64k;
        proxy_buffers 8 64k;
        fastcgi_buffer_size 128k;
        fastcgi_buffers 4 128k;

        location / {

          ......

        }

}         


6.   Nginx的php漏洞

漏洞介绍:nginx是一款高性能的web服务器,使用很是普遍,其不只常常被用做反向代理,也能够很是好的支持PHP的运行。80sec发现其中存在一个较为严重的安全问题,默认状况下可能致使服务器错误的将任何类型的文件以PHP的方式进行解析,这将致使严重的安全问题,使得恶意的攻击者可能攻陷支持php的nginx服务器。


漏洞分析:nginx默认以cgi的方式支持php的运行,譬如在配置文件当中能够以


location ~ .php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi_params;
}

的方式支持对php的解析,location对请求进行选择的时候会使用URI环境变量进行选择,其中传递到后端Fastcgi的关键变量SCRIPT_FILENAME由nginx生成的$fastcgi_script_name决定,而经过分析能够看到$fastcgi_script_name是直接由URI环境变量控制的,这里就是产生问题的点。而为了较好的支持PATH_INFO的提取,在PHP的配置选项里存在cgi.fix_pathinfo选项,其目的是为了从SCRIPT_FILENAME里取出真正的脚本名。
那么假设存在一个http://www.80sec.com/80sec.jpg,咱们以以下的方式去访问

http://www.80sec.com/80sec.jpg/80sec.php


将会获得一个URI

/80sec.jpg/80sec.php

通过location指令,该请求将会交给后端的fastcgi处理,nginx为其设置环境变量SCRIPT_FILENAME,内容为

/scripts/80sec.jpg/80sec.php

而在其余的webserver如lighttpd当中,咱们发现其中的SCRIPT_FILENAME被正确的设置为

/scripts/80sec.jpg

因此不存在此问题。
后端的fastcgi在接受到该选项时,会根据fix_pathinfo配置决定是否对SCRIPT_FILENAME进行额外的处理,通常状况下若是不对fix_pathinfo进行设置将影响使用PATH_INFO进行路由选择的应用,因此该选项通常配置开启。Php经过该选项以后将查找其中真正的脚本文件名字,查找的方式也是查看文件是否存在,这个时候将分离出SCRIPT_FILENAME和PATH_INFO分别为

/scripts/80sec.jpg和80sec.php

最后,以/scripts/80sec.jpg做为这次请求须要执行的脚本,攻击者就能够实现让nginx以php来解析任何类型的文件了。

POC: 访问一个nginx来支持php的站点,在一个任何资源的文件如robots.txt后面加上/80sec.php,这个时候你能够看到以下的区别:

访问http://www.80sec.com/robots.txt

HTTP/1.1 200 OK
Server: nginx/0.6.32
Date: Thu, 20 May 2010 10:05:30 GMT
Content-Type: text/plain
Content-Length: 18
Last-Modified: Thu, 20 May 2010 06:26:34 GMT
Connection: keep-alive
Keep-Alive: timeout=20
Accept-Ranges: bytes

访问访问http://www.80sec.com/robots.txt/80sec.php

HTTP/1.1 200 OK
Server: nginx/0.6.32
Date: Thu, 20 May 2010 10:06:49 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
Keep-Alive: timeout=20
X-Powered-By: PHP/5.2.6

其中的Content-Type的变化说明了后端负责解析的变化,该站点就可能存在漏洞。

漏洞厂商:http://www.nginx.org

解决方案:

咱们已经尝试联系官方,可是此前你能够经过如下的方式来减小损失

关闭cgi.fix_pathinfo为0

或者

if ( $fastcgi_script_name ~ ..*/.*php ) {
return 403;
}

PS: 鸣谢laruence大牛在分析过程当中给的帮助

相关文章
相关标签/搜索