目录
1.2.2.1 阻塞型 I/O 模型(blocking IO)
1.2.2.2 非阻塞型 I/O 模型 (nonblocking IO)
1.2.2.3 多路复用 I/O 型(I/O multiplexing)
1.2.2.4 信号驱动式 I/O 模型 (signal-driven IO)
1.2.2.5 异步 I/O 模型 (asynchronous IO)
5.1 ngx_http_rewrite_module 模块指令
5.2.3 rewrite 案例: break 与 last
6.1.1.3 实战案例: 指定 location 实现反向代理
一. Web 服务基础介绍
1.1 Web服务介绍
1.1.1 Apache 经典的 Web 服务端
Apache 起初由美国的伊利诺伊大学香槟分校的国家超级计算机应用中心开发目前经历了两大版本分别是 1.X 和 2.X .其可以通过编译安装实现特定的功能
1.1.1.1 Apache prefork 模型
- 预派生模式,有一个主控制进程,然后生成多个子进程,使用select模型,最大并发1024
- 每个子进程有一个独立的线程响应用户请求
- 相对比较占用内存,但是比较稳定,可以设置最大和最小进程数
- 是最古老的一种模式,也是最稳定的模式,适用于访问量不是很大的场景
优点:稳定缺点:每个用户请求需要对应开启一个进程 , 占用资源较多,并发性差 , 不适用于高并发场景
1.1.1.2 Apache worker 模型
- 一种多进程和多线程混合的模型
- 有一个控制进程,启动多个子进程
- 每个子进程里面包含固定的线程
- 使用线程程来处理请求
- 当线程不够使用的时候会再启动一个新的子进程,然后在进程里面再启动线程处理请求,
- 由于其使用了线程处理请求,因此可以承受更高的并发
优点:相比 prefork 占用的内存较少,可以同时处理更多的请求缺点:使用 keepalive 的长连接方式,某个线程会一直被占据,即使没有传输数据,也需要一直等待到超时才会被释放。如果过多的线程,被这样占据,也会导致在高并发场景下的无服务线程可用(该问题在prefork模式下,同样会发生)
1.1.1.3 Apache event模型
Apache 中最新的模式, 2012 年发布的 apache 2.4.X 系列正式支持 event 模型 , 属于事件驱动模型 (epoll)每个进程响应多个请求,在现在版本里的已经是稳定可用的模式它和 worker 模式很像,最大的区别在于,它解决了 keepalive 场景下长期被占用的线程的资源浪费问题(某些线程因为被keepalive ,空挂在哪里等待,中间几乎没有请求过来,甚至等到超时) event MPM 中,会有一个专门的线程来管理这些 keepalive 类型的线程当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放。这样增强了高并发场景下的请求处理能力优点:单线程响应多请求,占据更少的内存,高并发下表现更优秀,会有一个专门的线程来管理 keep-alive类型的线程,当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放缺点:没有线程安全控制
1.1.2 Nginx-高性能的 Web 服务端
Nginx 是由 1994 年毕业于俄罗斯国立莫斯科鲍曼科技大学的同学为俄罗斯 rambler.ru 公司开发的,开发工作最早从2002 年开始,第一次公开发布时间是 2004 年 10 月 4 日,版本号是 0.1.02019 年 3 月 11 日 F5 与 NGINX 达成协议 ,F5 将收购 NGINX 的所有已发行股票,总价值约为 6.7 亿美元。6.7亿美金约合 44.97 亿人民币 ,nginx 核心模块代码长度 198430 (包括空格、注释),所以一行代码约为2.2万人民币官网地址 www.nginx.orgNginx 历经十几年的迭代更新( https://nginx.org/en/CHANGES ), 目前功能已经非常完善且运行稳定,另外Nginx 的版本分为开发版、稳定版和过期版, nginx 以功能丰富著称,它即可以作为 http 服务器,也可以作为反向代理服务器或者邮件服务器能够快速的响应静态网页的请求支持 FastCGI/SSL/Virtual Host/URL Rwrite /Gzip / HTTP Basic Auth/http 或者 TCP 的负载均衡 (1.9 版本以上且开启stream 模块 ) 等功能,并且支持第三方的功能扩展。天猫 淘宝 京东 小米 163 新浪等一线互联网公司都在用 Nginx 或者进行二次开发基于 Nginx 的工作场景
1.1.3 用户访问体验和性能
1.1.3.1 用户访问体验统计
互联网存在用户速度体验的 1-3-10 原则,即 1 秒最优, 1-3 秒较优, 3~10 秒比较慢, 10 秒以上用户无法接受。用户放弃一个产品的代价很低,只是换一个URL 而已。全球最大搜索引擎 Google :慢 500ms = 20% 将放弃访问。全球最大的电商零售网站亚马逊:慢 100ms = 1% 将放弃交易有很多研究都表明,性能对用户的行为有很大的影响:79% 的用户表示不太可能再次打开一个缓慢的网站47% 的用户期望网页能在 2 秒钟以内加载40% 的用户表示如果加载时间超过三秒钟,就会放弃这个网站页面加载时间延迟一秒可能导致转换损失 7% ,页面浏览量减少 11%8 秒定律:用户访问一个网站时,如果等待网页打开的时间超过 8 秒,会有超过 30% 的用户放弃等待
1.1.3.2 影响用户体验的因素
据说马云在刚开始创业在给客户演示时,打开一个网站花了不到四个小时。影响用户体验的因素1. 客户端客户端硬件配置客户端网络速率客户端与服务端距离2. 服务器服务端网络速率服务端硬件配置服务端架构设计服务端应用程序工作模式服务端并发数量服务端响应文件大小及数量 buffer cache服务端 I/O 压力 1.2.4 服务端 I/O 流程
1.1.4 服务端 I/O 流程
I/O 在计算机中指 Input/Output , IOPS (Input/Output Per Second) 即每秒的输入输出量 ( 或读写次数 ) ,是衡量磁盘性能的主要指标之一。IOPS 是指单位时间内系统能处理的 I/O 请求数量,一般以每秒处理的I/O请求数量为单位, I/O 请求通常为读或写数据操作请求。一次完整的 I/O 是用户空间的进程数据与内核空间的内核数据的报文的完整交换,但是由于内核空间与用户空间是严格隔离的,所以其数据交换过程中不能由用户空间的进程直接调用内核空间的内存数据,而是需要经历一次从内核空间中的内存数据copy 到用户空间的进程内存当中,所以简单说 I/O 就是把数据从内核空间中的内存数据复制到用户空间中进程的内存当中。服务器的 I/O
- 磁盘I/O
- 网络I/O : 一切皆文件,本质为对socket文件的读写
1.1.4.1 磁盘 I/O
机械磁盘的寻道时间、旋转延迟和数据传输时间:寻道时间:是指磁头移动到正确的磁道上所花费的时间,寻道时间越短则 I/O 处理就越快,目前磁盘的寻道时间一般在3-15 毫秒左右。旋转延迟:是指将磁盘片旋转到数据所在的扇区到磁头下面所花费的时间,旋转延迟取决于磁盘的转速,通常使用磁盘旋转一周所需要时间的1/2 之一表示,比如 7200 转的磁盘平均训传延迟大约为60*1000/7200/2=4.17毫秒,公式的意思为 (每分钟 60 秒 *1000 毫秒每秒 /7200 转每分 /2 ),如果是15000转的则为 60*1000/15000/2=2 毫秒。数据传输时间:指的是读取到数据后传输数据的时间,主要取决于传输速率,这个值等于数据大小除以传输速 率,目前的磁盘接口每秒的传输速度可以达到600MB ,因此可以忽略不计。常见的机械磁盘平均寻道时间值:7200 转 / 分的磁盘平均物理寻道时间: 9 毫秒10000 转 / 分的磁盘平均物理寻道时间: 6 毫秒15000 转 / 分的磁盘平均物理寻道时间: 4 毫秒常见磁盘的平均延迟时间:7200 转的机械盘平均延迟: 60*1000/7200/2 = 4.17ms10000 转的机械盘平均延迟: 60*1000/10000/2 = 3ms15000 转的机械盘平均延迟: 60*1000/15000/2 = 2ms每秒最大 IOPS 的计算方法:7200 转的磁盘 IOPS 计算方式: 1000 毫秒 /(9 毫秒的寻道时间 +4.17 毫秒的平均旋转延迟时 间)=1000/13.13=75.9 IOPS10000转的磁盘的 IOPS 计算方式: 1000 毫秒 /(6 毫秒的寻道时间 +3 毫秒的平均旋转延迟时 间)=1000/9=111IOPS15000 转的磁盘的 IOPS 计算方式: 15000 毫秒 /(4 毫秒的寻道时间 +2 毫秒的平均旋转延迟时 间)=1000/6=166.6 IOPS
1.2.4.2 网络 I/O
网络通信就是网络协议栈到用户空间进程的 IO 就是网络 IO网络 I/O 处理过程获取请求数据,客户端与服务器建立连接发出请求,服务器接受请求( 1-3 )
- 构建响应,当服务器接收完请求,并在用户空间处理客户端的请求,直到构建响应完成(4)
- 返回数据,服务器将已构建好的响应再通过内核空间的网络 I/O 发还给客户端(5-7)
不论磁盘和网络 I/O每次 I/O ,都要经由两个阶段:
- 第一步:将数据从文件先加载至内核内存空间(缓冲区),等待数据准备完成,时间较长
- 第二步:将数据从内核缓冲区复制到用户空间的进程的内存中,时间较短
1.2 I/O 模型
1.2.1 I/O 模型相关概念
同步 / 异步:关注的是消息通信机制,即调用者在等待一件事情的处理结果时,被调用者是否提供完成状态的通知。
- 同步:synchronous,被调用者并不提供事件的处理结果相关的通知消息,需要调用者主动询问事 情是否处理完成
- 异步:asynchronous,被调用者通过状态、通知或回调机制主动通知调用者被调用者的运行状态
阻塞 / 非阻塞:关注调用者在等待结果返回之前所处的状态
- 阻塞:blocking,指IO操作需要彻底完成后才返回到用户空间,调用结果返回之前,调用者被挂起,干不了别的事情。
- 非阻塞:nonblocking,指IO操作被调用后立即返回给用户一个状态值,而无需等到IO操作彻底完成,在最终的调用结果返回之前,调用者不会被挂起,可以去做别的事情。
1.2.2 网络 I/O 模型
1.2.2.1 阻塞型 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 是否完成,这种方式简单,但是比较慢,用的比较少
1.2.2.2 非阻塞型 I/O 模型 (nonblocking IO)
用户线程发起 IO 请求时立即返回。但并未读取到任何数据,用户线程需要不断地发起 IO 请求,直到数据到达后,才真正读取到数据,继续执行。即 “ 轮询 ” 机制存在两个问题:如果有大量文件描述符都要等,那么就得一个一个的read 。这会带来大量的 Context Switch ( read 是系统调用,每调用一次就得在用户态和核心态切换一次)。轮询的时间不好把握。这里是要猜多久之后数据才能到。等待时间设的太长,程序响应延迟就过大;设的太短,就会造成过于频繁的重试,干耗 CPU 而已,是比较浪费 CPU 的方式,一般很少直接使用这种模型,而是在其他IO 模型中使用非阻塞 IO 这一特性。非阻塞:程序向内核发送请 I/O 求后一直等待内核响应,如果内核处理请求的 IO 操作不能立即返回 IO 结果,进程将不再等待,而且继续处理其他请求,但是仍然需要进程隔一段时间就要查看内核I/O 是否完成。查看上图可知,在设置连接为非阻塞时,当应用进程系统调用 recvfrom 没有数据返回时,内核会立即返回一个 EWOULDBLOCK 错误,而不会一直阻塞到数据准备好。如上图在第四次调用时有一个数据报准备好了,所以这时数据会被复制到 应用进程缓冲区 ,于是 recvfrom 成功返回数据当一个应用进程这样循环调用 recvfrom 时,称之为轮询 polling 。这么做往往会耗费大量 CPU 时间,实际使用很少
1.2.2.3 多路复用 I/O 型(I/O multiplexing)
上面的模型中 , 每一个文件描述符对应的 IO 是由一个线程监控和处理多路复用 IO 指一个线程可以同时(实际是交替实现,即并发完成)监控和处理多个文件描述符对应各自的IO ,即复用同一个线程一个线程之所以能实现同时处理多个 IO, 是因为这个线程调用了内核中的 SELECT,POLL 或 EPOLL 等系统调用,从而实现多路复用IOI/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 是要配合一起使用才有实际意义IO 多路复用是指内核一旦发现进程指定的一个或者多个 IO 条件准备读取,就通知该进程多个连接共用一个等待机制,本模型会阻塞进程,但是进程是阻塞在select 或者 poll 这两个系统调用上,而不是阻塞在真正的IO 操作上用户首先将需要进行 IO 操作添加到 select 中,同时等待 select 系统调用返回。当数据到达时,IO 被激活, select 函数返回。用户线程正式发起 read 请求,读取数据并继续执行从流程上来看,使用select函数进行 IO 请求和同步阻塞模型没有太大的区别,甚至还多了添加监视 IO ,以及调用 select 函数的额外操作,效率更差。并且阻塞了两次,但是第一次阻塞在select 上时, select 可以监控多个 IO 上是否已有IO 操作准备就绪,即可达到在同一个线程内同时处理多个 IO 请求的目的。而不像阻塞 IO 那种,一次只能监控一个IO 虽然上述方式允许单线程内处理多个 IO 请求,但是每个 IO 请求的过程还是阻塞的(在 select函数上阻塞),平均时间甚至比同步阻塞IO 模型还要长。如果用户线程只是注册自己需要的 IO 请求,然后去做自己的事情,等到数据到来时再进行处理,则可以提高CPU 的利用率 IO 多路复用是最常使用的 IO模型,但是其异步程度还不够“ 彻底 ” ,因它使用了会阻塞线程的 select 系统调用。因此 IO 多路复用只能称为异步阻塞IO 模型,而非真正的异步 IO优缺点
- 优点:可以基于一个阻塞对象,同时在多个描述符上等待就绪,而不是使用多个线程(每个文件描述符一个线程),这样可以大大节省系统资源
- 缺点:当连接数较少时效率相比多线程+阻塞 I/O 模型效率较低,可能延迟更大,因为单个连接处理需要 2 次系统调用,占用时间会有增加
IO 多路复用适用如下场合:
- 当客户端处理多个描述符时(一般是交互式输入和网络套接口),必须使用I/O复用
- 当一个客户端同时处理多个套接字时,此情况可能的但很少出现
- 当一个服务器既要处理监听套接字,又要处理已连接套接字,一般也要用到I/O复用
- 当一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用
- 当一个服务器要处理多个服务或多个协议,一般要使用I/O复用
1.2.2.4 信号驱动式 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 完成后内核再通知进程。
1.2.2.5 异步 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 复用,因此异步非阻塞使用最多的一种通信方式。
1.2.3 五种 IO 对比
1.2.4 I/O 的具体实现方式
1.2.4.1 I/O常见实现
Nginx 支持在多种不同的操作系统实现不同的事件驱动模型,但是其在不同的操作系统甚至是不同的系统 版本上面的实现方式不尽相同,主要有以下实现方式: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 、 Iocp : 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 以上的版本,该驱动库看防止内核崩溃等情况的发生。
1.2.4.2 常用I/O模型比较
Select :POSIX 所规定,目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,本质上是通过设置或者检查存放fd 标志位的数据结构来进行下一步处理缺点单个进程能够监视的文件描述符的数量存在最大限制,在 Linux 上一般为 1024 ,可以通过修改宏定FD_SETSIZE ,再重新编译内核实现,但是这样也会造成效率的降低单个进程可监视的 fd 数量被限制,默认是1024 ,修改此值需要重新编译内核对 socket 是线性扫描,即采用轮询的方法,效率较低 select 采取了内存拷贝方法来实现内核将 FD 消息通知给用户空间,这样一个用来存放大量 fd 的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大poll :本质上和 select 没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个 fd 对应的设备状态其没有最大连接数的限制,原因是它是基于链表来存储的大量的fd 的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义poll 特点是 “ 水平触发 ” ,如果报告了 fd 后,没有被处理,那么下次poll时会再次报告该 fd select 是边缘触发即只通知一次epoll :在 Linux 2.6 内核中提出的 select 和 poll 的增强版本支持水平触发 LT 和边缘触发 ET ,最大的特点在于边缘触发,它只告诉进程哪些fd 刚刚变为就需态,并且只会通知一次使用 “ 事件 ” 的就绪通知方式,通过 epoll_ctl 注册fd ,一旦该 fd 就绪,内核就会采用类似 callback 的回调机制来激活该 fd , epoll_wait 便可以收到通知优点 :没有最大并发连接的限制:能打开的 FD 的上限远大于 1024(1G 的内存能监听约 10 万个端口 ) ,具体查看/proc/sys/fs/file-max,此值和系统内存大小相关效率提升:非轮询的方式,不会随着 FD 数目的增加而效率下降 ; 只有活跃可用的 FD 才会调用 callback 函数,即epoll 最大的优点就在于它只管理 “ 活跃 ” 的连接,而跟连接总数无关内存拷贝,利用 mmap(Memory Mapping) 加速与内核空间的消息传递 ; 即 epoll 使用 mmap 减少复制开销总结 :1 、 epoll 只是一组 API ,比起 select 这种扫描全部的文件描述符, epoll 只读取就绪的文件描述符,再加入基于事件的就绪通知机制,所以性能比较好2 、基于 epoll 的事件多路复用减少了进程间切换的次数,使得操作系统少做了相对于用户任务来说的无用功。3 、 epoll 比 select 等多路复用方式来说,减少了遍历循环及内存拷贝的工作量,因为活跃连接只占总并发连接的很小一部分。
1.3 零拷贝
1.3.1 零拷贝介绍
传统的 Linux 系统的标准 I/O 接口( read 、 write )是基于数据拷贝的,也就是数据都是 copy_to_user或者 copy_from_user ,这样做的好处是,通过中间缓存的机制,减少磁盘 I/O 的操作,但是坏处也很明显,大量数据的拷贝,用户态和内核态的频繁切换,会消耗大量的 CPU 资源,严重影响数据传输的性能,统计表明,在Linux 协议栈中,数据包在内核态和用户态之间的拷贝所用的时间甚至占到了数据包整个处理流程时间的57.1%零拷贝就是上述问题的一个解决方案,通过尽量避免拷贝操作来缓解 CPU 的压力。零拷贝并没有真正做到“0” 拷贝,它更多是一种思想,很多的零拷贝技术都是基于这个思想去做的优化
1.3.2 零拷页相关技术
MMAP ( Memory Mapping )‘mmap() 系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进行访问。mmap 是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write 等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。内存映射减少数据在用户空间和内核空间之间的拷贝操作 , 适合大量数据传输SENDFILEDMA 辅助的 SENDFILE
二. Nginx 架构和安装
2.1 Nginx 概述
2.1.1 Nginx 介绍
Nginx : engine X , 2002 年开发,分为社区版和商业版 (nginx plus )2019 年 3 月 11 日 F5 Networks 6.7 亿美元的价格收购Nginx 是免费的、开源的、高性能的 HTTP 和反向代理服务器、邮件代理服务器、以及 TCP/UDP 代理服务器解决 C10K 问题( 10K Connections )Nginx 官网: http://nginx.orgnginx 的其它的二次发行版:Tengine :由淘宝网发起的 Web 服务器项目。它在 Nginx 的基础上,针对大访问量网站的需求,添加了很多高级功能和特性。 Tengine 的性能和稳定性已经在大型的网站如淘宝网,天猫商城等得到了很好的检验。它的最终目标是打造一个高效、稳定、安全、易用的Web 平台。从 2011 年 12 月开始,Tengine成为一个开源项目官网 : http://tengine.taobao.org/OpenResty :基于 Nginx 与 Lua 语言的高性能 Web 平台, 章亦春团队开发,官网: http://openresty.org/cn/
2.1.2 Nginx 功能介绍
- 静态的web资源服务器html,图片,js,css,txt等静态资源
- http/https协议的反向代理
- 结合FastCGI/uWSGI/SCGI等协议反向代理动态资源请求
- tcp/udp协议的请求转发(反向代理)
- imap4/pop3协议的反向代理
2.2.3 基础特性
- 模块化设计,较好的扩展性
- 高可靠性
- 支持热部署:不停机更新配置文件,升级版本,更换日志文件
- 低内存消耗:10000个keep-alive连接模式下的非活动连接,仅需2.5M内存
- event-driven,aio,mmap,sendfile
2.2.4 Web 服务相关的功能
- 虚拟主机(server)
- 支持 keep-alive 和管道连接(利用一个连接做多次请求)
- 访问日志(支持基于日志缓冲提高其性能)url rewirte
- 路径别名
- 基于IP及用户的访问控制
- 支持速率限制及并发数限制
- 重新配置和在线升级而无须中断客户的工作进程
2.2 Nginx 架构和进程
2.2.1 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调用,获取响应数据
- 与后端服务器通信,接收后端服务器的处理结果
- 缓存数据,访问缓存索引,查询和调用缓存数据
- 发送请求结果,响应客户的请求
- 接收主程序指令,比如重启、升级和退出等
2.2.2 Nginx 进程间通信
工作进程是由主进程生成的,主进程使用 fork() 函数,在 Nginx 服务器启动过程中主进程根据配置文件决定启动工作进程的数量,然后建立一张全局的工作表用于存放当前未退出的所有的工作进程,主进程生成工作进程后会将新生成的工作进程加入到工作进程表中,并建立一个单向的管道并将其传递给工作进程,该管道与普通的管道不同,它是由主进程指向工作进程的单向通道,包含了主进程向工作进程发出的指令、工作进程ID 、工作进程在工作进程表中的索引和必要的文件描述符等信息。主进程与外界通过信号机制进行通信,当接收到需要处理的信号时,它通过管道向相关的工作进程发送正确的指令,每个工作进程都有能力捕获管道中的可读事件,当管道中有可读事件的时候,工作进程就会从管道中读取并解析指令,然后采取相应的执行动作,这样就完成了主进程与工作进程的交互。
2.3 Nginx 模块介绍
nginx 有多种模块
- 核心模块:是 Nginx 服务器正常运行必不可少的模块,提供错误日志记录 、配置文件解析 、事件驱动机制 、进程管理等核心功能
- 标准HTTP模块:提供 HTTP 协议解析相关的功能,比如: 端口配置 、 网页编码设置 、 HTTP响应头设置 等等
- 可选HTTP模块:主要用于扩展标准的 HTTP 功能,让 Nginx 能处理一些特殊的服务,比如: Flash
- 多媒体传输 、解析 GeoIP 请求、 网络传输压缩 、 安全协议 SSL 支持等
- 邮件服务模块:主要用于支持 Nginx 的 邮件服务 ,包括对 POP3 协议、 IMAP 协议和 SMTP协议的支持
- Stream服务模块: 实现反向代理功能,包括TCP协议代理
- 第三方模块:是为了扩展 Nginx 服务器应用,完成开发者自定义功能,比如: Json 支持、 Lua 支持等
nginx 高度模块化,但其模块早期不支持 DSO 机制 ;1.9.11 版本支持动态装载和卸载
2.4 Nginx 安装
2.4.1 Nginx版本和安装方式
Nginx 版本
- Mainline version 主要开发版本,一般为奇数版本号,比如1.19
- Stable version 当前最新稳定版,一般为偶数版本,如:1.20
- Legacy versions 旧的稳定版,一般为偶数版本,如:1.18
Nginx 安装可以使用 yum 或源码安装,但是推荐使用源码编译安装
- yum的版本比较旧
- 编译安装可以更方便自定义相关路径
- 使用源码编译可以自定义相关功能,更方便业务的上的使用
2.4.2.Nginx 编译安装
源码安装需要提前准备标准的编译器, GCC 的全称是( GNU Compiler collection ),其有 GNU 开发,并以 GPL即 LGPL 许可,是自由的类 UNIX 即苹果电脑 Mac OS X 操作系统的标准编译器,因为 GCC 原本只能处理 C 语言,所以原名为GNU C 语言编译器,后来得到快速发展,可以处理 C++,Fortran , pascal , objective C ,java以及 Ada 等其他语言,此外还需要 Automake 工具,以完成自动创建 Makefile 的工作, Nginx 的一些模块需要依赖第三方库,比如: pcre (支持 rewrite ), zlib (支持 gzip 模块)和 openssl (支持 ssl 模块)等
官方源码包下载地址:https://nginx.org/en/download.html
[root@Nginx ~]# dnf install gcc pcre-devel zlib-devel openssl-devel -y
[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]# cd nginx-1.24.0/
[root@Nginx nginx-1.24.0]# ls
auto CHANGES.ru configure html Makefile objs src
CHANGES conf contrib LICENSE man README
[root@Nginx nginx-1.24.0]# ./configure --prefix=/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
[root@Nginx nginx-1.24.0]# ls /usr/local/nginx/conf html logs sbinconf :保存 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软件命令执行路径添加到环境变量中
[root@Nginx ~]# vim ~/.bash_profile
export PATH=$PATH:/usr/local/nginx/sbin
[root@Nginx ~]# source ~/.bash_profile
[root@Nginx ~]# nginx -V
nginx version: nginx/1.24.0
built by gcc 11.2.1 20220127 (Red Hat 11.2.1-9) (GCC)
built with OpenSSL 3.0.1 14 Dec 2021
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --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 ~]# nginx
[root@Nginx ~]# ps aux | grep nginx
root 37620 0.0 0.0 9840 928 ? Ss 18:55 0:00 nginx: master process nginx
nginx 37621 0.0 0.1 13700 4804 ? S 18:55 0:00 nginx: worker process
root 37623 0.0 0.0 221684 2484 pts/1 S+ 18:55 0:00 grep --color=auto nginx
#关闭debug功能
[root@Nginx nginx-1.24.0]# vim auto/cc/gcc
# debug
#CFLAGS="$CFLAGS -g"
#Nginx 启动文件
[root@Nginx ~]# vim /lib/systemd/system/nginx.service
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
[root@Nginx ~]# systemctl daemon-reload
[root@Nginx ~]# systemctl start nginx
nginx常见参数
[root@Nginx ~]# nginx -help
nginx version: nginx/1.24.0
Usage: nginx [-?hvVtTq] [-s signal] [-p prefix]
[-e filename] [-c filename] [-g directives]
Options:
-?,-h : this help
-v : show version and exit
-V : show version and configure options then exit #显示版本和编译参数
-t : test configuration and exit #测试配置文件是否异
-T : test configuration, dump it and exit #测试并打印
-q : suppress non-error messages during configuration testing #静默
模式
-s signal : send signal to a master process: stop, quit, reopen, reload #
发送信号,reload信号 会生成新的worker,但master不会重新生成
-p prefix : set prefix path (default: /usr/local/nginx/) #指定Nginx 目录
-e filename : set error log file (default: logs/error.log)
-c filename : set configuration file (default: conf/nginx.conf) #
配置文件路径
-g directives : set global directives out of configuration file #设置全局指令,注意和配置文件不要同时配置,否则冲突
#开启多个worker
[root@Nginx ~]# vim /usr/local/nginx/conf/nginx.conf
#user nobody;
worker_processes 6;
[root@Nginx ~]# nginx -s reload
[root@Nginx ~]# ps aux | grep nginx
root 37832 0.0 0.0 9840 2604 ? Ss 19:20 0:00 nginx: master process /usr/local/nginx/sbin/nginx
root 41202 0.0 0.1 9876 6548 ? S 19:31 0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx 41223 0.0 0.1 13700 5368 ? S 19:37 0:00 nginx: worker process
nginx 41323 0.0 0.1 13768 4932 ? S 21:15 0:00 nginx: worker process
nginx 41324 0.0 0.1 13768 4932 ? S 21:15 0:00 nginx: worker process
nginx 41325 0.0 0.1 13768 4932 ? S 21:15 0:00 nginx: worker process
nginx 41326 0.0 0.1 13768 4932 ? S 21:15 0:00 nginx: worker process
nginx 41327 0.0 0.1 13768 4932 ? S 21:15 0:00 nginx: worker process
nginx 41328 0.0 0.1 13768 4932 ? S 21:15 0:00 nginx: worker process
root 41330 0.0 0.0 221684 2492 pts/1 S+ 21:15 0:00 grep --color=auto nginx
2.5 平滑升级和回滚
2.5.1 平滑升级流程
- 将旧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
2.5.2 平滑升级和回滚案例
[root@Nginx ~]# tar zxf nginx-1.26.1.tar.gz
[root@Nginx ~]# tar zxf echo-nginx-module-0.63.tar.gz
[root@Nginx ~]# cd nginx-1.26.1/
[root@Nginx nginx-1.26.1]# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --add-module=/root/echo-nginx-module-0.63 --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
#只要make无需要make install
[root@Nginx nginx-1.26.1]# make
#把之前的旧版的nginx命令备份
[root@Nginx ~]# cd /usr/local/nginx/sbin/
[root@Nginx sbin]# cp nginx nginx.24
#把新版本的nginx命令复制过去
[root@Nginx sbin]# \cp -f /root/nginx-1.26.1/objs/nginx /usr/local/nginx/sbin
#检测一下有没有问题
[root@Nginx sbin]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@Nginx sbin]# ps aux | grep nginx
root 37832 0.0 0.0 9840 928 ? Ss 19:20 0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx 37833 0.0 0.1 13700 5368 ? S 19:20 0:00 nginx: worker process
root 41201 0.0 0.0 221684 2316 pts/1 S+ 19:31 0:00 grep --color=auto nginx
[root@Nginx sbin]# kill -USR2 37832
#USR2 平滑升级可执行程序,将存储有旧版本主进程PID的文件重命名为nginx.pid.oldbin,并启动新的nginx
#此时两个master的进程都在运行,只是旧的master不在监听,由新的master监听80
#此时Nginx开启一个新的master进程,这个master进程会生成新的worker进程,这就是升级后的Nginx进程,此时老的进程不会自动退出,但是当接收到新的请求不作处理而是交给新的进程处理。
[root@Nginx sbin]# ps aux | grep nginx
root 37832 0.0 0.0 9840 2604 ? Ss 19:20 0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx 37833 0.0 0.1 13700 5368 ? S 19:20 0:00 nginx: worker process
root 41202 0.0 0.1 9876 6112 ? S 19:31 0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx 41203 0.0 0.1 13736 4904 ? S 19:31 0:00 nginx: worker process
root 41205 0.0 0.0 221684 2440 pts/1 S+ 19:31 0:00 grep --color=auto nginx
[root@Nginx sbin]# curl -I 172.25.254.100
HTTP/1.1 200 OK
Server: nginx/1.24.0 #依旧是旧版本生生效
Date: Tue, 20 Aug 2024 11:33:06 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 20 Aug 2024 09:05:53 GMT
Connection: keep-alive
ETag: "66c45c71-267"
Accept-Ranges: bytes
#回收旧版本
[root@Nginx sbin]# kill -WINCH 37832
[root@Nginx sbin]# ps aux | grep nginx
root 37832 0.0 0.0 9840 2604 ? Ss 19:20 0:00 nginx: master process /usr/local/nginx/sbin/nginx
root 41202 0.0 0.1 9876 6112 ? S 19:31 0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx 41203 0.0 0.1 13736 5428 ? S 19:31 0:00 nginx: worker process
root 41210 0.0 0.0 221684 2372 pts/1 S+ 19:34 0:00 grep --color=auto nginx
[root@Nginx sbin]# curl -I 172.25.254.100
HTTP/1.1 200 OK
Server: nginx/1.26.1
Date: Tue, 20 Aug 2024 11:34:23 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 20 Aug 2024 09:05:53 GMT
Connection: keep-alive
ETag: "66c45c71-267"
Accept-Ranges: bytes
#回滚
#如果升级的版本发现问题需要回滚,可以重新拉起旧版本的worker
[root@Nginx sbin]# cp nginx nginx.26
[root@Nginx sbin]# mv -f nginx.24 nginx
[root@Nginx sbin]# kill -HUP 37832
[root@Nginx sbin]# ps aux | grep nginx
root 37832 0.0 0.0 9840 2604 ? Ss 19:20 0:00 nginx: master process /usr/local/nginx/sbin/nginx
root 41202 0.0 0.1 9876 6112 ? S 19:31 0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx 41203 0.0 0.1 13736 5428 ? S 19:31 0:00 nginx: worker process
nginx 41223 0.0 0.1 13700 4780 ? S 19:37 0:00 nginx: worker process
root 41226 0.0 0.0 221684 2488 pts/1 S+ 19:37 0:00 grep --color=auto nginx
[root@Nginx sbin]# kill -WINCH 41202
[root@Nginx sbin]# curl -I 172.25.254.100
HTTP/1.1 200 OK
Server: nginx/1.24.0 #版本回滚完成
Date: Tue, 20 Aug 2024 11:38:01 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 20 Aug 2024 09:05:53 GMT
Connection: keep-alive
ETag: "66c45c71-267"
Accept-Ranges: bytes
三. Nginx 核心配置详解
3.1 配置文件说明
nginx 官方帮助文档: http://nginx.org/en/docs/Nginx 的配置文件的组成部分:
- 主配置文件:nginx.conf
- 子配置文件: include conf.d/*.conf
- fastcgi, uwsgi,scgi 等协议相关的配置文件
- mime.types:支持的mime类型,MIME(Multipurpose Internet Mail Extensions)多用途互联网邮
- 件扩展类型,MIME消息能包含文本、图像、音频、视频以及其他应用程序专用的数据,是设定某
- 种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动
- 使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
nginx 配置文件格式说明:配置文件由指令与指令块构成每条指令以 ; 分号结尾,指令与值之间以空格符号分隔可以将多条指令放在同一行 , 用分号分隔即可 , 但可读性差 , 不推荐指令块以 { } 大括号将多条指令组织在一起 , 且可以嵌套指令块include 语句允许组合多个配置文件以提升可维护性使用 # 符号添加注释,提高可读性使用 $ 符号使用变量部分指令的参数支持正则表达式
# 全局配置端,对全局生效,主要设置 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 (快速拷贝到kernelsocket buffer) >>协议栈。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 {# ...# } stream 服务器相关配置段# 导入其他路径的配置文件#include /apps/nginx/conf.d/*.conf}
3.2 全局配置
- 正常运行必备的配置
- 优化性能相关的配置
- 用于调试及定位问题相关的配置
- 事件驱动相关的配置
user nginx nginx; #启动Nginx 工作进程的用户和组worker_processes [number | auto]; #启动 Nginx 工作进程的数量 , 一般设为和 CPU 核心数相同worker_cpu_affinity 00000001 00000010 00000100 00001000 | auto ;# 将 Nginx 工作进程绑定到指定的 CPU 核心,默认 Nginx 是不进行进程绑定的,绑定并不是意味着当前 nginx 进程独占以一核心CPU ,但是可以保证此进程不运行在其他核心上,这就极大减少了 nginx 的工作进程在不同的cpu核心上的来回跳转,减少了 CPU 对进程的资源分配与回收以及内存管理等,因此可以有效的提升 nginx 服务器的性能。CPU MASK: 00000001: 0 号 CPU00000010:1号CPU10000000:7号CPU# 示例worker_cpu_affinity 0001 0010 0100 1000; 第 0 号 --- 第 3 号 CPUworker_cpu_affinity 0101 1010;# 示例worker_processes 4;worker_cpu_affinity 00000010 00001000 00100000 10000000;[root@Nginx ~]# ps axo pid,cmd,psr | grep nginx31093 nginx: master process /apps 134474 nginx: worker process 134475 nginx: worker process 334476 nginx: worker process 534477 nginx: worker process 7# 错误日志记录配置,语法: error_log file [debug | info | notice | warn | error | crit| alert | emerg]#error_log logs/error.log;#error_log logs/error.log notice;error_log /usr/local/nginx/logs/error.log error;#pid 文件保存路径pid /usr/local/nginx/logs/nginx.pid;worker_priority 0; #工作进程优先级, -20~20(19)worker_rlimit_nofile 65536; #所有 worker 进程能打开的文件数量上限 ,#包括:Nginx的所有连接(例如与代理服务器的连接等)#而不仅仅是与客户端的连接#另一个考虑因素是实际的并发连接数不能超过系统级别的最大打开文件 数的限制#最好与ulimit -n 或者limits.conf的值保持一致,# 修改 pam 限制[root@Nginx ~]# sudo -u nginx ulimit -n1024[root@Nginx ~]# vim /etc/security/limits.conf* - nofile 100000[root@Nginx ~]# sudo -u nginx ulimit -n100000daemon off; #前台运行Nginx 服务用于测试、 docker 等环境。master_process off|on; #是否开启 Nginx 的 master-worker 工作模式,仅用于开发调试场景 , 默认为 onevents {worker_connections 65535; #设置单个工作进程的最大并发连接数use epoll; #使用epoll事件驱动,#Nginx支持众多的事件驱动,#比如:select、poll、epoll ,只能设置在 events 模块中设置accept_mutex on; #on 为同一时刻一个请求轮流由 work 进程处理 ,#而防止被同时唤醒所有worker#避免多个睡眠进程被唤醒的设置,默认为off#新请求会唤醒所有worker进程,此过程也称为"惊群"#因此nginx刚安装完以后要进行适当的优化。建议设置为onmulti_accept on; #on时Nginx服务器的每个工作进程可以同时接受多个新的网络连接#此指令默认为off,#即默认为一个工作进程只能一次接受一个新的网络连接#打开后几个同接受多个。建议设置为on}
[root@Nginx ~]# ulimit -n 102400
[root@Nginx ~]# ab -c 5000 -n 10000 http://172.25.254.100/
#默认配置不支持高并发,会出现以下错误日志
[root@Nginx ~]# tail /apps/nginx/logs/error.log
2020/09/24 21:19:33 [crit] 41006#0: *1105860 open() "/apps/nginx/html/50x.html"
failed (24: Too many open files), client: 10.0.0.7, server: localhost, request:
"GET / HTTP/1.0", host: "10.0.0.8"
2020/09/24 21:19:33 [crit] 41006#0: accept4() failed (24: Too many open files)
2020/09/24 21:19:33 [crit] 41006#0: *1114177 open()
"/apps/nginx/html/index.html" failed (24: Too many open files), client: 10.0.0.7,
server: localhost, request: "GET / HTTP/1.0", host: "10.0.0.8"
#修改配置
[root@Nginx ~]# vim /etc/security/limits.conf
* - nproc 100000
[root@Nginx ~]# vim /apps/nginx/conf/nginx.conf
worker_rlimit_nofile 100000;
[root@Nginx ~]# systemctl restart nginx
3.3 核心配置示例
3.3.1 新建一个 PC web 站点
#定义子配置文件路径
[root@Nginx ~]# mkdir /usr/local/nginx/conf.d/
[root@centos8 ~]# vim /usr/local/nginx/conf/nginx.conf
http {
......
include /apps/nginx/conf/conf.d/*.conf; #在配置文件的最后面添加此行
#注意不要放在最前面,会导致前面的命令无法生效
}
#创建虚拟主机网站配置
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
}
[root@Nginx ~]# nginx -s reload
[root@Nginx ~]# mkdir -p /data/web/html
[root@Nginx ~]# echo www.leoliu.org > /data/web/html/index.html
#访问测试
[root@Nginx ~]# echo 172.25.254.100 www.leoliu.org >> /etc/hosts
[root@Nginx ~]# curl www.leoliu.org
www.leoliu.org
3.3.2 root 与 alias
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location /test1 {
root /data/web;
}
}
[root@Nginx ~]# nginx -s reload
[root@Nginx ~]# mkdir -p /data/web/test1
[root@Nginx ~]# echo test1 > /data/web/test1/index.html
测试:(注意要在windows上做本地解析)
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location /test1 {
root /data/web;
}
location /test2 {
alias /data/web/test1;
}
}
[root@Nginx ~]# nginx -s reload
测试:
location 中使用 root 指令和 alias 指令的意义不同root # 给定的路径对应于 location 中的 /uri 左侧的 /alias # 给定的路径对应于 location 中的 /uri 的完整路径
3.3.3 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前,表示包含正则表达式并且转义字符。可以将 . * ? 等转义为普通符号#匹配优先级从高到低:#对目录匹配 (~* | ~) > 不带符号 > ^~ > = #=不能指定目录所以排在最后#对文件匹配 = > (~* | ~)> 不带符号 > ^~
3.3.3.1 匹配案例-精确匹配
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location /test1 {
root /data/web;
}
location = /test2 {
root /data/web;
}
}
[root@Nginx ~]# nginx -s reload
[root@Nginx ~]# mkdir /data/web/test2
[root@Nginx ~]# echo test2 > /data/web/test2/index.html
[root@Nginx ~]# curl www.leoliu.org/test2/
test2
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location /test1 {
root /data/web;
}
location ~ /Test2 {
root /data/web;
}
}
[root@Nginx ~]# nginx -s reload
[root@Nginx ~]# curl www.leoliu.org/test2/
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.24.0</center>
</body>
</html>
3.3.3.3 匹配案例-不区分大小写
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location /test1 {
root /data/web;
}
location ~* /Test2 {
root /data/web;
}
}
[root@Nginx ~]# nginx -s reload
[root@Nginx ~]# curl www.leoliu.org/test2/
test2
3.3.3.4 匹配案例-URI开始
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location /test1 {
root /data/web;
}
location ^~ /test {
root /data/web;
}
}
[root@Nginx ~]# nginx -s reload
[root@Nginx ~]# mkdir /data/web/test3
[root@Nginx ~]# echo test1 > /data/web/test3/index.html
[root@Nginx ~]# curl www.leoliu.org/test3/
test1
[root@Nginx ~]# curl www.leoliu.org/test1/
test1
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location /test1 {
root /data/web;
}
location ~* \.haha$ {
root /data/web;
}
}
[root@Nginx ~]# nginx -s reload
[root@Nginx ~]# echo test.haha > /data/web/test1/test.haha
[root@Nginx ~]# curl www.leoliu.org/test1/test.haha
test.haha
3.3.4 Nginx 账户认证功能
[root@Nginx ~]# htpasswd -cmb /usr/local/nginx/conf/.htpasswd admin liu #-b 表
示非交互建立用户认证
Adding password for user admin
[root@Nginx ~]# htpasswd -mb /usr/local/nginx/conf/.htpasswd exam liu #不加c
Adding password for user exam
[root@Nginx ~]# cat /usr/local/nginx/conf/.htpasswd
admin:$apr1$.noVZMUi$zFd46YMS632kk2a6YTSQ80
exam:$apr1$gnaOAcpu$q/nF9ep7A6rs.7G94SwMB/
[root@Nginx ~]# mkdir /data/web/liu
[root@Nginx ~]# echo liu > /data/web/liu/index.html
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location /liu {
root /data/web;
auth_basic "login password";
auth_basic_user_file "/usr/local/nginx/conf/.htpasswd";
}
}
[root@Nginx ~]# nginx -s reload
#测试
[root@Nginx ~]# curl www.leoliu.org/liu/ -u admin:liu
liu
[root@Nginx ~]# curl www.leoliu.org/liu/ -u exam:liu
liu
浏览器测试:
3.3.5 自定义错误页面
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
error_page 404 /40x.html;
location = /40x.html {
root /data/web/errorpage;
}
}
[root@Nginx ~]# nginx -s reload
[root@Nginx ~]# mkdir /data/web/errorpage
[root@Nginx ~]# echo error page > /data/web/errorpage/40x.html
[root@Nginx ~]# curl www.leoliu.org/xixi
error page
浏览器测试:
3.3.6 自定义错误日志
[root@Nginx ~]# mkdir /var/log/nginx
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
error_page 404 /40x.html;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location = /40x.html {
root /data/web/errorpage;
}
}
[root@Nginx ~]# nginx -s reload
#测试
[root@Nginx ~]# curl www.leoliu.org
www.leoliu.org
[root@Nginx ~]# cat /var/log/nginx/access.log
172.25.254.100 - - [22/Aug/2024:18:40:51 +0800] "GET / HTTP/1.1" 200 15 "-" "curl/7.76.1"
[root@Nginx ~]# curl www.leoliu.org/xixi
error page
[root@Nginx ~]# cat /var/log/nginx/error.log
2024/08/22 18:41:30 [error] 3877#0: *65 open() "/data/web/html/xixi" failed (2: No such file or directory), client: 172.25.254.100, server: www.leoliu.org, request: "GET /xixi HTTP/1.1", host: "www.leoliu.org"
3.3.7 检测文件是否存在
try_files 会按顺序检查文件是否存在,返回第一个找到的文件或文件夹(结尾加斜线表示为文件夹),如果所有文件或文件夹都找不到,会进行一个内部重定向到最后一个参数。只有最后一个参数可以引起一个内部重定向,之前的参数只设置内部URI 的指向。最后一个参数是回退 URI 且必须存在,否则会出现内部500 错误。
[root@Nginx ~]# mkdir /data/web/html/error
[root@Nginx ~]# echo index.html is not exist > /data/web/html/error/default.html
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
error_page 404 /40x.html;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
try_files $uri $uri.html $uri/index.html /error/default.html;
location = /40x.html {
root /data/web/errorpage;
}
}
[root@Nginx ~]# nginx -s reload
#测试
[root@Nginx ~]# curl www.leoliu.org/haha
index.html is not exist
[root@Nginx ~]# curl www.leoliu.org/heihei
index.html is not exist
3.3.8 长连接配置
keepalive_timeout timeout [header_timeout]; #设定保持连接超时时长, 0 表示禁止长连接,默认为75s#通常配置在http字段作为站点全局配置keepalive_requests 数字; #在一次长连接上所允许请求的资源的最大数量#默认为100次,建议适当调大,比如:500
[root@Nginx ~]# vim /usr/local/nginx/conf/nginx.conf
keepalive_requests 2; #允许请求2次
keepalive_timeout 65 60; #开启长连接后,返回客户端的会话保持时间为60s,单次长连接累计请求达到指定次数请求或65秒就会被断开,第二个数字60为发送给客户端应答报文头部中显示的超时时间设置为60s:如不设置客户端将不显示超时间。
[root@Nginx ~]# nginx -s reload
#使用命令测试:
[root@Nginx ~]# telnet www.leoliu.org 80
Trying 172.25.254.100...
Connected to www.leoliu.org.
Escape character is '^]'.
GET / HTTP/1.1 #输入动作
HOST: www.leoliu.org #输入访问HOST
#输入回车
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Thu, 22 Aug 2024 11:22:33 GMT
Content-Type: text/html
Content-Length: 15
Last-Modified: Wed, 21 Aug 2024 08:25:21 GMT
Connection: keep-alive
Keep-Alive: timeout=60
ETag: "66c5a471-f"
Accept-Ranges: bytes
www.leoliu.org
GET / HTTP/1.1 #第二次输入
HOST: www.leoliu.org #第二次输入
#第二次输入
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Thu, 22 Aug 2024 11:26:51 GMT
Content-Type: text/html
Content-Length: 15
Last-Modified: Wed, 21 Aug 2024 08:25:21 GMT
Connection: close
ETag: "66c5a471-f"
Accept-Ranges: bytes
www.leoliu.org
Connection closed by foreign host. #自动断开链接
3.3.9 作为下载服务器配置
autoindex on | off; #自动文件索引功能,默为offautoindex_exact_size on | off; #计算文件确切大小(单位 bytes ), off 显示大概大小(单位 K 、M),默认 onautoindex_localtime on | off ; #显示本机时间而非 GMT( 格林威治 ) 时间,默认 offautoindex_format html | xml | json | jsonp; #显示索引的页面文件风格,默认 htmllimit_rate rate; #响应客户端传输速率(除GET 和 HEAD 以外的所有方法 ) ,单位B/s,bytes/second, # 默认值 0, 表示无限制 , 此指令由ngx_http_core_module 提供set $limit_rate 4k; #也可以通变量限速, 单位 B/s, 同时设置 , 此项优级高 .
[root@Nginx ~]# mkdir /data/web/download
[root@Nginx ~]# dd if=/dev/zero of=/data/web/download/liufile bs=1M count=100
记录了100+0 的读入
记录了100+0 的写出
104857600字节(105 MB,100 MiB)已复制,0.11359 s,923 MB/s
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location /download {
root /data/web;
autoindex on; #自动索引功能
autoindex_exact_size on; #计算文件确切大小(单位bytes),此为默认值,off只显示大概大小(单位kb、mb、gb)
autoindex_localtime on; #on表示显示本机时间而非GMT(格林威治)时间,默为为off显示GMT时间
limit_rate 1024k; #限速,默认不限速
}
}
[root@Nginx ~]# nginx -s reload
#访问测试下载页面
[root@Nginx ~]# wget http://www.leoliu.org/download/liufile
--2024-08-22 19:40:14-- http://www.leoliu.org/download/liufile
正在解析主机 www.leoliu.org (www.leoliu.org)... 172.25.254.100
正在连接 www.leoliu.org (www.leoliu.org)|172.25.254.100|:80... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:104857600 (100M) [application/octet-stream]
正在保存至: “liufile”
liufile 41%[====> ] 41.00M 1.00MB/s 剩余 59s ^
四. Nginx 高级配置
4.1 Nginx 状态页
- 基于nginx 模块 ngx_http_stub_status_module 实现,
- 在编译安装nginx的时候需要添加编译参数 --with-http_stub_status_module
- 否则配置完成之后监测会是提示法错误
注意 : 状态页显示的是整个服务器的状态 , 而非虚拟主机的状态
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location /status {
root /data/web;
stub_status;
auth_basic "auth login";
auth_basic_user_file /usr/local/nginx/conf/.htpasswd;
allow 172.25.254.1; #指定windows访问
deny all;
}
}
[root@Nginx ~]# nginx -s reload
#状态页用于输出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)
4.2 Nginx 压缩功能
Nginx 支持对指定类型的文件进行压缩然后再传输给客户端,而且压缩还可以设置压缩比例,压缩后的文件大小将比源文件显著变小,样有助于降低出口带宽的利用率,降低企业的IT 支出,不过会占用相应的CPU 资源。Nginx 对文件的压缩功能是依赖于模块 ngx_http_gzip_module, 默认是内置模块
# 启用或禁用 gzip 压缩,默认关闭gzip on | off;# 压缩比由低到高从 1 到 9 ,默认为 1 ,值越高压缩后文件越小,但是消耗 cpu 比较高。基本设定未 4 或者 5gzip_comp_level 4;# 禁用 IE6 gzip 功能,早期的 IE6 之前的版本不支持压缩gzip_disable "MSIE [1-6]\.";#gzip 压缩的最小文件,小于设置值的文件将不会压缩gzip_min_length 1k;# 启用压缩功能时,协议的最小版本,默认 HTTP/1.1gzip_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;
#重启nginx并进行访问测试压缩功能
[root@Nginx ~]# vim /usr/local/nginx/conf/nginx.conf
............
gzip on;
gzip_comp_level 5;
gzip_min_length 1k;
gzip_http_version 1.1;
gzip_vary on; gzip_types text/plain application/javascript application/x-javascript text/cssapplication/xml text/javascript application/x-httpd-php image/gif image/png;
[root@Nginx ~]# echo hello > /data/web/html/small.html #小于1k的文件测试是否会压缩
[root@Nginx ~]# cat /usr/local/nginx/logs/access.log > /data/web/html/big.html #大于1k文件
#访问测试:
[root@Nginx ~]# curl --head --compressed www.leoliu.org/small.html
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Thu, 22 Aug 2024 12:42:11 GMT
Content-Type: text/html
Content-Length: 6
Last-Modified: Thu, 22 Aug 2024 12:40:40 GMT
Connection: keep-alive
Keep-Alive: timeout=60
ETag: "66c731c8-6"
Accept-Ranges: bytes #没有压缩
[root@Nginx ~]# curl --head --compressed www.leoliu.org/big.html
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Thu, 22 Aug 2024 12:42:34 GMT
Content-Type: text/html
Last-Modified: Thu, 22 Aug 2024 12:39:06 GMT
Connection: keep-alive
Keep-Alive: timeout=60
Vary: Accept-Encoding
ETag: W/"66c7316a-35f3"
Content-Encoding: gzip #压缩了
4.3 Nginx的版本隐藏
[root@Nginx nginx-1.26.1]# vim src/core/nginx.h
#define nginx_version 1026001
#define NGINX_VERSION "1.0"
#define NGINX_VER "HAHA/" NGINX_VERSION
4.4 Nginx 变量使用
- nginx的变量可以在配置文件中引用,作为功能判断或者日志等场景使用
- 变量可以分为内置变量和自定义变量
- 内置变量是由nginx模块自带,通过变量可以获取到众多的与客户端访问相关的值
4.4.1 内置变量
$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 的对应的首部字段名需要为小写,如果有横线需要替换为下划线# 示例 :echo $http_user_agent;echo $http_host;$sent_http_<name>#name 为响应报文的首部字段, name 的对应的首部字段名需要为小写,如果有横线需要替换为下划线 , 此变量有问题echo $sent_http_server;$arg_<name># 此变量存放了 URL 中的指定参数, name 为请求 url 中指定的参数echo $arg_id;
[root@Nginx sbin]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location /var {
default_type text/html;
echo $remote_addr;
echo $args;
echo $document_root;
echo $document_uri;
echo $host;
echo $http_user_agent;
echo $request_filename;
echo $scheme;
echo $scheme://$host$document_uri?$args;
echo $http_cookie;
echo $cookie_key2;
echo $http_Accept;
set $liu leoliu;
echo $liu;
}
}
[root@Nginx sbin]# nginx -s reload
[root@Nginx ~]# curl -b "key1=liu1,key2=liu2" www.leoliu.org/var?search=liu&&id=66666666
172.25.254.100
search=liu
/data/web/html
/var
www.leoliu.org
curl/7.76.1
/data/web/html/var
http
http://www.leoliu.org/var?search=liu
key1=liu1,key2=liu2
liu2
*/*
leoliu
五. Nginx Rewrite 相关功能
- Nginx服务器利用 ngx_http_rewrite_module 模块解析和处理rewrite请求
- 此功能依靠 PCRE(perl compatible regular expression),因此编译之前要安装PCRE库
- rewrite是nginx服务器的重要功能之一,用于实现URL的重写,URL的重写是非常有用的功能
- 比如它可以在我们改变网站结构之后,不需要客户端修改原来的书签,也无需其他网站修改我们的 链接,就可以设置为访问
- 另外还可以在一定程度上提高网站的安全性。
5.1 ngx_http_rewrite_module 模块指令
5.1.1 if 指令
用于条件匹配判断,并根据条件判断结果选择不同的 Nginx 配置,可以配置在 server 或 location 块中进行配置,Nginx 的 if 语法仅能使用 if 做单次判断,不支持使用 if else 或者 if elif 这样的多重判断,用法如下:if (条件匹配) {action}
= #比较变量和字符串是否相等,相等时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 ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location /test {
if ( !-e $request_filename ){
echo "$request_filename is not exist";
}
}
}
[root@Nginx ~]# nginx -s reload
[root@Nginx ~]# curl www.leoliu.org/test
/data/web/html/test is not exist
5.1.2 set 指令
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location /test {
set $name haha;
echo $name;
}
}
[root@Nginx ~]# nginx -s reload
[root@Nginx ~]# curl www.leoliu.org/test
haha
5.1.3 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/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location /break {
default_type text/html;
set $name haha;
echo $name;
break;
set $id 123456;
echo $id;
}
}
[root@Nginx ~]# nginx -s reload
[root@Nginx ~]# curl www.leoliu.org/break #当未添加break时
haha
123456
[root@Nginx ~]# curl www.leoliu.org/break #添加break后
haha
5.1.4 return 指令
return 用于完成对请求的处理,并直接向客户端返回响应状态码,比如 : 可以指定重定向 URL( 对于特殊重定向状态码,301/302 等 ) 或者是指定提示文本内容 ( 对于特殊状态码 403/500 等 ) ,处于此指令后的所有配置都将不被执行,return 可以在 server 、 if 和 location 块进行配置语法格式:return code; #返回给客户端指定的HTTP 状态码return code [text]; #返回给客户端的状态码及响应报文的实体内容#可以调用变量,其中text如果有空格 , 需要用单或双引号return code URL; #返回给客户端的 URL 地址
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location /return {
default_type text/html;
if ( !-e $request_filename){
return 301 http://www.baidu.com;
}
echo "$request_filename is exist";
}
}
[root@Nginx ~]# nginx -s reload
[root@Nginx ~]# mkdir /data/web/html/return
[root@Nginx ~]# curl www.leoliu.org/return
/data/web/html/return is exist
[root@Nginx ~]# curl -I www.leoliu.org/return1
HTTP/1.1 301 Moved Permanently
Server: nginx/1.26.1
Date: Thu, 22 Aug 2024 14:00:35 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Keep-Alive: timeout=60
Location: http://www.baidu.com #访问到百度上了
5.2 rewrite 指令
通过正则表达式的匹配来改变 URI ,可以同时存在一个或多个指令,按照顺序依次对 URI 进行匹配, rewrite主要是针对用户请求的 URL 或者是 URI 做具体处理官方文档: https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewriterewrite 将用户请求的 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 这几个字母以外的任意字符
5.2.1 rewrite flag 使用介绍
利用 nginx 的 rewrite 的指令,可以实现 url 的重新跳转, rewrite 有四种不同的 flag ,分别是 redirect( 临时重定向302) 、 permanent( 永久重定向 301) 、 break 和 last 。其中前两种是跳转型的 flag ,后两种是代理型
- 跳转型指由客户端浏览器重新对新地址进行请求
- 代理型是在WEB服务器内部实现跳转
redirect;# 临时重定向,重写完成后以临时重定向方式直接返回重写后生成的新 URL 给客户端# 由客户端重新发起请求 ; 使用相对路径 , 或者 http:// 或 https:// 开头,状态码: 302permanent;# 重写完成后以永久重定向方式直接返回重写后生成的新 URL 给客户端# 由客户端重新发起请求,状态码: 301break;# 重写完成后 , 停止对当前 URL 在当前 location 中后续的其它重写操作# 而后直接跳转至重写规则配置块之后的其它配置,结束循环,建议在 location 中使用# 适用于一个 URL 一次重写last;# 重写完成后 , 停止对当前 URI 在当前 location 中后续的其它重写操作,# 而后对新的 URL 启动新一轮重写检查,不建议在 location 中使用# 适用于一个 URL 多次重写,要注意避免出现超过十次以及 URL 重写后返回错误的给用户
5.2.2 rewrite案例: 域名永久与临时重定向
域名的临时的调整,后期可能会变,之前的域名或者 URL 可能还用、或者跳转的目的域名和 URL 还会跳转,这种情况浏览器不会缓存跳转, 临时重定向不会缓存域名解析记录 (A 记录 ) ,但是永久重定向会缓存。
5.2.2.1 永久重定向304
域名永久型调整,即域名永远跳转至另外一个新的域名,之前的域名再也不使用,跳转记录可以缓存到客户端浏览器永久重定向会缓存 DNS 解析记录 , 浏览器中有 from disk cache 信息 , 即使 nginx 服务器无法访问 , 浏览器也会利用缓存进行重定向
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location / {
rewrite / http://www.leoliu.com permanent;
}
}
server {
listen 80;
server_name www.leoliu.com;
root /data/web/html;
index index.html;
}
[root@Nginx ~]# nginx -s reload
测试:
5.2.2.2 临时重定向302
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location / {
rewrite / http://www.leoliu.com redirect;
}
}
server {
listen 80;
server_name www.leoliu.com;
root /data/web/html;
index index.html;
}
[root@Nginx ~]# nginx -s reload
测试:
5.2.3 rewrite 案例: break 与 last
5.2.3.1 break和last区别案例
[root@Nginx ~]# mkdir /data/web/html/{test1,test2,break,last}
[root@Nginx ~]# echo test1 > /data/web/html/test1/index.html
[root@Nginx ~]# echo test2 > /data/web/html/test2/index.html
[root@Nginx ~]# echo break > /data/web/html/break/index.html
[root@Nginx ~]# echo last > /data/web/html/last/index.html
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location /break {
rewrite ^/break/(.*) /test1/$1 break;
rewrite ^/test1/(.*) /test2/$1 ;
}
location /last {
rewrite ^/last/(.*) /test1/$1 last;
rewrite ^/test1/(.*) /test2/$1 ;
}
location /test1 {
default_type text/html;
return 666 "new test1";
}
location /test2 {
root /data/web/html;
}
}
[root@Nginx ~]# nginx -s reload
[root@Nginx ~]# curl -L www.leoliu.org/break/index.html
test1
[root@Nginx ~]# curl -L www.leoliu.org/last/index.html
new test1[root@Nginx ~]#
5.2.4 rewrite案例: 自动跳转 https
[root@Nginx ~]# cd /usr/local/nginx/
[root@Nginx nginx]# mkdir certs
[root@Nginx nginx]# openssl req -newkey rsa:2048 -nodes -sha256 -keyout /usr/local/nginx/certs/liu.key -x509 -days 365 -out /usr/local/nginx/certs/liu.crt
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:shaanxi
Locality Name (eg, city) [Default City]:xi'an
Organization Name (eg, company) [Default Company Ltd]:leoliu
Organizational Unit Name (eg, section) []:IT
Common Name (eg, your name or your server's hostname) []:www.leoliu.org
Email Address []:admin@leoliu.org
[root@Nginx nginx]# ls certs/
liu.crt liu.key
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
listen 443 ssl;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
ssl_certificate /usr/local/nginx/certs/liu.crt;
ssl_certificate_key /usr/local/nginx/certs/liu.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
location / {
if ($scheme = http ){
rewrite / https://$host redirect;
}
}
}
[root@Nginx ~]# nginx -s reload
测试:
5.2.5 rewrite 案例: 判断文件是否存在
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
listen 443 ssl;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
ssl_certificate /usr/local/nginx/certs/liu.crt;
ssl_certificate_key /usr/local/nginx/certs/liu.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
location / {
if ($scheme = http ){
rewrite / https://$host redirect;
}
if (!-e $request_filename) {
rewrite /(.*) https://www.leoliu.org/index.html redirect;
}
}
}
[root@Nginx ~]# nginx -s reload
测试:输入www.leoliu.org/a/b,没有这个文件会自动跳转
none: #请求报文首部没有 referer 首部,#比如用户直接在浏览器输入域名访问web网站,就没有referer 信息。blocked: #请求报文有 referer 首部,但无有效值,比如为空。server_names: #referer 首部中包含本主机名及即 nginx 监听的 server_name 。arbitrary_string: # 自定义指定字符串,但可使用 * 作通配符。示例 : *.timinglee.orgwww.timinglee.*regular expression : # 被指定的正则表达式模式匹配到的字符串 , 要使用 ~ 开头,例如:~.*\.timinglee\.com
#新建一个主机172.25.254.10,盗取另一台主机www.leoliu.org/images/R.png的图片
[root@Nginx ~]# mkdir /data/web/html/images
[root@Nginx ~]# cd /data/web/html/images/
[root@Nginx images]# rz -E
rz waiting to receive.
[root@Nginx images]# ls
R.png
[root@web1 ~]# yum install httpd -y
[root@web1 ~]# vim /var/www/html/index.html
<html>
<head>
<meta http-equiv=Content-Type content="text/html;charset=utf-8">
<title>盗链</title>
</head>
<body>
<img src="http://www.leoliu.org/images/R.png" >
<h1 style="color:red">欢迎大家</h1>
<p><a href=http://www.leoliu.org>柳飞飘絮</a>出门见喜</p>
</body>
</html>
[root@web1 ~]# systemctl enable --now httpd
#验证两个域名的日志,是否会在被盗连的web站点的日志中出现以下盗链日志信息:
[root@Nginx html]# cat /usr/local/nginx/logs/access.log
172.25.254.1 - exam [23/Aug/2024:16:45:17 +0800] "GET /images/R.png HTTP/1.1" 200 46637 "http://172.25.254.10/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"
[root@web1 ~]# cat /etc/httpd/logs/access_log
172.25.254.1 - - [23/Aug/2024:16:45:17 +0800] "GET / HTTP/1.1" 200 301 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"
172.25.254.1 - - [23/Aug/2024:16:45:17 +0800] "GET /favicon.ico HTTP/1.1" 404 196 "http://172.25.254.10/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"
172.25.254.1 - - [23/Aug/2024:16:46:09 +0800] "-" 408 - "-" "-"
正常访问www.leoliu.org/images/R.png
5.3.2 实现防盗链
基于访问安全考虑, nginx 支持通过 ngx_http_referer_module 模块 , 检查访问请求的 referer 信息是否有效实现防盗链功能官方文档: https://nginx.org/en/docs/http/ngx_http_referer_module.html
[root@Nginx html]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location /images {
valid_referers none blocked server_names *.timinglee.org ~\.baidu\.;
if ($invalid_referer){
return 403;
#rewrite ^/ http://www.leoliu.org/daolian.png permanent;
}
}
}
[root@Nginx html]# nginx -s reload
[root@Nginx ~]# cd /data/web/html/
[root@Nginx html]# rz -E
rz waiting to receive.
[root@Nginx html]# ls
big.html daolian.png images last small.html test2
break error index.html return test1 var
再次访问172.25.254.10,可以看见盗取不了了
六. 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 协议转发至指定服务器处理
6.1 实现 http 反向代理
6.1.1 http 协议反向代理
6.1.1.1 反向代理配置参数
#官方文档:https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
proxy_pass; #用来设置将客户端请求转发给的后端服务器的主机
#可以是主机名(将转发至后端服务做为主机头首部)、IP地址:端口的方式
#也可以代理到预先设置的主机群组,需要模块ngx_http_upstream_module支持
#示例:
location /web {
index index.html;
proxy_pass http://172.25.254.30:8080; #8080后面无uri,即无 / 符号,
#需要将location后面url 附加到proxy_pass指定的 url后面
#此行为类似于root
#proxy_pass指定的uri不带斜线将访问的/web
#等于访问后端服务器
proxy_pass http://172.25.254.40:8080/; #8080后面有uri,即有 / 符号
#相当于置换,即访问/web时实际返回proxy_pass后面uri内容
#此行为类似于alias
#proxy_pass指定的uri带斜线
#等于访问后端服务器的
#http://172.25.254.40:8080/index.html
#内容返回给客户端
} # http://nginx/web/index.html ==>http://1:8080
#重启Nginx测试访问效果:
#curl -L http://www.zhang.org/web
#如果location定义其uri时使用了正则表达式模式(包括~,~*,但不包括^~),则proxy_pass之后必须不能使用uri
#即不能有/ ,用户请求时传递的uri将直接附加至后端服务器之后
server {
...
server_name HOSTNAME;
location ~|~* /uri/ {
proxy_pass http://host:port; #proxy_pass后面的url 不能加/
}
...
}
http://HOSTNAME/uri/ --> http://host/uri/
proxy_hide_header field; #用于 nginx 作为反向代理的时候#在返回给客户端http响应时#隐藏后端服务器相应头部的信息#可以设置在http,server或location块# 示例 : 隐藏后端服务器 ETag 首部字段location /web {index index.html;proxy_pass http://10.0.0.18:8080/;proxy_hide_header ETag;}proxy_pass_header field; # 透传# 默认 nginx 在响应报文中不传递后端服务器的首部字段 Date, Server, X-Pad, X-Accel 等参数# 如果要传递的话则要使用 proxy_pass_header field 声明将后端服务器返回的值传递给客户端#field 首部字段大小不敏感# 示例 : 透传后端服务器的 Server 和 Date 首部给客户端 , 同时不再响应报中显示前端服务器的 Server 字段proxy_pass_header Server;proxy_pass_header Date;proxy_pass_request_body on | off;# 是否向后端服务器发送 HTTP 实体部分 , 可以设置在 http,server 或 location 块,默认即为开启proxy_pass_request_headers on | off;# 是否将客户端的请求头部转发给后端服务器,可以设置在 http,server 或 location 块,默认即为开启proxy_set_header;# 可更改或添加客户端的请求头部信息内容并转发至后端服务器,比如在后端服务器想要获取客户端的真实 IP 的时候,就要更改每一个报文的头部# 示例 :location ~ /web {proxy_pass http://172.25.254.20:80;proxy_hide_header ETag;proxy_pass_header Server;proxy_pass_request_body on;proxy_pass_request_headers on;proxy_set_header X-Forwarded-For $remote_addr;}[root@apache20 ~]# vim /etc/httpd/conf/httpd.confLogFormat "\"%{X-Forwarded-For}i\" %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined访问后看后端服务器日志proxy_connect_timeout time;# 配置 nginx 服务器与后端服务器尝试建立连接的超时时间,默认为 60 秒用法如下: proxy_connect_timeout 6s;#60s 为自定义 nginx 与后端服务器建立连接的超时时间 , 超时会返回客户端 504 响应码proxy_read_timeout time;# 配置 nginx 服务器向后端服务器或服务器组发起 read 请求后,等待的超时时间,默认 60sproxy_send_timeout time;# 配置 nginx 项后端服务器或服务器组发起 write 请求后,等待的超时 时间,默认 60sproxy_http_version 1.0;# 用于设置 nginx 提供代理服务的 HTTP 协议的版本,默认 http 1.0proxy_ignore_client_abort off;# 当客户端网络中断请求时, nginx 服务器中断其对后端服务器的请求。即如果此项设置为 on 开启,则服务器、会忽略客户端中断并一直等着代理服务执行返回,如果设置为 off ,则客户端中断后 Nginx 也会中断客户端请求并立即记录 499 日志,默认为 off 。
6.1.1.2 实战案例: 反向代理单台 web 服务器
#环境配置添加两台主机,分别是web1:172.25.254.10和web2:172.25.254.20 ,部署后端 Apache服务器
[root@web1 ~]# yum install httpd -y
[root@web1 ~]# echo 172.25.254.10 > /var/www/html/index.html
[root@web1 ~]# systemctl enable --now httpd
[root@web2 ~]# yum install httpd -y
[root@web2 ~]# echo 172.25.254.20 > /var/www/html/index.html
[root@web2 ~]# systemctl enable --now httpd
验证通不通:
[root@Nginx ~]# curl 172.25.254.10
172.25.254.10
[root@Nginx ~]# curl 172.25.254.20
172.25.254.20
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location / {
proxy_pass http://172.25.254.10;
}
}
[root@Nginx ~]# nginx -s reload
[C:\~]$ curl www.leoliu.org
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 100 14 100 14 0 0 554 0 --:--:-- --:--:-- --:--:-- 666
172.25.254.10
6.1.1.3 实战案例: 指定 location 实现反向代理
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location / {
proxy_pass http://172.25.254.10;
}
location ~ /static {
proxy_pass http://172.25.254.20:8080;
}
}
[root@Nginx ~]# nginx -s reload
#修改端口
[root@web2 ~]# vim /etc/httpd/conf/httpd.conf
Listen 8080
[root@web2 ~]# mkdir /var/www/html/static
[root@web2 ~]# echo static 172.25.254.20 > /var/www/html/static/index.html
[root@web2 ~]# systemctl restart httpd
访问
[C:\~]$ curl www.leoliu.org/static/
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 100 21 100 21 0 0 781 0 --:--:-- --:--:-- --:--:-- 954
static 172.25.254.20
6.1.1.4 反向代理示例: 缓存功能
proxy_cache zone_name | off; 默认 off# 指明调用的缓存,或关闭缓存机制 ;Context:http, server, location#zone_name 表示缓存的名称 . 需要由 proxy_cache_path 事先定义proxy_cache_key string;# 缓存中用于 “ 键 ” 的内容,默认值: proxy_cache_key $scheme$proxy_host$request_uri;proxy_cache_valid [code ...] time;# 定义对特定响应码的响应内容的缓存时长,定义在 http{...} 中示例 :proxy_cache_valid 200 302 10m;proxy_cache_valid 404 1m;proxy_cache_path;# 定义可用于 proxy 功能的缓存 ;Context:httpproxy_cache_path path [levels=levels] [use_temp_path=on|off]keys_zone=zone_name:size [inactive=time] [max_size=size] [manager_files=number][manager_sleep=time] [manager_threshold=time] [loader_files=number][loader_sleep=time] [loader_threshold=time] [purger=on|off][purger_files=number] [purger_sleep=time] [purger_threshold=time];# 示例:在 http 配置定义缓存信息proxy_cache_path /var/cache/nginx/proxy_cache # 定义缓存保存路径, proxy_cache 会自动创建levels=1:2:2 #定义缓存目录结构层次#1:2:2 可以生成2^4x2^8x2^8=2^20=1048576 个目录keys_zone=proxycache:20m #指内存中缓存的大小,主要用于存放key 和 metadata (如:使用次数)#一般1M可存放8000个左右的keyinactive=120s #缓存有效时间max_size=10g; #最大磁盘占用空间,磁盘存入文件内容的缓存空间最大值# 调用缓存功能,需要定义在相应的配置段,如 server{...}; 或者 location 等proxy_cache proxycache;proxy_cache_key $request_uri; #对指定的数据进行MD5 的运算做为缓存的 keyproxy_cache_valid 200 302 301 10m; #指定的状态码返回的数据缓存多长时间proxy_cache_valid any 1m; #除指定的状态码返回的数据以外的缓存多长时间 , 必须设置 ,否则不会缓存proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 |http_502 | http_503 | http_504 | http_403 | http_404 | off ; #默认是 off#在被代理的后端服务器出现哪种情况下,可直接使用过期的缓存响应客户端# 示例proxy_cache_use_stale error http_502 http_503;proxy_cache_methods GET | HEAD | POST ...;# 对哪些客户端请求方法对应的响应进行缓存, GET 和 HEAD 方法总是被缓存
6.1.2 http 反向代理负载均衡
在上一个节中 Nginx 可以将客户端的请求转发至单台后端服务器但是无法转发至特定的一组的服务器,而且不能对后端服务器提供相应的服务器状态监测,Nginx 可以基于 ngx_http_upstream_module 模块提供服务器分组转发、权重分配、状态监测、调度算法等高级功能官方文档: https://nginx.org/en/docs/http/ngx_http_upstream_module.html
6.1.2.1 http upstream配置参数
# 自定义一组服务器,配置在 http 块内upstream name {server ...........}# 示例upstream backend {server backend1.example.com weight=5;server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;server unix:/tmp/backend3;server backup1.example.com backup;}server address [parameters];# 配置一个后端 web 服务器,配置在 upstream 内,至少要有一个 server 服务器配置。#server 支持的 parameters 如下:weight=number #设置权重,默认为1, 实现类似于 LVS 中的 WRR,WLC 等max_conns=number #给当前后端 server 设置最大活动链接数,默认为 0 表示没有限制max_fails=number #后端服务器的下线条件 , 当客户端访问时 , 对本次调度选中的后端服务器连续进行检测多少次, 如果都失败就标记为不可用 , 默认为 1 次 , 当客户端访问时 , 才会利用 TCP 触发对探测后端服务器健康性检查, 而非周期性的探测fail_timeout=time #后端服务器的上线条件 , 对已经检测到处于不可用的后端服务器 , 每隔此时间间隔再次进行检测是否恢复可用,如果发现可用, 则将后端服务器参与调度 , 默认为 10 秒backup #设置为备份服务器,当所有后端服务器不可用时, 才会启用此备用服务器down #标记为down 状态 , 可以平滑下线后端服务器resolve #当 server 定义的是主机名的时候,当 A 记录发生变化会自动应用新 IP 而不用重启 Nginxhash KEY [consistent];# 基于指定请求报文中首部字段或者 URI 等 key 做 hash 计算,使用 consistent 参数,将使用 ketama 一致性 hash算法,适用于后端是 Cache 服务器(如 varnish )时使用, consistent 定义使用一致性 hash 运算,一致性hash 基于取模运算hash $request_uri consistent; # 基于用户请求的 uri 做 hashhash $cookie_sessionid # 基于 cookie 中的 sessionid 这个 key 进行 hash 调度 , 实现会话绑定ip_hash;# 源地址 hash 调度方法,基于的客户端的 remote_addr( 源地址 IPv4 的前 24 位或整个 IPv6 地址 ) 做 hash 计算,以实现会话保持least_conn;# 最少连接调度算法,优先将客户端请求调度到当前连接最少的后端服务器 , 相当于 LVS 中的 WLC
6.1.2.2 反向代理示例: 后端多台 web服务器
#环境配置添加两台主机,分别是web1:172.25.254.10和web2:172.25.254.20 ,部署后端 Apache服务器
[root@web1 ~]# yum install httpd -y
[root@web1 ~]# echo 172.25.254.10 > /var/www/html/index.html
[root@web1 ~]# systemctl enable --now httpd
[root@web2 ~]# yum install httpd -y
[root@web2 ~]# echo 172.25.254.20 > /var/www/html/index.html
[root@web2 ~]# systemctl enable --now httpd
验证通不通:
[root@Nginx ~]# curl 172.25.254.10
172.25.254.10
[root@Nginx ~]# curl 172.25.254.20
172.25.254.20
#配置 nginx 反向代理
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
upstream webserver {
#ip_hash;
#hash $request_uri consistent;
#hash $cookie_lee
#least_conn;
server 172.25.254.20:8080 weight=1 fail_timeout=15s max_fails=3;
server 172.25.254.10:80 weight=1 fail_timeout=15s max_fails=3;
server 172.25.254.100:80 backup;
}
server {
listen 80;
server_name www.leoliu.org;
location / {
proxy_pass http://webserver;
}
}
[root@Nginx ~]# nginx -s reload
#访问测试
[C:\~]$ curl www.leoliu.org
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 100 14 100 14 0 0 479 0 --:--:-- --:--:-- --:--:-- 560
172.25.254.20
[C:\~]$ curl www.leoliu.org
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 100 14 100 14 0 0 499 0 --:--:-- --:--:-- --:--:-- 583
172.25.254.10
6.2 实现 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 模块官方文档: https://nginx.org/en/docs/stream/ngx_stream_proxy_module.html
6.2.1 tcp负载均衡配置参数
stream { #定义stream相关的服务;Context:mainupstream backend { #定义后端服务器hash $remote_addr consistent; #定义调度算法server backend1.example.com:12345 weight=5; #定义具体serverserver 127.0.0.1:12345 max_fails=3 fail_timeout=30s;server unix:/tmp/backend3;}upstream dns { #定义后端服务器server 10.0.0.1:53; #定义具体serverserver dns.example.com:53;}server { #定义serverlisten 12345; #监听IP:PORTproxy_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;}}
6.2.2 udp 负载均衡实例: DNS
#web1和web2配置dns服务
[root@web1 ~]# yum install bind -y
[root@web1 ~]# vim /etc/named.conf
options {
# listen-on port 53 { 127.0.0.1; };
# listen-on-v6 port 53 { ::1; };
...........
# allow-query { localhost; };
..........
dnssec-validation no;
[root@web1 ~]# vim /etc/named.rfc1912.zones
zone "leoliu.org" IN {
type master;
file "named.org";
allow-update { none; };
};
[root@web1 ~]# cp /var/named/named.localhost /var/named/named.org -p
[root@web1 ~]# vim /var/named/named.org
$TTL 1D
@ IN SOA ns.leoliu.org. root.leoliu.org. (
0 ; serial
1D ; refresh
1H ; retry
1W ; expire
3H ) ; minimum
NS ns.leoliu.org.
ns A 172.25.254.10
www A 172.25.254.10
[root@web1 ~]# systemctl restart named
#测试
[root@web1 ~]# dig www.leoliu.org @172.25.254.10
; <<>> DiG 9.16.23-RH <<>> www.leoliu.org @172.25.254.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33707
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 8a40200c16cd15680100000066c871d81575d3d5e1db2b25 (good)
;; QUESTION SECTION:
;www.leoliu.org. IN A
;; ANSWER SECTION:
www.leoliu.org. 86400 IN A 172.25.254.10
;; Query time: 1 msec
;; SERVER: 172.25.254.10#53(172.25.254.10)
;; WHEN: Fri Aug 23 19:26:16 CST 2024
;; MSG SIZE rcvd: 87
###web2做一样的操作
[root@web2 ~]# dig www.leoliu.org @172.25.254.20
; <<>> DiG 9.16.23-RH <<>> www.leoliu.org @172.25.254.20
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 35717
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 00519baeab87813f0100000066c8731f603480a498f2b358 (good)
;; QUESTION SECTION:
;www.leoliu.org. IN A
;; ANSWER SECTION:
www.leoliu.org. 86400 IN A 172.25.254.20
;; Query time: 2 msec
;; SERVER: 172.25.254.20#53(172.25.254.20)
;; WHEN: Fri Aug 23 19:31:43 CST 2024
;; MSG SIZE rcvd: 87
#配置dns的负载均衡
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
stream {
upstream dns_server {
server 172.25.254.20:53 fail_timeout=15s max_fails=3;
server 172.25.254.10:53 fail_timeout=15s max_fails=3;
}
server {
listen 53 udp reuseport;
proxy_pass dns_server;
proxy_timeout 20s;
}
}
[root@Nginx ~]# nginx -s reload
[root@Nginx ~]# dig www.leoliu.org @172.25.254.100
; <<>> DiG 9.16.23-RH <<>> www.leoliu.org @172.25.254.100
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1294
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 8b8cf765b85493050100000066c2442f0a1af9f0eec6183d (good)
;; QUESTION SECTION:
;www.leoliu.org. IN A
;; ANSWER SECTION:
www.leoliu.org. 86400 IN A 172.25.254.10
;; Query time: 0 msec
;; SERVER: 172.25.254.100#53(172.25.254.100)
;; WHEN: Sun Aug 18 21:23:05 CST 2024
;; MSG SIZE rcvd: 86
6.2.3 负载均衡实例: MySQL
#安装mysql
[root@web1 ~]# yum install mariadb-server -y
[root@web2 ~]# yum install mariadb-server -y
#添加id以便区分
[root@web1 ~]# vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=10
[root@web1 ~]# systemctl start mariadb.service
[root@web2 ~]# vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id=20
[root@web2 ~]# systemctl start mariadb.service
#配置数据库
[root@web1 ~]# mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 3
Server version: 10.5.13-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> CREATE USER liu@"%" identified by "redhat";
Query OK, 0 rows affected (0.004 sec)
MariaDB [(none)]> GRANT ALL ON *.* TO liu@'%';
Query OK, 0 rows affected (0.001 sec)
MariaDB [(none)]> exit
Bye
[root@web2 ~]# mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 3
Server version: 10.5.13-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> CREATE USER liu@"%" identified by "redhat";
Query OK, 0 rows affected (0.002 sec)
MariaDB [(none)]> GRANT ALL ON *.* TO liu@'%';
Query OK, 0 rows affected (0.001 sec)
MariaDB [(none)]> exit
Bye
[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
stream {
upstream mysql {
server 172.25.254.20:3306 fail_timeout=15s max_fails=3;
server 172.25.254.10:3306 fail_timeout=15s max_fails=3;
}
server {
listen 3306;
proxy_pass mysql;
proxy_timeout s;
}
}
[root@Nginx ~]# nginx -s reload
[root@Nginx ~]# yum install mariadb -y
#测试
[root@Nginx ~]# mysql -u liu -p -h 172.25.254.100
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 4
Server version: 10.5.22-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
| 20 |
+-------------+
1 row in set (0.001 sec)
MariaDB [(none)]> exit
Bye
[root@Nginx ~]# mysql -u haha -p -h 172.25.254.100
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 8
Server version: 10.5.22-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
| 10 |
+-------------+
1 row in set (0.001 sec)
MariaDB [(none)]>
6.3 实现 FastCGI
为什么会有 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代码的处理。
6.3.1 FastCGI配置指令
Nginx 基于模块 ngx_http_fastcgi_module 实现通过 fastcgi 协议将指定的客户端请求转发至 php-fpm 处理,其配置指令如下:fastcgi_pass address:port;# 转发请求到后端服务器, address 为后端的 fastcgi server 的地址,可用位置: location, if inlocationfastcgi_index name;#fastcgi 默认的主页资源,示例: fastcgi_index index.php;fastcgi_param parameter value [if_not_empty];# 设置传递给 FastCGI 服务器的参数值,可以是文本,变量或组合,可用于将 Nginx 的内置变量赋值给自定义keyfastcgi_param REMOTE_ADDR $remote_addr; # 客户端源 IPfastcgi_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 nameNginx 默认配置示例: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}
#安装环境配置,解决php依赖
[root@Nginx ~]# yum install -y bzip2 systemd-devel libxml2-devel sqlite-devel libpng-devel libcurl-devel
[root@Nginx ~]# wget https://mirrors.aliyun.com/rockylinux/9.4/devel/x86_64/kickstart/Packages/o/oniguruma-devel-6.9.6-1.el9.5.x86_64.rpm
[root@Nginx ~]# yum install -y oniguruma-devel-6.9.6-1.el9.5.x86_64.rpm
[root@nginx-node1 php-8.3.9]# ./configure --prefix=/usr/local/php --with-config-file-path=/usr/local/php/etc --enable-fpm --with-fpm-user=nginx --with-fpm-group=nginx --with-curl --with-iconv --with-mhash --with-zlib --with-openssl --enable-mysqlnd --with-mysqli --with-pdo-mysql --disable-debug --enable-sockets --enable-soap --enable-xml --enable-ftp --enable-gd --enable-exif --enable-mbstring --enable-bcmath --with-fpm-systemd
[root@nginx-node1 php-8.3.9]# make && make install
插件介绍:
[root@Nginx php-8.3.9]# ./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
[root@Nginx ~]# cd /usr/local/php/etc
[root@Nginx etc]# ls
php-fpm.conf.default php-fpm.d
[root@Nginx etc]# cp -p php-fpm.conf.default php-fpm.conf
[root@Nginx etc]# vim php-fpm.conf
#打开
pid = run/php-fpm.pid #指定pid文件存放位置
[root@Nginx etc]# ls
php-fpm.conf php-fpm.conf.default php-fpm.d
[root@Nginx etc]# cd php-fpm.d/
[root@Nginx php-fpm.d]# ls
www.conf.default
[root@Nginx php-fpm.d]# cp www.conf.default www.conf -p
#生成php的主配置文件
[root@Nginx php-fpm.d]# cd
[root@Nginx ~]# cd php-8.3.9/
[root@Nginx php-8.3.9]# cp php.ini-production /usr/local/php/etc/php.ini
#更改时区
[root@Nginx php-8.3.9]# cd
[root@Nginx ~]# cd /usr/local/php/etc
[root@Nginx etc]# vim php.ini
#添加
date.timezone = Asia/Shanghai #修改时区
#查看该配置什么时区的方法
[root@Nginxnginx-node1 etc]# timedatectl list-timezones | grep Asia/Shanghai
Asia/Shanghai
#复制php的启动脚本
[root@Nginx etc]# cd /root/php-8.3.9/
[root@Nginx php-8.3.9]# cd sapi/
[root@Nginx sapi]# cd fpm/
[root@Nginx fpm]# cp php-fpm.service /lib/systemd/system/
#注释掉默认只读的参数
[root@Nginx fpm]# vim /lib/systemd/system/php-fpm.service
#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 209584 137908/php-fpm: mas
#添加php环境变量
[root@Nginx ~]# vim ~/.bash_profile
#添加
export PATH=$PATH:/usr/local/nginx/sbin:/usr/local/php/bin:/usr/local/php/sbin
[root@Nginx ~]# source ~/.bash_profile
[root@Nginx ~]# mkdir /data/web/php
[root@Nginx ~]# vim /data/web/php/index.php
<?php
phpinfo();
?>
#Nginx配置转发
[root@Nginx ~]# vim /usr/local/nginx/conf.d/php.conf
server {
listen 80;
server_name www.leoliu.org;
root /data/web/html;
index index.html;
location ~ \.php$ {
root /data/web/php;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}
[root@Nginx ~]# nginx -s reload
访问验证php测试页面
6.3.3 php的动态扩展模块(php的缓存模块)
[root@Nginx ~]# tar zxf memcache-8.2.tgz
[root@Nginx ~]# cd memcache-8.2/
[root@Nginx memcache-8.2]# yum install autoconf
[root@Nginx memcache-8.2]# phpize
Configuring for:
PHP Api Version: 20230831
Zend Module Api No: 20230831
Zend Extension Api No: 420230831
[root@Nginx memcache-8.2]# ./configure && make && make install
[root@Nginx memcache-8.2]# ls /usr/local/php/lib/php/extensions/no-debug-non-zts-20230831/
memcache.so opcache.so
[root@Nginx memcache-8.2]# cp example.php memcache.php /data/web/php/
[root@Nginx memcache-8.2]# vim /data/web/php/memcache.php
define('ADMIN_USERNAME','admin'); // Admin Username
define('ADMIN_PASSWORD','123'); // Admin Password
define('DATE_FORMAT','Y/m/d H:i:s');
define('GRAPH_SIZE',200);
define('MAX_ITEM_DUMP',50);
$MEMCACHE_SERVERS[] = 'localhost:11211'; // add more as an array
#$MEMCACHE_SERVERS[] = 'mymemcache-server2:11211'; // add more as an array
[root@Nginx ~]# vim /usr/local/php/etc/php.ini
;extension=zip
extension=memcache
;zend_extension=opcache
[root@Nginx ~]# systemctl reload php-fpm
[root@Nginx no-debug-non-zts-20230831]# php -m | grep mem
memcache
[root@Nginx ~]# yum install memcached -y
[root@Nginx ~]# systemctl enable --now memcached.service
[root@Nginx ~]# netstat -antlupe | grep memcache
tcp 0 0 127.0.0.1:11211 0.0.0.0:* LISTEN 977 219275 143464/memcached
tcp6 0 0 ::1:11211 :::* LISTEN 977 219276 143464/memcached
[root@Nginx ~]# cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS="-l 127.0.0.1,::1"
[root@Nginx ~]# ab -n500 -c10 http://www.leoliu.org/index.php
-----内容忽略-------
Server Software: nginx/1.26.1
Server Hostname: www.leoliu.org
Server Port: 80
Document Path: /index.php
Document Length: 74902 bytes
Concurrency Level: 10
Time taken for tests: 0.629 seconds
Complete requests: 500
Failed requests: 53
(Connect: 0, Receive: 0, Length: 53, Exceptions: 0)
Total transferred: 37543442 bytes
HTML transferred: 37450942 bytes
Requests per second: 795.10 [#/sec] (mean)
Time per request: 12.577 [ms] (mean)
Time per request: 1.258 [ms] (mean, across all concurrent requests)
Transfer rate: 58302.48 [Kbytes/sec] received
[root@Nginx ~]# ab -n500 -c10 http://www.leoliu.org/example.php
Concurrency Level: 10
Time taken for tests: 0.619 seconds
Complete requests: 500
Failed requests: 0
Total transferred: 150500 bytes
HTML transferred: 58000 bytes
Requests per second: 807.83 [#/sec] (mean)
Time per request: 12.379 [ms] (mean)
Time per request: 1.238 [ms] (mean, across all concurrent requests)
Transfer rate: 237.46 [Kbytes/sec] received
6.3.4 php高速缓存
[root@Nginx ~]# rm -rf /usr/local/nginx/
[root@Nginx ~]# cd nginx-1.26.1/
[root@Nginx nginx-1.26.1]# make clean
rm -rf Makefile objs
[root@Nginx nginx-1.26.1]# cd
[root@Nginx ~]# rz -E
rz waiting to receive.
[root@Nginx ~]# rz -E
rz waiting to receive.
[root@Nginx ~]# tar zxf srcache-nginx-module-0.33.tar.gz
[root@Nginx ~]# tar zxf memc-nginx-module-0.20.tar.gz
[root@Nginx ~]# cd nginx-1.26.1/
[root@Nginx nginx-1.26.1]# ./configure --prefix=/apps/nginx --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 --add-module=/root/memc-nginx-module-0.20 --add-module=/root/srcache-nginx-module-0.33
[root@Nginx nginx-1.26.1]# make && make install
[root@Nginx ~]# vim /usr/local/nginx/conf.d/php.conf
upstream memcache {
server 127.0.0.1:11211;
keepalive 512;
}
server {
listen 80;
server_name php.leoliu.org;
root /data/php;
location /memc {
internal;
memc_connect_timeout 100ms;
memc_send_timeout 100ms;
memc_read_timeout 100ms;
set $memc_key $query_string; #使用内置变量$query_string来作为key
set $memc_exptime 300; #缓存失效时间300秒
memc_pass memcache;
}
location ~ \.php$ {
set $key $uri$args; #设定key的值
srcache_fetch GET /memc $key; #检测mem中是否有要访问的php
srcache_store PUT /memc $key; #缓存为加载的php数据
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}
[root@Nginx ~]# systemctl start nginx.service
#测试结果
[root@Nginx ~]# ab -n500 -c10 http://php.leoliu.org/index.php
Concurrency Level: 10
Time taken for tests: 0.255 seconds
Complete requests: 500
Failed requests: 0