目录
信号驱动式 I/O 模型 (signal-driven IO)
FastCGI实战案例 : Nginx与php-fpm在同一服务器
Web服务器基础介绍
正常情况下的单次web服务器访问流程
1、客户端发起请求:用户在浏览器中输入网址或点击链接等操作后,浏览器会根据目标网址构建一个 HTTP 请求报文,包含请求方法(如 GET、POST 等)、请求头(如用户代理、接受的文件类型等)和请求体(如果有数据需要提交的话)
2、网络传输:请求通过网络传输,依据互联网的路由规则,经过一系列的网络设备(如路由器、交换机等),最终找到目标 web 服务器的网络地址
3、服务器接收请求:web 服务器接收到请求后,会对请求进行解析,提取出请求的关键信息,如请求的资源路径等
4、服务器处理请求:根据请求的资源路径,服务器在自身的文件系统或应用程序中查找对应的资源或执行相应的业务逻辑处理(如从数据库查询数据、进行数据计算等)
5、服务器响应:服务器将处理结果封装成 HTTP 响应报文,包含响应状态码(表示请求是否成功等信息)、响应头(如设置内容类型、缓存控制等)和响应体(包含请求的资源内容或处理结果数据)
6、网络传输返回:响应报文通过网络原路返回给客户端
7、客户端接收响应:浏览器接收到响应后,根据响应头中的信息进行相应的处理,如解析响应体中的 HTML、CSS、JavaScript 等内容,并进行页面渲染展示给用户
Apache 经典的 Web服务端
Apache prefork 模型
预派生模式,有一个主控制进程,然后生成多个子进程,使用select模型,最大并发1024
每个子进程有一个独立的线程响应用户请求
相对比较占用内存,但是比较稳定,可以设置最大和最小进程数
是最古老的一种模式,也是最稳定的模式,适用于访问量不是很大的场景
优点:
稳定性高,兼容性好,对CPU多核利用较直接
缺点:
每个用户请求需要对应开启一个进程,占用资源较多,并发性差,不适用于高并发场景
Apache work模型
一种多进程和多线程混合的模型
有一个控制进程,启动多个子进程
每个子进程里面包含固定的线程
使用线程程来处理请求
当线程不够使用的时候会再启动一个新的子进程,然后在进程里面再启动线程处理请求,
由于其使用了线程处理请求,因此可以承受更高的并发
优点:
相比prefork 占用的内存较少,可以同时处理更多的请求
缺点:
使用keepalive的长连接方式,某个线程会一直被占据,即使没有传输数据,也需要一直等待到超时才会被释放。如果过多的线程,被这样占据,也会导致在高并发场景下的无服务线程可用(该问题在 prefork模式下,同样会发生)
Apache event模型
Apache中最新的模式,2012年发布的apache 2.4.X系列正式支持event 模型,属于事件驱动模型(epoll)
每个进程响应多个请求,在现在版本里的已经是稳定可用的模式
它和worker模式很像,最大的区别在于,它解决了keepalive场景下长期被占用的线程的资源浪费问题 (某些线程因为被keepalive,空挂在哪里等待,中间几乎没有请求过来,甚至等到超时)
event MPM中,会有一个专门的线程来管理这些keepalive类型的线程
当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放。这样增强了高并发场 景下的请求处理能力
优点:
单线程响应多请求,占据更少的内存,高并发下表现更优秀,会有一个专门的线程来管理keep-alive类型的线程,当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放
缺点:
没有线程安全控制
服务端的I/O流程
I/O在计算机中指Input/Output, IOPS (Input/Output Per Second)即每秒的输入输出量(或读写次数), 是衡量磁盘性能的主要指标之一
IOPS是指单位时间内系统能处理的I/O请求数量,一般以每秒处理的 I/O请求数量为单位,I/O请求通常为读或写数据操作请求
服务器的I/O
磁盘I/O
网络I/O:一切皆文件,本质为对socket文件的读写
磁盘I/O
磁盘I/O是进程向内核发起系统调用,请求磁盘上的某个资源比如是html 文件或者图片,然后内核通过相 应的驱动程序将目标文件加载到内核的内存空间,加载完成之后把数据从内核内存再复制给进程内存, 如果是比较大的数据也需要等待时间
网络I/O
网络通信就是网络协议栈到用户空间进程的IO就是网络IO
网络I/O处理过程
获取请求数据,客户端与服务器建立连接发出请求,服务器接受请求
构建响应,当服务器接收完请求,并在用户空间处理客户端的请求,直到构建响应完成
返回数据,服务器将已构建好的响应再通过内核空间的网络 I/O 发还给客户端
I/O模型
I/O模型相关概念
同步/异步
关注的是消息通信机制,即调用者在等待一件事情的处理结果时,被调用者是否提供完成状态的通知
同步:synchronous,被调用者并不提供事件的处理结果相关的通知消息,需要调用者主动询问事情是否处理完成
异步:asynchronous,被调用者通过状态、通知或回调机制主动通知调用者被调用者的运行状态
阻塞/非阻塞
关注调用者在等待结果返回之前所处的状态
阻塞:blocking,指IO操作需要彻底完成后才返回到用户空间,调用结果返回之前,调用者被挂起,干不了别的事情
非阻塞:nonblocking,指IO操作被调用后立即返回给用户一个状态值,而无需等到IO操作彻底完成,在最终的调用结果返回之前,调用者不会被挂起,可以去做别的事情
网络I/O模型
阻塞型、非阻塞型、复用型、信号驱动型、异步
阻塞型 I/O 模型(blocking IO)
阻塞IO模型是最简单的I/O模型,用户线程在内核进行IO操作时被阻塞
用户线程通过系统调用read发起I/O读操作,由用户空间转到内核空间。内核等到数据包到达后,然 后将接收的数据拷贝到用户空间,完成read操作
用户需要等待read将数据读取到buffer后,才继续处理接收的数据。整个I/O请求的过程中,用户线 程是被阻塞的,这导致用户在发起IO请求时,不能做任何事情,对CPU的资源利用率不够
优点:
程序简单,在阻塞等待数据期间进程/线程挂起,基本不会占用 CPU 资源
缺点:
每个连接需要独立的进程/线程单独处理,当并发请求量大时为了维护程序,内存、线程切换开销 较apache 的preforck使用的是这种模式
同步阻塞:
程序向内核发送I/O请求后一直等待内核响应,如果内核处理请求的IO操作不能立即返回,则进程将一直等待并不再接受新的请求,并由进程轮询查看I/O是否完成,完成后进程将I/O结果返回给Client,在IO没有返回期间进程不能接受其他客户的请求,而且是有进程自己去查看I/O是否完成,这种方式简单,但是比较慢,用的比较少
非阻塞型 I/O 模型 (nonblocking IO)
用户线程发起IO请求时立即返回。但并未读取到任何数据,用户线程需要不断地发起IO请求,直到数据 到达后,才真正读取到数据,继续执行。即 “轮询”机制存在两个问题:如果有大量文件描述符都要等, 那么就得一个一个的read。这会带来大量的Context Switch(read是系统调用,每调用一次就得在用户 态和核心态切换一次)。轮询的时间不好把握。这里是要猜多久之后数据才能到。等待时间设的太长, 程序响应延迟就过大;设的太短,就会造成过于频繁的重试,干耗CPU而已,是比较浪费CPU的方式,一 般很少直接使用这种模型,而是在其他IO模型中使用非阻塞IO这一特性
优点:
可以在等待数据期间执行其他任务,提高系统的并发性和资源利用率,实现高效的多任务处理
适用于需要快速响应和处理大量并发连接的场景,如高并发的服务器端程序
缺点:
编程模型相对复杂、对于一些简单的、少量连接的应用场景,其性能优势可能不明显,甚至由于额外的复杂性导致性能不如传统的阻塞型 I/O
非阻塞:
程序向内核发送请I/O求后一直等待内核响应,如果内核处理请求的IO操作不能立即返回IO结 果,进程将不再等待,而且继续处理其他请求,但是仍然需要进程隔一段时间就要查看内核I/O是否完成
多路复用 I/O 型(I/O multiplexing)
多路复用IO指一个线程可以同时(实际是交替实现,即并发完成)监控和处理多个文件描述符对应各自 的IO,即复用同一个线程
一个线程之所以能实现同时处理多个IO,是因为这个线程调用了内核中的SELECT,POLL或EPOLL等系统调 用,从而实现多路复用IO
I/O multiplexing 主要包括:select,poll,epoll三种系统调用,select/poll/epoll的好处就在于单个 process就可以同时处理多个网络连接的IO
基本原理:
select/poll/epoll这个function会不断的轮询所负责的所有socket,当某个socket有数 据到达了,就通知用户进程
当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket, 当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从 kernel拷贝到用户进程
Apache prefork是此模式的select,worker是poll模式
IO多路复用(IO Multiplexing)
是一种机制,程序注册一组socket文件描述符给操作系统,表示“我要 监视这些fd是否有IO事件发生,有了就告诉程序处理”IO多路复用一般和NIO一起使用的。NIO和IO多路 复用是相对独立的。NIO仅仅是指IO API总是能立刻返回,不会被Blocking;而IO多路复用仅仅是操作系统 提供的一种便利的通知机制。操作系统并不会强制这俩必须得一起用,可以只用IO多路复用 + BIO,这时 还是当前线程被卡住。IO多路复用和NIO是要配合一起使用才有
优点:
可以基于一个阻塞对象,同时在多个描述符上等待就绪,而不是使用多个线程(每个文件描述 符一个线程),这样可以大大节省系统资源
缺点:
当连接数较少时效率相比多线程+阻塞 I/O 模型效率较低,可能延迟更大,因为单个连接处理 需要 2 次系统调用,占用时间会有增加
I/O多路复用适用场景:
当客户端处理多个描述符时(一般是交互式输入和网络套接口),必须使用I/O复用
当一个客户端同时处理多个套接字时,此情况可能的但很少出现
当一个服务器既要处理监听套接字,又要处理已连接套接字,一般也要用到I/O复用
当一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用
当一个服务器要处理多个服务或多个协议,一般要使用I/O复用
信号驱动式 I/O 模型 (signal-driven IO)
信号驱动I/O的意思就是进程现在不用傻等着,也不用去轮询。而是让内核在数据就绪时,发送信号通知进程
调用的步骤:
通过系统调用 sigaction ,并注册一个信号处理的回调函数,该调用会立即返回,然后主 程序可以继续向下执行,当有I/O操作准备就绪,即内核数据就绪时,内核会为该进程产生一个 SIGIO信 号,并回调注册的信号回调函数,这样就可以在信号回调函数中系统调用 recvfrom 获取数据,将用户进 程所需要的数据从内核空间拷贝到用户空间
优点:
等待数据报到达期间进程不被阻塞。用户主程序可以继续执行,只要等待来自信号处 理函数的通知
在信号驱动式 I/O 模型中,应用程序使用套接口进行信号驱动 I/O,并安装一个信号处理函数,进程继续 运行并不阻塞
在信号驱动式 I/O 模型中,应用程序使用套接口进行信号驱动 I/O,并安装一个信号处理函数,进程继续 运行并不阻塞
当数据准备好时,进程会收到一个 SIGIO 信号,可以在信号处理函数中调用 I/O 操作函数处理数据。优 点:线程并没有在等待数据时被阻塞,内核直接返回调用接收信号,不影响进程继续处理其他请求因此 可以提高资源的利用率
缺点:
信号 I/O 在大量 IO 操作时可能会因为信号队列溢出导致没法通知
异步阻塞:
程序进程向内核发送IO调用后,不用等待内核响应,可以继续接受其他请求,内核收到进程 请求后
进行的IO如果不能立即返回,就由内核等待结果,直到IO完成后内核再通知进程
异步 I/O 模型 (asynchronous IO)
异步I/O 与 信号驱动I/O最大区别在于,信号驱动是内核通知用户进程何时开始一个I/O操作,而异步I/O 是由内核通知用户进程I/O操作何时完成,两者有本质区别,相当于不用去饭店吃饭,直接点个外卖,把等待上菜的时间也给省了
相对于同步I/O,异步I/O不是顺序执行。用户进程进行aio_read系统调用之后,无论内核数据是否准备 好,都会直接返回给用户进程,然后用户态进程可以去做别的事情。等到socket数据准备好了,内核直 接复制数据给进程,然后从内核向进程发送通知。IO两个阶段,进程都是非阻塞的
信号驱动IO当内核通知触发信号处理程序时,信号处理程序还需要阻塞在从内核空间缓冲区拷贝数据到 用户空间缓冲区这个阶段,而异步IO直接是在第二个阶段完成后,内核直接通知用户线程可以进行后续 操作了
优点:
异步 I/O 能够充分利用 DMA 特性,让 I/O 操作与计算重叠
缺点:
要实现真正的异步 I/O,操作系统需要做大量的工作
目前 Windows 下通过 IOCP 实现了真正的 异步 I/O,在 Linux 系统下,Linux 2.6才引入,目前 AIO 并不完善,因此在 Linux 下实现高并发网络编 程时以 IO 复用模型模式+多线程任务的架构基本可以满足需求
Linux提供了AIO库函数实现异步,但是用的很少。目前有很多开源的异步IO库,例如libevent、libev、 libuv
异步非阻塞:
程序进程向内核发送IO调用后,不用等待内核响应,可以继续接受其他请求,内核调用的 IO如果不能立即返回,内核会继续处理其他事物,直到IO完成后将结果通知给内核,内核在将IO完成的 结果返回给进程,期间进程可以接受新的请求,内核也可以处理新的事物,因此相互不影响,可以实现 较大的同时并实现较高的IO复用,因此异步非阻塞使用最多的一种通信方式
五种I/O对比
这五种 I/O 模型中,越往后,阻塞越少,理论上效率也是最优前四种属于同步 I/O,因为其中真正的 I/O 操作(recvfrom)将阻塞进程/线程,只有异步 I/O 模型才与 POSIX 定义的异步 I/O 相匹配
I/O的常见实现
1、select
select库是在linux和windows平台都基本支持的 事件驱动模型库,并且在接口的定义也基本相同,只是 部分参数的含义略有差异,最大并发限制1024,是最早期的事件驱动模型
2、poll
在Linux 的基本驱动模型,windows不支持此驱动模型,是select的升级版,取消了最大的并发限制,在 编译nginx的时候可以使用--with-poll_module和--without-poll_module这两个指定是否编译select库
3、epoll
epoll是库是Nginx服务器支持的最高性能的事件驱动库之一,是公认的非常优秀的事件驱动模型,它和 select和poll有很大的区别,epoll是poll的升级版,但是与poll有很大的区别.epoll的处理方式是创建一个 待处理的事件列表,然后把这个列表发给内核,返回的时候在去轮询检查这个表,以判断事件是否发 生,epoll支持一个进程打开的最大事件描述符的上限是系统可以打开的文件的最大数,同时epoll库的 I/O效率不随描述符数目增加而线性下降,因为它只会对内核上报的“活跃”的描述符进行操作
4、kqueue
用于支持BSD系列平台的高校事件驱动模型,主要用在FreeBSD 4.1及以上版本、OpenBSD 2.0级以上版 本NetBSD级以上版本及Mac OS X 平台上,该模型也是poll库的变种,因此和epoll没有本质上的区别, 都是通过避免轮询操作提供效率
5、locp
Windows系统上的实现方式,对应第5种(异步I/O)模型
6、rtsig
不是一个常用事件驱动,最大队列1024,不是很常用
7、/dev/poll
用于支持unix衍生平台的高效事件驱动模型,主要在Solaris 平台、HP/UX,该模型是sun公司在开发 Solaris系列平台的时候提出的用于完成事件驱动机制的方案,它使用了虚拟的/dev/poll设备,开发人员 将要见识的文件描述符加入这个设备,然后通过ioctl()调用来获取事件通知,因此运行在以上系列平台的 时候请使用/dev/poll事件驱动机制
8、eventport
该方案也是sun公司在开发Solaris的时候提出的事件驱动库,只是Solaris 10以上的版本,该驱动库看防 止内核崩溃等情况的发生
Nginx 架构和安装
Nginx介绍
Nginx 是一款轻量级的高性能 Web 服务器、反向代理服务器以及电子邮件(IMAP/POP3)代理服务器
Nginx官网:nginx news
作为Web服务器:
能够高效地处理静态文件请求,如 HTML、CSS、JavaScript 文件以及图片等,速度极快,比传统的服务器在处理静态资源方面表现更出色
具有优秀的并发处理能力,能够同时处理大量的连接请求,这得益于其采用的事件驱动的异步非阻塞架构,在高并发场景下能保持稳定和高效
作为反向代理服务器:
可以将来自客户端的请求转发到后端的多台服务器上,实现负载均衡,提高系统的可用性和扩展性。例如,根据不同的负载策略将请求分发到不同的应用服务器上,确保每个服务器都能得到合理的利用,避免单点故障
能够隐藏后端服务器的真实 IP 地址和架构,增强了系统的安全性和保密性,同时也方便进行服务器的管理和维护
基础特性
模块化设计,较好的扩展性
高可靠性
支持热部署:不停机更新配置文件,升级版本,更换日志文件
低内存消耗:10000个keep-alive连接模式下的非活动连接,仅需2.5M内存
event-driven,aio,mmap,sendfile
Nginx架构
Nginx 的架构主要包含以下几个关键部分
模块化设计:
Nginx 由多个模块组成,包括核心模块和各种功能模块。核心模块负责处理最基本的网络事件和请求分发等核心功能。功能模块则提供丰富的特性,如 HTTP 模块处理 HTTP 请求相关的功能,包括请求解析、响应生成等;反向代理模块负责实现将请求转发到后端服务器等。各模块之间相对独立又协同工作,可根据需要进行灵活的配置和扩展
事件驱动模型:
Nginx 使用异步非阻塞的事件驱动模型来处理网络连接和请求。它基于操作系统提供的高效事件通知机制(如 epoll、kqueue 等),当一个连接有事件发生时(如可读、可写),Nginx 才会去处理该事件,而在等待事件的过程中不会阻塞进程,从而能够高效地处理大量并发连接
请求处理流程:
当 Nginx 接收到一个网络请求时,首先由其监听端口对应的事件处理器捕获到连接事件。核心模块会初步处理连接,建立连接上下文。然后,根据请求的类型(如 HTTP 请求),将请求传递给相应的模块进行进一步处理
在 HTTP 请求处理中,HTTP 模块会解析请求的头部信息,确定请求的资源路径等。如果配置了反向代理等功能,Nginx 会根据相应的规则将请求转发到后端服务器。后端服务器处理完请求后,将响应返回给 Nginx,Nginx 再将响应返回给客户端
进程模型:
Nginx 通常以多进程或多线程的方式运行。主进程负责管理和监控工作进程(在某些系统上也可能使用线程)。工作进程负责实际的请求处理。主进程可以根据需要启动、停止工作进程,实现热部署和故障恢复等功能。同时,多个工作进程之间相互独立,可以充分利用多核处理器的性能,提高系统的吞吐量
Nginx进程结构
Web请求机制
多进程方式:服务器每接收到一个客户端请求就有服务器的主进程生成一个子进程响应客户端,直 到用户关闭连接,这样的优势是处理速度快,子进程之间相互独立,但是如果访问过大会导致服务 器资源耗尽而无法提供请求
多线程方式:与多进程方式类似,但是每收到一个客户端请求会有服务进程派生出一个线程和此客 户端进行交互,一个线程的开销远远小于一个进程,因此多线程方式在很大程度减轻了web服务器 对系统资源的要求,但是多线程也有自己的缺点,即当多个线程位于同一个进程内工作的时候,可 以相互访问同样的内存地址空间,所以他们相互影响,一旦主进程挂掉则所有子线程都不能工作 了,IIS服务器使用了多线程的方式,需要间隔一段时间就重启一次才能稳定
Nginx是多进程组织模型,而且是一个由Master主进程和Worker工作进程组成
主进程(master process)的功能
对外接口:接收外部的操作(信号)
对内转发:根据外部的操作的不同,通过信号管理 Worker
监控:监控 worker 进程的运行状态,worker 进程异常终止后,自动重启 worker 进程
读取Nginx 配置文件并验证其有效性和正确性
建立、绑定和关闭socket连接
按照配置生成、管理和结束工作进程
接受外界指令,比如重启、升级及退出服务器等指令
不中断服务,实现平滑升级,重启服务并应用新的配置
开启日志文件,获取文件描述符
不中断服务,实现平滑升级,升级失败进行回滚处理
编译和处理perl脚本
工作进程(worker process)的功能
所有 Worker 进程都是平等的
实际处理:网络请求,由 Worker 进程处理
Worker进程数量:一般设置为核心数,充分利用CPU资源,同时避免进程数量过多,导致进程竞争 CPU资源
增加上下文切换的损耗
接受处理客户的请求
将请求依次送入各个功能模块进行处理
I/O调用,获取响应数据
与后端服务器通信,接收后端服务器的处理结果
缓存数据,访问缓存索引,查询和调用缓存数据
发送请求结果,响应客户的请求
接收主程序指令,比如重启、升级和退出等
Nginx模块介绍
核心模块:是 Nginx 服务器正常运行必不可少的模块,提供错误日志记录 、配置文件解析 、事件 驱动机制 、进程管理等核心功能
标准HTTP模块:提供 HTTP 协议解析相关的功能,比如: 端口配置 、 网页编码设置 、 HTTP响应头设置等等
可选HTTP模块:主要用于扩展标准的 HTTP 功能,让 Nginx 能处理一些特殊的服务,比如: Flash
多媒体传输 、解析 GeoIP 请求、网络传输压缩 、安全协议 SSL 支持等
邮件服务模块:主要用于支持 Nginx 的 邮件服务 ,包括对 POP3 协议、IMAP 协议和 SMTP协议的支持
Stream服务模块::实现反向代理功能,包括TCP协议代理
第三方模块:是为了扩展 Nginx 服务器应用,完成开发者自定义功能,比如: Json 支持、 Lua 支持等
Nginx安装
准备工作
一台版本为 rhel9.4 的虚拟机,网络模式默认为 NAT 模式
Nginx编译安装
[root@Nginx ~]# dnf install gcc pcre-devel zlib-devel openssl-devel -y
[root@Nginx nginx-1.24.0]# useradd -s /sbin/nologin -M nginx #创建名为nginx的新用户,指定默认登录shell为 /sbin/nologin ,并且不创建用户的家目录
[root@Nginx nginx]# tar zxf nginx-1.24.0.tar.gz
[root@Nginx nginx-1.24.0]# useradd -s /sbin/nologin -M nginx
[root@Nginx nginx-1.24.0]# ./configure --prefix=/usr/local/nginx \
#对nginx的编译环境和安装选项进行配置
# ./configure表示在当前目录下运行名为configure的脚本程序
#指定安装目录为 /usr/local/nginx
--user=nginx \ # 指定nginx运行用户
--group=nginx \ # 指定nginx运行组
--with-http_ssl_module \ # 支持https://
--with-http_v2_module \ # 支持http版本2
--with-http_realip_module \ # 支持ip透传
--with-http_stub_status_module \ # 支持状态页面
--with-http_gzip_static_module \ # 支持压缩
--with-pcre \ # 支持正则
--with-stream \ # 支持tcp反向代理
--with-stream_ssl_module \ # 支持tcp的ssl加密
--with-stream_realip_module # 支持tcp的透传ip
[root@Nginx nginx-1.24.0]# make && make install
#将编译生成的文件安装到指定目录;其中,make install是在make编译后执行的操作
Nginx 安装完成后,里面有四个主要的目录
[root@Nginx nginx-1.24.0]# ls /usr/local/nginx/
conf html logs sbin
目录名 | 解释 |
conf | 保存nginx所有的配置文件,其中nginx.conf是nginx服务器的最核心最主要的配置文件,其他 的.conf则是用来配置nginx相关的功能的,例如fastcgi功能使用的是fastcgi.conf和fastcgi_params 两个文件,配置文件一般都有一个样板配置文件,是以.default为后缀,使用时可将其复制并将default后缀 去掉即可 |
html | 中保存了nginx服务器的web文件,但是可以更改为其他目录保存web文件,另外还有一个50x的web 文件是默认的错误页面提示页面 |
logs | 保存nginx服务器的访问日志错误日志等日志,logs目录可以放在其他路径,比 如/var/logs/nginx里面 |
sbin | 保存nginx二进制启动脚本,可以接受不同的参数以实现不同的功能 |
Nginx平滑升级和回滚
为什么平滑升级
有时候我们需要对Nginx版本进行升级以满足对其功能的需求,例如添加新模块,需要新功能,而此时 Nginx又在跑着业务无法停掉,这时我们就可能选择平滑升级
平滑升级流程
将旧Nginx二进制文件换成新Nginx程序文件(注意先备份)
向master进程发送USR2信号
master进程修改pid文件名加上后缀.oldbin,成为nginx.pid.oldbin
master进程用新Nginx文件启动新master进程成为旧master的子进程,系统中将有新旧两个Nginx主 进程共同提供Web服务,当前新的请求仍然由旧Nginx的worker进程进行处理,将新生成的master进 程的PID存放至新生成的pid文件nginx.pid
向旧的Nginx服务进程发送WINCH信号,使旧的Nginx worker进程平滑停止
向旧master进程发送QUIT信号,关闭老master,并删除Nginx.pid.oldbin文件
如果发现升级有问题,可以回滚∶向老master发送HUP,向新master发送QUIT
案例
#先去官网下载对应新版本
#http://nginx.org
#使用tar命令对新版本进行解压,进入解压后的目录准备编译
[root@Nginx nginx]# tar zxf nginx-1.26.1.tar.gz
[root@Nginx nginx]# cd nginx-1.26.1/
#编译解压的新版本
[root@Nginx nginx-1.26.1]# ./configure --with-http_ssl_module --withhttp_v2_module --with-http_realip_module --with-http_stub_status_module --withhttp_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --
with-stream_realip_module
#使用make编译源代码
[root@Nginx nginx-1.26.1]# make
#查看版本
[root@Nginx nginx-1.26.1]# ll objs/nginx /usr/local/nginx/sbin/nginx
#对之前的nginx旧版本进行命令备份
[root@Nginx ~]# cd /usr/local/nginx/sbin/
[root@Nginx sbin]# cp nginx nginx.24
#复制新版本命令
[root@Nginx sbin]# \cp -f /root/nginx/nginx-1.26.1/objs/nginx
/usr/local/nginx/sbin
#检测
[root@Nginx sbin]# nginx -t
#触发指定nginx工作进程的平滑升级流程中的一个关键信号传递操作
[root@Nginx sbin]# kill -USR2 48732 #nginx worker ID #USR2信号用于触发nginx的平滑升级
#进程查看
[root@Nginx sbin]# ps aux | grep nginx
#回收旧版本
[root@Nginx sbin]# kill -WINCH 48732
[root@Nginx sbin]# ps aux | grep nginx
#检测版本信息
[root@Nginx sbin]# curl -I localhost
#回滚
#如果升级的版本发现问题需要回滚,可以重新拉起旧版本的worker
[root@Nginx sbin]# kill -HUP 48732
#进程查看
[root@Nginx sbin]# ps aux | grep nginx
[root@Nginx sbin]# kill -WINCH 52075
#进程查看
[root@Nginx sbin]# ps aux | grep nginx
#检测版本
[root@Nginx sbin]# curl -I localhost
Nginx核心配置
配置文件说明
Nginx配置文件组成部分
主配置文件:nginx.conf
子配置文件: include conf.d/*.conf
fastcgi,uwsgi,scgi 等协议相关的配置文件
mime.types:支持的mime类型,MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型,MIME消息能包含文本、图像、音频、视频以及其他应用程序专用的数据,是设定某 种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动 使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式
Nginx配置文件格式说明
配置文件由指令与指令块构成
每条指令以;分号结尾,指令与值之间以空格符号分隔
可以将多条指令放在同一行,用分号分隔即可,但可读性差,不推荐
指令块以{ }大括号将多条指令组织在一起,且可以嵌套指令块
include语句允许组合多个配置文件以提升可维护性
使用#符号添加注释,提高可读性
使用$符号使用变量
部分指令的参数支持正则表达式
Nginx主配置文件的配置指令方式
directive value [value2 ...];
注意:
1、指令必须以分号结尾
2、支持使用配置变量
内建变量:由Nginx模块引入,可直接引用
自定义变量:由用户使用set命令定义,格式: set variable_name value;
引用变量:$variable_name
主配置文件结构
main block:主配置段,即全局配置段,对http,mail都有效
#事件驱动相关的配置
event {
...
}
#http/https 协议相关配置段
http {
...
}
#默认配置文件不包括下面两个块
#mail 协议相关配置段
mail {
...
}
#stream 服务器相关配置段
stream {
...
}
默认的nginx.conf配置文件格式说明
#全局配置端,对全局生效,主要设置nginx的启动用户/组,启动的工作进程数量,工作模式,Nginx的PID路
径,日志路径等
user nginx nginx;
worker_processes 1; #启动工作进程数数量
events { #events #设置快,主要影响nginx服务器与用户的网络连接,比如是否允许同时接受多个网络连接,使用哪种事件驱动模型
#处理请求,每个工作进程可以同时支持的最大连接数,是否开启对多工作进程下的网络连接进行序列化等
worker_connections 1024; #设置单个nginx工作进程可以接受的最大并发,作为web服务器的时候最大并发数为 #worker_connections *
worker_processes,作为反向代理的时候为
#(worker_connections * worker_processes)/2
}
http { #http块是Nginx服务器配置中的重要部分,缓存、代理和日志格式定义等绝大多数功能和第三方模块都
#可以在这设置,http块可以包含多个server块,而一个server块中又可以包含多个location块
#server块可以配置文件引入、MIME-Type定义、日志自定义、是否启用sendfile、连接超时时间和 #单个链接的请求上限等
include mime.types;
default_type application/octet-stream;
sendfile on; #作为web服务器的时候打开sendfile加快静态文件传输,指定是否使用
#sendfile系统调用来传输文件
#sendfile系统调用在两个文件描述符之间直接传递数据(完全在内核中操作)
#从而避免了数据在内核缓冲区和用户缓冲区之间的拷贝,操作效率很高,被称之为零拷贝
#硬盘 >> kernel buffer (快速拷贝到kernelsocketbuffer) >>协议栈
keepalive_timeout 65; #长连接超时时间,单位是秒
server { #设置一个虚拟机主机,可以包含自己的全局快,同时也可以包含多个location模块
#比如本虚拟机监听的端口、本虚拟机的名称和IP配置,多个server 可以使用一个端口比如都使用 #80端口提供web服务
listen 80; #配置server监听的端口
server_name localhost; #本server的名称,当访问此名称的时候nginx会调用当前serevr内部的配置进程匹配
location / { #location其实是server的一个指令,为nginx服务器提供比较多而且灵活的指令
#都是在location中体现的,主要是基于nginx接受到的请求字符串
#对用户请求的UIL进行匹配,并对特定的指令进行处理
#包括地址重定向、数据缓存和应答控制等功能都是在这部分实现
#另外很多第三方模块的配置也是在location模块中配置
root html; #相当于默认页面的目录名称,默认是安装目录的相对路径,可以使用绝对路径配置
index index.html index.htm; #默认的页面文件名称
}
error_page 500 502 503 504 /50x.html; #错误页面的文件名称
location = /50x.html { #location处理对应的不同错误码的页面定义到/50x.html
#这个跟对应其server中定义的目录下
root html; #定义默认页面所在的目录
}
}
#和邮件相关的配置
#mail {
# ...
# } mail 协议相关配置段
#tcp代理配置,1.9版本以上支持
#stream {
# ...
# } s tream 服务器相关配置段
#导入其他路径的配置文件
#include /apps/nginx/conf.d/*.conf
}
全局配置
Nginx全局配置段常见的配置指令分类:
正常运行必备的配置
优化性能相关的配置
用于调试及定位问题相关的配置
事件驱动相关的配置
核心配置
基于不同的IP、不同的端口以及不用得域名实现不同的虚拟主机,依赖于核心模块 ngx_http_core_module实现
新建一个PC web站点
#编辑配置文件
vim /usr/local/nginx/conf/nginx.conf
# 设置单个nginx工作进程能够同时建立的最大连接数
#并指定nginx使用的事件模型
events {
worker_connections 12345;
use epoll;
}
#在配置文件最后添加
#使用include关键字,指定包含的配置文件的路径和模式
include /apps/nginx/conf/conf.d/*.conf;
#创建虚拟主机网站配置
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
#写入内容
server {
listen 80;
server_name lee.timinglee.org;
root /data/web/html;
index index.html
}
[root@Nginx ~]# mkdir -p /webdata/nginx/timinglee.org/lee/html
[root@Nginx ~]# echo lee.timinglee.org > /webdata/nginx/timinglee.org/lee/html/index.html
[root@Nginx ~]# nginx -s reload
#浏览器访问测试
#需要在windows解析文件添加相应解析
www.timinglee.org
测试
root 与 alias
root:指定web的家目录,在定义location的时候,文件的绝对路径等于 root+location
alias:定义路径别名,会把访问的路径重新定义到其指定的路径,文档映射的另一种机制;仅能用于 location上下文,此指令使用较少
#编辑文件
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
#写入内容
server {
listen 80;
server_name www.timinglee.org;
root /data/web/html;
index index.html;
location /test1/ {
root /data/web;
}
}
[root@Nginx ~]# mkdir /data/web/test1 -p
[root@Nginx ~]# echo /data/web/test1 > /data/web/test1/index.html
#重新加载nginx配置
[root@Nginx ~]# nginx -s reload
#编辑文件
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
#写入内容
server {
listen 80;
server_name www.timinglee.org;
root /data/web/html;
index index.html;
location /test1/ {
root /data/web;
}
location /test2/ {
alias /data/web/test1; #当客户端请求的URL以/test2/开头时,nginx会将请求映射到/data/web/test1目录下查找相应的文件
}
}
#重新加载nginx配置
[root@Nginx ~]# nginx -s reload
测试
location的详细使用
在一个server中location配置段可存在多个,用于实现从uri到文件系统的路径映射;
ngnix会根据用户请求的URI来检查定义的所有location,按一定的优先级找出一个最佳匹配, 而后应用其配置在没有使用正则表达式的时候,nginx会先在server中的多个location选取匹配度最 高的一个uri
uri是用户请求的字符串,即域名后面的web文件路径
然后使用该location模块中的正则url和字符串,如果匹配成功就结束搜索,并使用此location处理此请求
#语法规则:
location [ = | ~ | ~* | ^~ ] uri { ... }
= #用于标准uri前,需要请求字串与uri精确匹配,大小敏感,如果匹配成功就停止向下匹配并立
即处理请求
^~ #用于标准uri前,表示包含正则表达式,并且匹配以指定的正则表达式开头
#对uri的最左边部分做匹配检查,不区分字符大小写
~ #用于标准uri前,表示包含正则表达式,并且区分大小写
~* #用于标准uri前,表示包含正则表达式,并且不区分大写
不带符号 #匹配起始于此uri的所有的uri
\ #用于标准uri前,表示包含正则表达式并且转义字符。可以将 . * ?等转义为普通符号
#匹配优先级从高到低:
=, ^~, ~/~*, 不带符号
示例
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
#写入内容
server {
listen 80;
server_name www.timinglee.org;
root /data/web/html;
index index.html;
location /test {
root /data/web2;
}
location = /test {
root /data/web1;
}
}
[root@Nginx ~]# mkdir /data/web1/test -p
[root@Nginx ~]# mkdir /data/web2/test -p
[root@Nginx ~]# echo web1 test > /data/web1/test/index.html
[root@Nginx ~]# echo web2 test > /data/web1/test/index.html
#重新加载nginx配置
[root@Nginx ~]# nginx -s reload
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
#写入内容
server {
linten 80;
server_name: www.timinglee.org;
root /data/web/html;
index index.html
location = /test {
root /data/web2;
}
location /test {
root /data/web1;
}
location ^~ t {
root /data/web1;
}
}
[root@Nginx ~]# mkdir -p /data/web1/lee
[root@Nginx ~]# mkdir -p /data/web1/test1
[root@Nginx ~]# mkdir -p /data/web1/tee
[root@Nginx ~]# echo test1 > /data/web1/test1/index.html
[root@Nginx ~]# echo lee > /data/web1/lee/index.html
[root@Nginx ~]# echo tee > /data/web1/tee/index.html
[root@Nginx ~]# nginx -s reload
测试
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
#写入内容
server {
listen 80;
server_name www.timinglee.org;
root /data/wdb/html;
index index.html;
#html结尾
location ~\.html$ {
root /data/web1;
}
}
[root@Nginx ~]# nginx -s reload
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
#写入内容
server {
listen 80;
server_name www.timinglee.org;
root /data/wdb/html;
index index.html;
#html结尾而且不区分大小写
location ~* \.HTML$ {
root /data/web1;
}
}
[root@Nginx ~]# nginx -s reload
测试优先级
[root@Nginx ~]# mkdir -p /data/web1
[root@Nginx ~]# mkdir -p /data/web2
[root@Nginx ~]# mkdir -p /data/web3
[root@Nginx ~]# mkdir -p /data/web4
[root@Nginx ~]# mkdir -p /data/web5
[root@Nginx ~]# mkdir -p /data/web1/test
[root@Nginx ~]# mkdir -p /data/web2/test
[root@Nginx ~]# mkdir -p /data/web3/test
[root@Nginx ~]# mkdir -p /data/web4/test
[root@Nginx ~]# mkdir -p /data/web5/test
[root@Nginx ~]# echo web1 > /data/web1/test/index.html
[root@Nginx ~]# echo web2 > /data/web2/test/index.html
[root@Nginx ~]# echo web3 > /data/web3/test/index.html
[root@Nginx ~]# echo web4 > /data/web4/test/index.html
[root@Nginx ~]# echo web5 > /data/web5/test/index.html
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
#写入内容
server {
listen 80;
server_name www.timinglee.org;
root /data/web/html;
index index.html;
location = /test/ {
root /data/web2;
}
location /test {
root /data/web1;
}
location ^~ /t {
root /data/web3;
}
location ~ .html$ {
root /data/web4;
}
location ~* .HTML$ {
root /data/web5;
}
}
[root@Nginx ~] nginx -s reload
Nginx 账户认证功能
[root@Nginx ~]# htpasswd -cm /usr/local/nginx/.htpasswd admin
New password:
Re-type new password:
Adding password for user admin
[root@Nginx ~]# cat /usr/local/nginx/.htpasswd
admin:$apr1zHeKyror$bFdyaBF8qjVg6z5SHyqfp0
lee:$apr1$1TL8iHFe$wuHUTEwIOsUzL4tJYZgb/
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
#写入内容
server {
listen 80;
server_name www.timinglee.org;
root /data/web/html;
index index.html;
location /login {
root /data/lee;
auth_basic "login password";
auth_basic_user_file "/usr/local/nginx/.htpasswd";
}
}
[root@Nginx ~]# nginx -s reload
Nginx自定义错误页面
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
#写入内容
server {
listen 80;
server_name www.timinglee.org;
root /data/web/html;
index index.html;
error_page 404 /40x.html;
location /lee {
root /data/lee;
auth_basic "login password";
autn_basic_user_file "/usr/local/nginx/.htpasswd";
}
location = /40x.html {
root /data/web/errorpage;
}
}
[root@Nginx ~]# mkdir -p /data/web/errorpage
[root@Nginx ~]# echo error page > /data/web/errorpage/40x.html
[root@Nginx ~]# nginx -s reload
Nginx自定义错误日志
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
#写入内容
server {
listen 80;
server_name www.timinglee.org;
root /data/web/html;
index index.html;
error_page 404 /40x.html;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
location /lee {
root /data/web;
auth_basic "login password";
auth_basic_user_file "/usr/local/nginx/.htpasswd";
}
location = /40x.html {
root /data/web/errorpage;
}
}
[root@Nginx ~]# mkdir /var/log/timinglee.org
[root@Nginx ~]# nginx -s reload
Nginx文件检测
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
#写入内容
server {
listen 80;
server_name www.timinglee.org;
root /data/web/html;
index index.html;
error_page 404 /40x.html;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
try_files $uri $uri.html $uri/index.html /error/default.html;
location /lee {
root /data/web;
auth_basic "login password";
auth_basic_user_file "/usr/local/nginx/.htpasswd";
}
location = /40x.html {
root /data/web/errorpage;
}
}
[root@Nginx ~]# nginx -s reload
[root@Nginx ~]# curl www.timinglee.org
www.timinglee.org
[root@Nginx ~]# rm -rf /data/web/html/index.html
[root@Nginx ~]# rm -rf /data/web/html/error/
#测试
[root@Nginx ~]# curl www.timinglee.org
<html>
<head><title>500 Internal Server Error</title></head>
<body>
<center><h1>500 Internal Server Error</h1></center>
<hr><center>nginx/1.26.2</center>
</body>
</html>
[root@Nginx ~]# mkdir /data/web/html/error -p
[root@Nginx ~]# echo error default > /data/web/html/error/default.html
#测试
[root@Nginx ~]# curl www.timinglee.org
error default
Nginx长链接控制
keepalive_timeout timeout [header_timeout]; #设定保持连接超时时长,0表示禁止长连接,默认为75s
#通常配置在http字段作为站点全局配置
keepalive_requests 数字; #在一次长连接上所允许请求的资源的最大数量
#默认为100次,建议适当调大,比如:500
测试
[root@Nginx ~]# telnet www.lee.timinglee.org 80
Trying 172.25.254.100...
Connected to www.timinglee.org.
Escape character is '^]'.
GET / HTTP/1.1
HOST: www.timinglee.org
HTTP/1.1 200 OK
Server: nginx/1.26.2
Date: Sun, 18 Aug 2024 20:00:02 GMT
Content-Type: text/html
Content-Length: 15
Last-Modified: Sun, 18 Aug 2024 19:54:52 GMT
Connection: keep-alive
ETag: "66c237ca8-12"
Accept-Ranges: bytes
www.timinglee.org
GET / HTTP/1.1
HOST: www.timinglee.org
HTTP/1.1 200 OK
Server: nginx/1.26.2
Date: Sun, 18 Aug 2024 20:00:16 GMT
Content-Type: text/html
Content-Length: 15
Last-Modified: Sun, 18 Aug 2024 19:54:52 GMT
Connection: keep-alive
ETag: "66c237ca8-12"
Accept-Ranges: bytes
www.timinglee.org
Connection closed by foreign host.
Nginx下载服务器
[root@Nginx ~]# mkdir /data/web/download
[root@Nginx ~]#
[root@Nginx ~]# dd if=/dev/zero of=/data/web/download/leefile bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.075944 s, 1.3 GB/s
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
#写入内容
server {
listen 80;
server_name www.timinglee.org;
root /data/web/html;
index index.html;
error_page 404 /40x.html;
error_log /var/log/qwert.org/error.log;
access_log /var/log/qwert.org/access.log;
try_files $uri $uri.html $uri/index.html /error/default.html;
location /lee {
root /data/web;
auth_basic "login password";
auth_basic_user_file "/usr/local/nginx/.htpasswd";
}
location = /40x.html {
root /data/web/errorpage;
}
location /download {
autoindex on;
autoindex_exact_size on;
autoindex_localtime on;
limit_rate 1024k;
}
}
Nginx高级配置
Nginx状态页
基于nginx 模块 ngx_http_stub_status_module 实现
在编译安装nginx的时候需要添加编译参数 --with-http_stub_status_module
否则配置完成之后监测会是提示法错误
注意:
状态页显示的是整个服务器的状态,而非虚拟主机的状态
#配置示例
location /nginx_status {
stub_status;
auth_basic "auth login";
auth_basic_user_file /apps/nginx/conf/.htpasswd;
allow 192.168.0.0/16;
allow 127.0.0.1;
deny all;
}
#状态页用于输出nginx的基本状态信息:
#输出信息示例:
Active connections: 291
server accepts handled requests
16630948 16630948 31070465
上面三个数字分别对应accepts,handled,requests三个值
Reading: 6 Writing: 179 Waiting: 106
Active connections: #当前处于活动状态的客户端连接数
#包括连接等待空闲连接数=reading+writing+waiting
accepts: #统计总值,Nginx自启动后已经接受的客户端请求连接的总数
handled: #统计总值,Nginx自启动后已经处理完成的客户端请求连接总数
#通常等于accepts,除非有因worker_connections限制等被拒绝的连接
requests: #统计总值,Nginx自启动后客户端发来的总的请求数
Reading: #当前状态,正在读取客户端请求报文首部的连接的连接数
#数值越大,说明排队现象严重,性能不足
Writing: #当前状态,正在向客户端发送响应报文过程中的连接数,数值越大,说明访问量很大
Waiting: #当前状态,正在等待客户端发出请求的空闲连接数
开启 keep-alive的情况下,这个值等于active – (reading+writing)
[root@Nginx conf.d]# vim status.conf
#写入内容
server {
listen 80;
server_name status.timinglee.org;
root /data/web/html;
index index.html;
location /status {
stub_status;
}
}
[root@Nginx conf.d]# nginx -s reload
#测试
#浏览器status.timinglee.org/status测试
Nginx压缩功能
Nginx支持对指定类型的文件进行压缩然后再传输给客户端,而且压缩还可以设置压缩比例,压缩后的文 件大小将比源文件显著变小,样有助于降低出口带宽的利用率,降低企业的IT支出,不过会占用相 应的CPU资源
Nginx对文件的压缩功能是依赖于模块 ngx_http_gzip_module,默认是内置模块
相关配置指令:
#启用或禁用gzip压缩,默认关闭
gzip on | off;
#压缩比由低到高从1到9,默认为1,值越高压缩后文件越小,但是消耗cpu比较高。基本设定未4或者5
gzip_comp_level 4;
#禁用IE6 gzip功能,早期的IE6之前的版本不支持压缩
gzip_disable "MSIE [1-6]\.";
#gzip压缩的最小文件,小于设置值的文件将不会压缩
gzip_min_length 1k;
#启用压缩功能时,协议的最小版本,默认HTTP/1.1
gzip_http_version 1.0 | 1.1;
#指定Nginx服务需要向服务器申请的缓存空间的个数和大小,平台不同,默认:32 4k或者16 8k;
gzip_buffers number size;
#指明仅对哪些类型的资源执行压缩操作;默认为gzip_types text/html,不用显示指定,否则出错
gzip_types mime-type ...;
#如果启用压缩,是否在响应报文首部插入“Vary: Accept-Encoding”,一般建议打开
gzip_vary on | off;
#预压缩,即直接从磁盘找到对应文件的gz后缀的式的压缩文件返回给用户,无需消耗服务器CPU
#注意: 来自于ngx_http_gzip_static_module模块
gzip_static on | off;
[root@Nginx conf.d]# vim /usr/local/nginx/conf/nginx.conf
keepalive_timeout 65 60;
keepalive_requests 2;
gzip on; #打开压缩功能
gzip_comp_level 5;
gzip_min_length 1k;
gzip_http_version 1.1;
gzip_vary on;
[root@Nginx conf.d]# echo hello timinglee > /data/web/html/small.html
[root@Nginx conf.d]# cat /usr/local/nginx/logs/access.log > /data/web/html/big.html
Nginx的变量
nginx的变量可以在配置文件中引用,作为功能判断或者日志等场景使用
变量可以分为内置变量和自定义变量
内置变量是由nginx模块自带,通过变量可以获取到众多的与客户端访问相关的值
内置变量
常用的内置变量
$remote_addr;
#存放了客户端的地址,注意是客户端的公网IP
$args;
#变量中存放了URL中的所有参数
#例如:https://search.jd.com/Search?keyword=手机&enc=utf-8
#返回结果为: keyword=手机&enc=utf-8
$is_args
#如果有参数为? 否则为空
$document_root;
#保存了针对当前资源的请求的系统根目录,例如:/webdata/nginx/timinglee.org/lee。
$document_uri;
#保存了当前请求中不包含参数的URI,注意是不包含请求的指令
#比如:http://lee.timinglee.org/var?\id=11111会被定义为/var
#返回结果为:/var
$host;
#存放了请求的host名称
limit_rate 10240;
echo $limit_rate;
#如果nginx服务器使用limit_rate配置了显示网络速率,则会显示,如果没有设置, 则显示0
$remote_port;
#客户端请求Nginx服务器时随机打开的端口,这是每个客户端自己的端口
$remote_user;
#已经经过Auth Basic Module验证的用户名
$request_body_file;
#做反向代理时发给后端服务器的本地资源的名称
$request_method;
#请求资源的方式,GET/PUT/DELETE等
$request_filename;
#当前请求的资源文件的磁盘路径,由root或alias指令与URI请求生成的文件绝对路径,
#如:webdata/nginx/timinglee.org/lee/var/index.html
$request_uri;
#包含请求参数的原始URI,不包含主机名,相当于:$document_uri?$args,
#例如:/main/index.do?id=20190221&partner=search
$scheme;
#请求的协议,例如:http,https,ftp等
$server_protocol;
#保存了客户端请求资源使用的协议的版本,例如:HTTP/1.0,HTTP/1.1,HTTP/2.0等
$server_addr;
#保存了服务器的IP地址
$server_name;
#虚拟主机的主机名
$server_port;
#虚拟主机的端口号
$http_user_agent;
#客户端浏览器的详细信息
$http_cookie;
#客户端的所有cookie信息
$cookie_<name>
#name为任意请求报文首部字部cookie的key名
$http_<name>
#name为任意请求报文首部字段,表示记录请求报文的首部字段,ame的对应的首部字段名需要为小写,如果有横线需要替换为下划线
[root@Nginx conf.d]# vim vars.conf
server {
listen 80;
server_name var.timinglee.org.org;
root /data/web/html;
index index.html;
location /var {
default_type text/html;
echo $remote_addr;
echo $args;
echo $is_args;
echo $document_root;
echo $document_uri;
echo $host;
echo $remote_port;
echo $remote_user;
echo $request_method;
echo $request_filename;
echo $request_uri;
echo $scheme;
echo $server_protocol;
echo $server_addr;
echo $server_name;
echo $server_port;
echo $http_user_agent;
echo $http_cookie;
echo $cookie_key2;
}
}
自定义变量
假如需要自定义变量名称和值,使用指令set $variable value;
#语法:
Syntax: set $variable value;
Default: —
Context: server, location, if
Nginx Rewrite 相关功能
Nginx服务器利用 ngx_http_rewrite_module 模块解析和处理rewrite请求
此功能依靠 PCRE(perl compatible regular expression),因此编译之前要安装PCRE库
rewrite是nginx服务器的重要功能之一,用于实现URL的重写,URL的重写是非常有用的功能 比如它可以在我们改变网站结构之后,不需要客户端修改原来的书签,也无需其他网站修改我们的 链接,就可以设置为访问
另外还可以在一定程度上提高网站的安全性
IF指令
用于条件匹配判断,并根据条件判断结果选择不同的Nginx配置,可以配置在server或location块中进行 配置,Nginx的if语法仅能使用if做单次判断,不支持使用if else或者if elif这样的多重判断
#语法
if (条件匹配) {
action
}
使用正则表达式对变量进行匹配,匹配成功时if指令认为条件为true,否则认为false,变量与表达式之间 使用以下符号链接:
= #比较变量和字符串是否相等,相等时if指令认为该条件为true,反之为false
!= #比较变量和字符串是否不相等,不相等时if指令认为条件为true,反之为false
~ #区分大小写字符,可以通过正则表达式匹配,满足匹配条件为真,不满足匹配条件为假
!~ #区分大小写字符,判断是否匹配,不满足匹配条件为真,满足匹配条件为假
~* #不区分大小写字符,可以通过正则表达式匹配,满足匹配条件为真,不满足匹配条件为假
!~* #不区分大小字符,判断是否匹配,满足匹配条件为假,不满足匹配条件为真
-f 和 !-f #判断请求的文件是否存在和是否不存在
-d 和 !-d #判断请求的目录是否存在和是否不存在
-x 和 !-x #判断文件是否可执行和是否不可执行
-e 和 !-e #判断请求的文件或目录是否存在和是否不存在(包括文件,目录,软链接)
#注意:
#如果$变量的值为空字符串或0,则if指令认为该条件为false,其他条件为true。
#nginx 1.0.1之前$变量的值如果以0开头的任意字符串会返回false
[root@Nginx conf.d]# vim vars.conf
server {
listen 80;
server_name var.timinglee.org.org;
root /data/web/html;
index index.html;
location /var {
default_type text/html;
echo $remote_addr;
echo $args;
echo $is_args;
echo $document_root;
echo $document_uri;
echo $host;
echo $remote_port;
echo $remote_user;
echo $request_method;
echo $request_filename;
echo $request_uri;
echo $scheme;
echo $server_protocol;
echo $server_addr;
echo $server_name;
echo $server_port;
echo $http_user_agent;
echo $http_cookie;
echo $cookie_key2;
}
location /test2 {
if ( !-e $request_filename ){
echo "$request_filename is not exist";
}
}
}
set指令
指定key并给其定义一个变量,变量可以调用Nginx内置变量赋值给key
另外set定义格式为set $key value,value可以是text, variables和两者的组合
location /break {
default_type text/html;
set $name lee;
echo $name;
break;
set $id 666;
echo $id;
}
break指令
用于中断当前相同作用域(location)中的其他Nginx配置
与该指令处于同一作用域的Nginx配置中,位于它前面的配置生效
位于后面的 ngx_http_rewrite_module 模块中指令就不再执行
Nginx服务器在根据配置处理请求的过程中遇到该指令的时候,回到上一层作用域继续向下读取配置,、
该指令可以在server块和locationif块中使用
注意:
如果break指令在location块中后续指令还会继续执行,只是不执行ngx_http_rewrite_module 模块的指令,其它指令还会执行
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
#内容
location /break {
default_type text/html;
set $name lee;
echo $name;
if ( $http_user_agent = curl ) {
break;
}
break;
set $id 666;
echo $id;
}
return指令
return用于完成对请求的处理,并直接向客户端返回响应状态码,比如:可以指定重定向URL(对于特殊重 定向状态码,301/302等) 或者是指定提示文本内容(对于特殊状态码403/500等),处于此指令后的所有配 置都将不被执行,return可以在server、if 和 location块进行配置
#语法
return code; #返回给客户端指定的HTTP状态码
return code [text]; #返回给客户端的状态码及响应报文的实体内容
#可以调用变量,其中text如果有空格,需要用单或双引号
return code URL; #返回给客户端的URL地址
location /return {
default_type text/html;
if ( !-e $request_filename){
return 301 http://www.baidu.com;
}
echo "$request_filename is exist";
}
rewritr指令
通过正则表达式的匹配来改变URI,可以同时存在一个或多个指令,按照顺序依次对URI进行匹配, rewrite主要是针对用户请求的URL或者是URI做具体处理
#语法
rewrite regex replacement [flag];
rewrite将用户请求的URI基于regex所描述的模式进行检查,匹配到时将其替换为表达式指定的新的URI
注意:
如果在同一级配置块中存在多个rewrite规则,那么会自下而下逐个检查;被某条件规则替换完成 后,会重新一轮的替换检查,隐含有循环机制,但不超过10次;如果超过,提示500响应码,[flag]所表示的 标志位用于控制此循环机制
如果替换后的URL是以http://或https://开头,则替换结果会直接以重定向返回给客户端, 即永久重定向 301
正则表达式格式
. #匹配除换行符以外的任意字符
\w #匹配字母或数字或下划线或汉字
\s #匹配任意的空白符
\d #匹配数字
\b #匹配单词的开始或结束
^ #匹配字付串的开始
$ #匹配字符串的结束
* #匹配重复零次或更多次
+ #匹配重复一次或更多次
? #匹配重复零次或一次
(n) #匹配重复n次
{n,} #匹配重复n次或更多次
{n,m} #匹配重复n到m次
*? #匹配重复任意次,但尽可能少重复
+? #匹配重复1次或更多次,但尽可能少重复
?? #匹配重复0次或1次,但尽可能少重复
{n,m}? #匹配重复n到m次,但尽可能少重复
{n,}? #匹配重复n次以上,但尽可能少重复
\W #匹配任意不是字母,数字,下划线,汉字的字符
\S #匹配任意不是空白符的字符
\D #匹配任意非数字的字符
\B #匹配不是单词开头或结束的位置
[^x] #匹配除了x以外的任意字符
[^lee] #匹配除了magedu 这几个字母以外的任意字符
永久重定向301
[root@Nginx conf.d]# vim vars.conf
#写入内容
server {
listen 80;
server_name var.timinglee.org;
root /data/web/html;
index index.html;
location / {
root /data/web/var;
index index.html;
}
}
加密
[root@Nginx conf.d]# cd /usr/local/nginx/
[root@Nginx nginx]# vim /usr/local/nginx/conf.d/vhost.conf
#内容
server {
listen 80;
listen 443 ssl;
server_name www.timinglee.org;
root /data/web/html;
index index.html;
ssl_certificate /usr/local/nginx/certs/timinglee.org.crt;
ssl_certificate_key /usr/local/nginx/certs/timinglee.org.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
location / {
if ( $scheme = http ){
rewrite /(.*) https://$host/$1 redirect;
}
if ( !-e $request_filename ){
rewrite /(.*) https://$host/index.html redirect;
}
}
}
Nginx防盗链
防盗链基于客户端携带的referer实现,referer是记录打开一个页面之前记录是从哪个页面跳转过来的标 记信息,如果别人只链接了自己网站图片或某个单独的资源,而不是打开了网站的整个页面,这就是盗 链,referer就是之前的那个网站域名
正常的referer信息有以下几种:
none: #请求报文首部没有referer首部,
#比如用户直接在浏览器输入域名访问web网站,就没有referer信息。
blocked: #请求报文有referer首部,但无有效值,比如为空。
server_names: #referer首部中包含本主机名及即nginx 监听的server_name。
arbitrary_string: #自定义指定字符串,但可使用*作通配符。示例: *.timinglee.org www.timinglee.*
regular expression: #被指定的正则表达式模式匹配到的字符串,要使用~开头,例如:
~.*\.timinglee\.com
防盗链实现
基于访问安全考虑,nginx支持通过ngx_http_referer_module模块,检查访问请求的referer信息是否有效 实现防盗链功能
#定义防盗链
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
#内容
server {
listen 80;
server_name www.timinglee.org;
root /webdata/nginx/timinglee.org/lee;
location /images {
valid_referers none blocked server_names *.timinglee.org ~\.baidu\.;
if ($invalid_referer){
#return 403;
rewrite ^/ http://www.timinglee.org/daolian.png permanent;
}
}
}
Nginx反向代理
反向代理:reverse proxy,指的是代理外网用户的请求到内部的指定的服务器,并将数据返回给用户的 一种方式,这是用的比较多的一种方式
Nginx 除了可以在企业提供高性能的web服务之外,另外还可以将 nginx 本身不具备的请求通过某种预 定义的协议转发至其它服务器处理,不同的协议就是Nginx服务器与其他服务器进行通信的一种规范,主 要在不同的场景使用以下模块实现不同的功能
ngx_http_proxy_module: #将客户端的请求以http协议转发至指定服务器进行处理
ngx_http_upstream_module #用于定义为proxy_pass,fastcgi_pass,uwsgi_pass
#等指令引用的后端服务器分组
ngx_stream_proxy_module: #将客户端的请求以tcp协议转发至指定服务器处理
ngx_http_fastcgi_module: #将客户端对php的请求以fastcgi协议转发至指定服务器助理
ngx_http_uwsgi_module: #将客户端对Python的请求以uwsgi协议转发至指定服务器处理
逻辑调用关系
逻辑调用关系主要包含以下关键要点:
客户端请求:客户端发起对目标服务器的请求,但并不知道实际是与 nginx 进行交互。它将请求发送到 nginx 配置的监听端口上。
nginx 接收请求:nginx 接收到客户端请求后,根据其配置的反向代理规则来决定如何处理。
请求转发:nginx 依据规则将请求转发到后端真实服务器。这通常涉及到修改请求头部信息,使其看起来像是直接来自 nginx 所在服务器,以隐藏后端服务器的真实信息。
后端服务器响应:后端真实服务器接收到请求并进行处理,然后将响应结果返回给 nginx。
nginx 响应客户端:nginx 接收到后端服务器的响应后,再将其转发给客户端。在此过程中,nginx 还可以对响应数据进行缓存、压缩等操作以优化性能
访问逻辑
客户端发起请求
客户端根据所需访问的域名或 IP 地址及端口,向网络发送请求。在配置了 nginx 反向代理的场景下,客户端实际上是将请求发送到 nginx 服务器的指定监听端口,此时客户端认为它正在与目标服务器直接通信,但并不知道中间有 nginx 代理的存在。
nginx 接收并处理请求
请求解析:nginx 接收到客户端请求后,迅速解析请求的内容,包括请求方法(如 GET、POST 等)、请求的 URL、HTTP 头部信息等
匹配代理规则:根据预先配置好的反向代理规则,nginx 确定将请求转发到哪个后端服务器集群或具体的真实服务器。这些规则可以基于请求的域名、URL 路径、客户端 IP 地址等多种条件进行灵活配置。
请求转发到后端服务器
建立连接:nginx 与选定的后端服务器建立网络连接。通常使用 HTTP 或其他应用层协议与后端服务器进行通信。
请求转发:nginx 将客户端的原始请求进行必要的转换(例如修改请求头部中的某些信息,使其适应后端服务器的要求)后,转发给后端服务器。在这个过程中,nginx 可以对请求进行负载均衡,将请求均匀地分配到不同的后端服务器上,以提高系统的整体性能和可靠性。
后端服务器处理请求并返回响应
处理请求:后端服务器接收到 nginx 转发过来的请求后,像直接接收客户端请求一样进行处理。后端服务器根据请求的具体内容,执行相应的应用程序逻辑,访问数据库或其他资源,生成响应结果。
返回响应:后端服务器将处理后的响应结果发送回 nginx。响应通常包括 HTTP 状态码、响应头部信息和响应主体内容。
nginx 接收后端服务器响应并返回给客户端
响应处理:nginx 接收到后端服务器的响应后,根据需要可以对响应进行一些额外的处理,例如缓存响应结果以供后续相同请求使用、对响应数据进行压缩以减少网络传输量等。
返回给客户端:最后,nginx 将处理后的响应按照 HTTP 协议的要求返回给客户端。客户端接收到响应后,就可以根据响应内容进行页面渲染、数据展示等操作。整个过程中,客户端只知道与它通信的是最初请求的目标地址,而完全不知道 nginx 反向代理的存在以及请求在后台的转发和处理过程
同构代理:
用户不需要其他程序的参与,直接通过http协议或者tcp协议访问后端服务器。静态
异构代理:
用户访问的资源时需要经过处理后才能返回的,比如php,python,等等,这种访问资源需要经过处理才能被访问
HTTP反向代理的实现
#准备两台主机
#一台server主机
#一台nginx主机
#server主机
[root@webserver1 ~]# dnf install httpd -y
[root@webserver1 ~]# echo 172.25.254.10 > /var/www/html/index.html
#nginx主机
[root@Nginx ~]# cd /usr/local/nginx/conf.d
[root@Nginx ~]#
[root@Nginx ~]# vim vhost.conf
#写入内容
server {
listen 80;
server_name www.timinglee.org;
location ~ \.php$ {
proxy_pass http://172.25.254.10:80;
}
location /static {
proxy_pass http://172.25.254.20:8080;
}
}
HTTP反向代理实现负载均衡
关键原理要点:
请求接收
反向代理服务器(如常见的 Nginx)监听一个对外的公共 IP 和端口,接收来自客户端的 HTTP 请求。
服务器组管理
配置一组后端真实服务器(也称为上游服务器)信息,包括它们的 IP 地址和端口等。这些服务器共同组成一个服务器集群来处理客户端请求。
负载均衡算法基于这些服务器的配置和当前状态进行决策。
负载均衡算法决策
轮询(Round Robin):按顺序依次将请求分发到不同的后端服务器。例如,第一个请求分配给服务器 A,第二个请求分配给服务器 B,第三个请求分配给服务器 C,然后再从服务器 A 开始循环。
加权轮询(Weighted Round Robin):根据服务器的性能差异为每个服务器分配一个权重值。性能较好的服务器权重较高,接收到的请求数量相对较多。例如,服务器 A 权重为 3,服务器 B 权重为 2,服务器 C 权重为 1,那么在 6 次请求中,服务器 A 将分配到 3 次请求,服务器 B 分配到 2 次请求,服务器 C 分配到 1 次请求。
最少连接数(Least Connections):实时统计每个后端服务器当前的活跃连接数,将新的请求分配到连接数最少的服务器上。这样可以确保负载能够更均匀地分配到各个服务器,避免某些服务器因连接过多而超载。
IP 哈希(IP Hash):根据客户端的 IP 地址计算一个哈希值,然后根据哈希值将请求分配到特定的服务器。这样,相同 IP 地址的客户端请求总是会被分配到同一台服务器,有利于保持会话的一致性。
请求转发
根据负载均衡算法选定的后端服务器,反向代理服务器将 HTTP 请求转发给对应的服务器。在转发请求时,通常会修改请求的一些头部信息,以确保后端服务器能够正确处理请求并将响应返回给反向代理服务器。
响应返回
后端服务器处理请求后,将响应结果返回给反向代理服务器。
反向代理服务器再将响应返回给客户端,对于客户端来说,整个过程就像是直接从反向代理服务器获取响应一样。
[root@Nginx ~]# cd /usr/local/nginx/conf.d
[root@Nginx conf.d]# vim vhost.conf
#内容
upstream webserver {
server 172.25.254.10:80 fail_timeout=15s max_fails=3;
server 172.25.254.20:8080 fail_timeout=15s max_fails=3;
server 172.25.254.100:80 backup;
}
server {
listen 80;
server_name www.timinglee.org;
location / {
proxy_pass http://webserver;
}
}
#测试
[root@Nginx conf.d]# curl www.timinglee.org
172.25.254.10
[root@Nginx conf.d]# curl www.timinglee.org
172.25.254.20
[root@Nginx conf.d]# vim vhost.conf
upstream webserver {
ip_hash;
server 172.25.254.10:80 fail_timeout=15s max_fails=3;
server 172.25.254.20:8080 fail_timeout=15s max_fails=3;
#server 172.25.254.100:80 backup;
}
server {
listen 80;
server_name www.timinglee.org;
location / {
proxy_pass http://webserver;
}
}
#重载测试
[root@Nginx conf.d]# nginx -s reload
[root@Nginx conf.d]# curl www.timinglee.org
172.25.254.10
[root@Nginx conf.d]# curl www.timinglee.org
172.25.254.20
[root@Nginx conf.d]# vim vhost.conf
upstream webserver {
#ip_hash;
hash $request_uri consistent;
server 172.25.254.10:80 fail_timeout=15s max_fails=3;
server 172.25.254.20:8080 fail_timeout=15s max_fails=3;
#server 172.25.254.100:80 backup;
}
server {
listen 80;
server_name www.timinglee.org;
location / {
proxy_pass http://webserver;
}
}
#重载测试
[root@Nginx conf.d]# nginx -s reload
[root@Nginx conf.d]# vim vhost.conf
upstream webserver {
#ip_hash;
#hash $request_uri consistent;
hash #cookie_lee;
server 172.25.254.10:80 fail_timeout=15s max_fails=3;
server 172.25.254.20:8080 fail_timeout=15s max_fails=3;
#server 172.25.254.100:80 backup;
}
server {
listen 80;
server_name www.timinglee.org;
location / {
proxy_pass http://webserver;
}
}
#重载测试
[root@Nginx conf.d]# nginx -s reload
Nginx四层负载均衡实现
Nginx在1.9.0版本开始支持tcp模式的负载均衡,在1.9.13版本开始支持udp协议的负载,udp主要用于 DNS的域名解析,其配置方式和指令和http 代理类似,其基于ngx_stream_proxy_module模块实现tcp 负载,另外基于模块ngx_stream_upstream_module实现后端服务器分组转发、权重分配、状态监测、 调度算法等高级功能
如果编译安装,需要指定 --with-stream 选项才能支持ngx_stream_proxy_module模块
tcp负载均衡配置参数
stream { #定义stream相关的服务;
Context:main
upstream backend { #定义后端服务器
hash $remote_addr consistent; #定义调度算法
server backend1.example.com:12345 weight=5; #定义具体server
server 127.0.0.1:12345 max_fails=3 fail_timeout=30s;
server unix:/tmp/backend3;
}
upstream dns { #定义后端服务器
server 10.0.0.1:53; #定义具体server
server dns.example.com:53;
}
server { #定义server
listen 12345; #监听IP:PORT
proxy_connect_timeout 1s; #连接超时时间
proxy_timeout 3s; #转发超时时间
proxy_pass backend; #转发到具体服务器组
}
server {
listen 127.0.0.1:53 udp reuseport;
proxy_timeout 20s;
proxy_pass dns;
}
server {
listen [::1]:12345;
proxy_pass unix:/tmp/stream.socket;
}
}
实现FastCGI
CGI的由来
最早的Web服务器只能简单地响应浏览器发来的HTTP请求,并将存储在服务器上的HTML文件返回给浏 览器,也就是静态html文件,但是后期随着网站功能增多网站开发也越来越复杂,以至于出现动态技 术,比如像php(1995年)、java(1995)、python(1991)语言开发的网站,但是nginx/apache服务器并不 能直接运行 php、java这样的文件,apache实现的方式是打补丁,但是nginx缺通过与第三方基于协议实 现,即通过某种特定协议将客户端请求转发给第三方服务处理,第三方服务器会新建新的进程处理用户 的请求,处理完成后返回数据给Nginx并回收进程,最后nginx在返回给客户端,那这个约定就是通用网 关接口(common gateway interface,简称CGI),CGI(协议) 是web服务器和外部应用程序之间的接口 标准,是cgi程序和web服务器之间传递信息的标准化接口
为什么会有FastCGI?
CGI协议虽然解决了语言解析器和 Web Server 之间通讯的问题,但是它的效率很低,因为 Web Server 每收到一个请求都会创建一个CGI进程,PHP解析器都会解析php.ini文件,初始化环境,请求结束的时候 再关闭进程,对于每一个创建的CGI进程都会执行这些操作,所以效率很低,而FastCGI是用来提高CGI性 能的,FastCGI每次处理完请求之后不会关闭掉进程,而是保留这个进程,使这个进程可以处理多个请 求。这样的话每个请求都不用再重新创建一个进程了,大大提升了处理效率
什么是PHP-FPM?
PHP-FPM(FastCGI Process Manager:
FastCGI进程管理器)是一个实现了Fastcgi的程序,并且提供进程管理的功能
进程包括master进程和worker进程。master进程只有一个,负责监听端口,接受来自web server 的请求
worker进程一般会有多个,每个进程中会嵌入一个PHP解析器,进行PHP代码的处理
FastCGI配置指令
Nginx基于模块ngx_http_fastcgi_module实现通过fastcgi协议将指定的客户端请求转发至php-fpm处 理,其配置指令如下
fastcgi_pass address:port;
#转发请求到后端服务器,address为后端的fastcgi server的地址,可用位置:location, if in location
fastcgi_index name;
#fastcgi默认的主页资源,示例:fastcgi_index index.php;
fastcgi_param parameter value [if_not_empty];
#设置传递给FastCGI服务器的参数值,可以是文本,变量或组合,可用于将Nginx的内置变量赋值给自定义key
fastcgi_param REMOTE_ADDR $remote_addr; #客户端源IP
fastcgi_param REMOTE_PORT $remote_port; #客户端源端口
fastcgi_param SERVER_ADDR $server_addr; #请求的服务器IP地址
fastcgi_param SERVER_PORT $server_port; #请求的服务器端口
fastcgi_param SERVER_NAME $server_name; #请求的server name
#Nginx默认配置示例:
location ~ \.php$ {
root /scripts;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; #默认脚本路径
#fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params; #此文件默认系统已提供,存放的相对路径为
prefix/conf
}
FastCGI实战案例 : Nginx与php-fpm在同一服务器
源码编译php
#利用yum解决php依赖
[root@Nginx ~]# yum install -y bzip2 systemd-devel libxml2-devel sqlite-devel
libpng-devel libcurl-devel oniguruma-devel
#解压源码并安装
[root@Nginx ~]# ./configure \
--prefix=/usr/local/php \ #安装路径
--with-config-file-path=/usr/local/php/etc \ #指定配置路径
--enable-fpm \ #用cgi方式启动程序
--with-fpm-user=nginx \ #指定运行用户身份
--with-fpm-group=nginx \
--with-curl \ #打开curl浏览器支持
--with-iconv \ #启用iconv函数,转换字符编码
--with-mhash \ #mhash加密方式扩展库
--with-zlib \ #支持zlib库,用于压缩http压缩传输
--with-openssl \ #支持ssl加密
--enable-mysqlnd \ #mysql数据库
--with-mysqli \
--with-pdo-mysql \
--disable-debug \ #关闭debug功能
--enable-sockets \ #支持套接字访问
--enable-soap \ #支持soap扩展协议
--enable-xml \ #支持xml
--enable-ftp \ #支持ftp
--enable-gd \ #支持gd库
--enable-exif \ #支持图片元数据
--enable-mbstring \ #支持多字节字符串
--enable-bcmath \ #打开图片大小调整,用到zabbix监控的时候用到了这个模块
--with-fpm-systemd #支持systemctl 管理cgi
php相关配置优化
[root@Nginx ~]# cd /usr/local/php/etc
[root@Nginx etc]# cp php-fpm.conf.default php-fpm.conf
[root@Nginx etc]# vim php-fpm.conf
去掉注释
pid = run/php-fpm.pid #指定pid文件存放位置
[root@Nginx etc]# cd php-fpm.d/
[root@Nginx php-fpm.d]# cp www.conf.default www.conf
#生成主配置文件
[root@Nginx php-fpm.d]# cd /root/php-8.3.9/
[root@Nginx php-8.3.9]# cp php.ini-production /usr/local/php/etc/php.ini
[root@Nginx ~]# vim /usr/local/php/etc/php.ini
[Date]
; Defines the default timezone used by the date functions
; https://php.net/date.timezone
date.timezone = Asia/Shanghai #修改时区
#生成启动文件
[root@Nginx ~]# cd /root/php-8.3.9/
[root@Nginx php-8.3.9]# cp sapi/fpm/php-fpm.service /lib/systemd/system/
# Mounts the /usr, /boot, and /etc directories read-only for processes invoked by
this unit.
#ProtectSystem=full #注释该内容
[root@Nginx php-8.3.9]# systemctl start php-fpm.service
[root@Nginx php-8.3.9]# netstat -antlupe | grep php
tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 0
820758 176202/php-fpm: mas
准备php测试页面
[root@Nginx ~]# mkdir /data/php -p
[root@centos8 ~]# cat /data/php/index.php #php测试页面
<?php
phpinfo();
?>
Nginx配置转发
Nginx安装完成之后默认生成了与fastcgi的相关配置文件,一般保存在nginx的安装路径的conf目录当 中,比如/apps/nginx/conf/fastcgi.conf、/apps/nginx/conf/fastcgi_params
[root@Nginx ~]# vim /apps/nginx/conf.d/php.conf
server {
listen 80;
server_name www.timinglee.org;
root /data/php;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}
#重启Nginx并访问web测试
[root@Nginx ~]# nginx -s reload
Nginx 二次开发版本
openresty
Nginx 是俄罗斯人发明的, Lua 是巴西几个教授发明的,中国人章亦春把 LuaJIT VM 嵌入到 Nginx 中, 实现了 OpenResty 这个高性能服务端解决方案
OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方 模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服 务和动态网关
OpenResty® 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言 调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高 性能 Web 应用系统
OpenResty 由于有功能强大且方便的的API,可扩展性更强,如果需要实现定制功能,OpenResty是个不错的选择
官网: http://openresty.org/cn/
编译安装 openresty
[root@Nginx ~]#dnf -yq install gcc pcre-devel openssl-devel perl
[root@Nginx ~]#useradd -r -s /sbin/nologin nginx
[root@Nginx ~]#cd /usr/local/src
[root@Nginx src]#wget https://openresty.org/download/openresty-1.17.8.2.tar.gz
[root@Nginx src]#tar xf openresty-1.17.8.2.tar.gz
[root@Nginx src]#cd openresty-1.17.8.2/
[root@Nginx openresty-1.17.8.2]#./configure \
--prefix=/apps/openresty \
--user=nginx --group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with_http_realip_module \
--with-http_stub_status_module \
--with-http_gzip_static_module
--with-pcre --with-stream \
--with-stream_ssl_module \
--with-stream_realip_module
[root@Nginx openresty-1.17.8.2]#make && make install
[root@Nginx openresty-1.17.8.2]#ln -s /apps/openresty/bin/* /usr/bin/
[root@Nginx openresty-1.17.8.2]#openresty -v
nginx version: openresty/1.17.8.2
[root@Nginx openresty-1.17.8.2]#openresty
[root@Nginx openresty-1.17.8.2]#ps -ef |grep nginx
[root@Nginx ~]#curl 10.0.0.18