当前位置: 首页 > news >正文

企业级高性能web服务器

1 web服务基础

1.1 正常情况的单次web服务访问流程:

正常情况下,单次 Web 服务访问流程从用户在客户端发起请求开始,到最终在客户端展示内容结束,涉及客户端、网络传输、服务器端等多个环节,以下是详细过程:

1.1.1 客户端发起请求

1.用户操作与URL解析:

用户在浏览器地址栏输入网址(如https://www.example.com ),或点击网页上的链接、提交表单等操作,触发 Web 服务访问。浏览器对输入的 URL 进行解析,识别出协议(常见的有 HTTP、HTTPS)、域名(www.example.com )、端口号(HTTP 默认 80,HTTPS 默认 443,若 URL 中未明确指定端口,浏览器会使用默认端口 )以及资源路径(如/index.html )。

2.DNS解析:

浏览器首先检查本地的 DNS 缓存,如果缓存中有对应的域名 - IP 地址映射,则直接获取 IP 地址;若没有,就向本地 DNS 服务器发送查询请求。本地 DNS 服务器会先查询自身缓存,若未找到结果,它会向根 DNS 服务器、顶级 DNS 服务器、权威 DNS 服务器等依次进行递归或迭代查询,最终将域名解析为对应的 IP 地址(例如192.168.1.100 ),并将结果返回给浏览器。

1.1.2 建立连接

1.TCP三次握手(以HTTP协议基于tcp传输为例):

  • 第一次握手:客户端向服务器发送一个带有 SYN(同步序列号)标志的 TCP 报文段,该报文段中包含客户端随机生成的初始序列号(假设为 x),表示客户端请求与服务器建立连接。
  • 第二次握手:服务器接收到客户端的 SYN 报文后,返回一个带有 SYN 和 ACK(确认应答)标志的 TCP 报文段。其中,ACK 标志表示对客户端 SYN 的确认,确认号为客户端初始序列号 x 加 1(即 x + 1);同时,服务器也生成自己的初始序列号(假设为 y),并将其放入 SYN 标志位中发送给客户端。
  • 第三次握手:客户端收到服务器的 SYN + ACK 报文后,向服务器发送一个带有 ACK 标志的 TCP 报文段,确认号为服务器的初始序列号 y 加 1(即 y + 1),序列号为客户端的初始序列号 x 加 1(即 x + 1),表示客户端确认收到服务器的响应并完成连接建立。至此,TCP 连接成功建立。

2.TLS/SSL握手(若使用HTTPS协议):

在 TCP 连接建立后,客户端和服务器之间会进行 TLS/SSL 握手,以协商加密算法、交换公钥证书等,确保数据传输的安全性。具体步骤如下:

  • 客户端发送ClientHello消息:包含客户端支持的 SSL/TLS 版本、加密算法列表、随机数等信息。
  • 服务器响应ServerHello消息:服务器从客户端提供的选项中选择合适的 SSL/TLS 版本和加密算法,并返回自己的证书(包含公钥)、随机数等信息。
  • 客户端验证服务器证书:客户端检查服务器证书的有效性(如证书是否过期、颁发机构是否可信等),并从中提取服务器的公钥。
  • 客户端生成预主密钥:客户端使用服务器的公钥加密一个随机生成的预主密钥,并发送给服务器。
  • 服务器解密预主密钥:服务器使用自己的私钥解密收到的预主密钥,然后客户端和服务器双方使用预主密钥、之前交换的随机数等信息,生成会话密钥,用于后续的数据加密传输。

具体加密原理请参考:加密(一)- 阮一峰:RSA算法原理_rsa 阮一峰-CSDN博客https://blog.csdn.net/yiguang_820/article/details/108842637

1.1.3 发送http请求

TCP 连接建立后,客户端通过该连接向服务器发送 HTTP 请求报文,请求报文主要包括:

  • 请求行:包含请求方法(常见的有 GET、POST、PUT、DELETE 等,例如 GET 方法用于获取资源,POST 方法用于提交数据 )、请求的资源路径(如/index.html )以及 HTTP 协议版本(如 HTTP/1.1 )。
  • 请求头:包含一系列键值对,提供了关于客户端、请求内容等的元信息。
  • 请求体:当请求方法为 POST、PUT 等需要提交数据的方法时,请求体中包含了要发送的数据,例如表单数据(格式如name=John&age=30 )或 JSON 格式的数据(如{"username": "John", "password": "123456"} )。

1.1.4 服务器处理请求

  • Web服务器接收与解析:Web 服务器(如 Apache、Nginx 等)在指定端口(如 80 或 443 )监听并接收客户端发送的 HTTP 请求报文,然后对请求报文进行解析,提取请求方法、资源路径等关键信息。
  • 请求分发与处理:
    • 静态资源请求:如果请求的是静态资源(如 HTML 文件、CSS 样式表、图片、JavaScript 脚本等),Web 服务器会根据资源路径在本地文件系统中查找对应的文件,并直接将其读取出来,准备返回给客户端。
    • 动态资源请求:对于动态资源请求(例如请求一个 PHP 脚本、Python Flask 应用的接口等),Web 服务器会将请求转发给相应的应用服务器(如 PHP-FPM、Gunicorn、Tomcat 等 )。应用服务器根据请求内容执行相应的业务逻辑,这可能涉及与数据库进行交互(例如查询用户信息、获取商品列表等 )。应用服务器通过数据库驱动程序(如 MySQL Connector/Python )连接到数据库(如 MySQL、PostgreSQL 等 ),执行 SQL 查询或操作,获取或更新数据,然后将处理结果返回给 Web 服务器。

1.1.5 服务器返回响应

  • 构建响应报文:Web 服务器接收到应用服务器返回的处理结果(如果是动态请求)或获取到静态资源后,构建 HTTP 响应报文。响应报文主要包括:
  1. 状态行:包含 HTTP 协议版本、状态码(如 200 表示请求成功,404 表示资源未找到,500 表示服务器内部错误等 )以及状态描述(如OK )。
  2. 响应头:包含一系列键值对,提供关于响应的元信息。
  3. 响应体:包含了实际要返回给客户端的内容,对于静态资源请求,可能是 HTML 页面、CSS 文件、图片等的二进制数据;对于动态请求,可能是 JSON 格式的数据、渲染后的 HTML 页面等。
  • 发送响应:Web 服务器通过已建立的 TCP 连接,将构建好的 HTTP 响应报文发送回客户端。

1.1.6 客户端接收与渲染

  • 接收响应:客户端通过 TCP 连接接收服务器发送的 HTTP 响应报文,根据响应头中的Content-Length等信息,确定接收数据的大小,并将数据完整地接收下来。
  • 解析与渲染:
  1. 响应状态检测:客户端首先检查响应的状态码,如果是 200 - 299 范围内的状态码,表示请求成功;如果是其他范围的状态码,可能意味着请求失败,客户端会根据状态码的含义进行相应的处理,例如显示错误页面。
  2. 响应头处理:客户端解析响应头中的信息,如Content-Type ,根据内容类型调用相应的渲染引擎。例如,如果是text/html ,则调用 HTML 渲染引擎;如果是image/jpeg ,则调用图片解码和显示模块。
  3. 响应体渲染:对于 HTML 页面,浏览器会构建 DOM 树,解析 CSS 样式表并应用样式,执行 JavaScript 脚本,最终在浏览器窗口中呈现出完整的网页内容;对于 JSON 数据等,客户端可能会根据业务逻辑进行数据处理和展示。

1.1.7 关闭连接

TCP四次挥手(默认情况下):

当数据传输完成后,客户端和服务器之间会进行 TCP 四次挥手来关闭连接:

  • 第一次挥手:客户端发送一个带有 FIN(结束标志)的 TCP 报文段,表示客户端不再发送数据,但还可以接收数据。
  • 第二次挥手:服务器接收到客户端的 FIN 报文后,返回一个带有 ACK 标志的 TCP 报文段,确认收到客户端的 FIN 请求。
  • 第三次挥手:服务器发送一个带有 FIN 标志的 TCP 报文段,表示服务器也不再发送数据。
  • 第四次挥手:客户端接收到服务器的 FIN 报文后,返回一个带有 ACK 标志的 TCP 报文段,确认收到服务器的 FIN 请求,至此,TCP 连接完全关闭。

HTTP长连接(若启用):在 HTTP/1.1 协议中,默认启用了 HTTP 长连接(通过Connection: keep-alive 头字段标识 ),这意味着在一次请求 - 响应完成后,TCP 连接不会立即关闭,而是可以被复用,用于后续的 HTTP 请求,这样可以减少建立和关闭连接的开销,提高性能。

1.2 web服务介绍

1.2.1 Apache经典的web服务端

Apache起初由美国的伊利诺伊大学香槟分校的国家超级计算机应用中心开发,目前经历了两大版本分别是1.X2.X,其可以通过编译安装实现特定的功能。
1.2.1.1 Apache prefork模型
  • 预派生模式,有一个主控制进程,然后生成多个子进程,使用select模型,最大并发1024
  • 每个子进程有一个独立的线程响应用户请求
  • 相对比较占用内存,但是比较稳定,可以设置最大和最小进程数
优点:稳定
缺点:每个用户请求需要对应开启一个进程,占用资源较多,并发性差,不适用于高并发场景
1.2.1.2 Apache worker模型
  • 一种多进程和多线程混合的模型
  • 有一个控制进程,启动多个子进程
  • 每个子进程里面包含固定的线程
  • 使用线程来处理请求
  • 当线程不够使用的时候会再启动一个新的子进程,然后在进程里面再启动线程处理请求
  • 由于其使用了线程处理请求,因此可以承受更高的并发
优点:相比于prefork占用的内存少,可以同时处理更多的请求
缺点:使用keepalive的长连接方式,某个线程会一直被占据,即使没有传输数据,也需要一直等待到超时才会被释放。如果过多的线程,被这样占据,也会导致在高并发场景下的无服务线程可用(该问题在prefork模式下,同样会发生)
1.2.1.3 Apache event模型
  • Apache中最新的模式,2012年发布的apache 2.4.X系列正式支持event 模型,属于事件驱动模型(epoll) 每个进程响应多个请求,在现在版本里的已经是稳定可用的模式
  • 它和worker模式很像,最大的区别在于,它解决了keepalive场景下长期被占用的线程的资源浪费问题(某些线程因为被keepalive,空挂在哪里等待,中间几乎没有请求过来,甚至等到超时)
  • event MPM中,会有一个专门的线程来管理这些keepalive类型的线程
  • 当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放。这样增强了高并发场景下的请求处理能力
优点:单线程响应多请求,占据更少的内存,高并发下表现更优秀,会有一个专门的线程来管理keepalive类型的线程,当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放
缺点:没有线程安全控制

1.2.2 nginx-高性能的web服务端

Nginx历经十几年的迭代更新(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或者进行二次开发

1.2.3 用户访问体验和性能

互联网存在用户速度体验的1-3-10原则,即1秒最优,1-3秒较优,3~10秒比较慢,10秒以上用户无法接受。用户放弃一个产品的代价很低,只是换一个URL而已。
1.2.3.1 影响用户体验的因素

1.客户端:

  • 客户端硬件配置
  • 客户端网络速率
  • 客户端与服务端距离

2.服务器:

  • 服务端网络速率
  • 服务端硬件配置
  • 服务端架构设计
  • 服务端应用程序工作模式
  • 服务端并发数量,服务端响应文件大小及数量
  • 服务端I/O压力

1.2.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.2.4.1 磁盘I/O
磁盘I/O是进程向内核发起系统调用,请求磁盘上的某个资源比如是html 文件或者图片,然后内核通过相应的驱动程序将目标文件加载到内核的内存空间,加载完成之后把数据从内核内存再复制给进程内存,如果是比较大的数据也需要等待时间
机械磁盘的寻道时间、旋转延迟和数据传输时间:
寻道时间:是指磁头移动到正确的磁道上所花费的时间,寻道时间越短则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.17ms
10000转的机械盘平均延迟:60*1000/10000/2 = 3ms
15000转的机械盘平均延迟:60*1000/15000/2 = 2ms
每秒最大IOPS的计算方法:
7200转的磁盘IOPS计算方式:1000毫秒/(9毫秒的寻道时间+4.17毫秒的平均旋转延迟时
)=1000/13.13=75.9 IOPS
10000转的磁盘的IOPS计算方式:1000毫秒/(6毫秒的寻道时间+3毫秒的平均旋转延迟时
)=1000/9=111IOPS
15000转的磁盘的IOPS计算方式:15000毫秒/(4毫秒的寻道时间+2毫秒的平均旋转延迟时
)=1000/6=166.6 IOPS
1.2.4.2 网络I/O
网络通信就是网络协议栈到用户空间进程的IO就是网络IO

网络I/O处理过程

  • 获取请求数据,客户端与服务器建立连接发出请求,服务器接受请求
  • 构建响应,当服务器接收完请求,并在用户空间处理客户端的请求,直到构建响应完成
  • 返回数据,服务器将已构建好的响应再通过内核空间的网络I/O发还给客户端

不论磁盘和网络I/O

每次I/O,都要经过两个阶段:

  1. 将数据从文件先加载到内核内存空间(缓冲区),等待数据准备完成,时间较长
  2. 将数据从内核缓冲区复制到用户空间的进程内存中,时间较短

1.3 I/O模型

1.3.1 I/O模型概念

同步/异步:关注的是消息通信机制,即调用者在等待一件事情的处理结果时,被调用者是否提供完成状态的通知。

  • 同步:synchronous,被调用者并不提供事件的处理结果相关的通知消息,需要调用者主动询问事情是否处理完成
  • 异步:asynchronous,被调用者通过状态、通知或回调机制主动通知调用者被调用者的运行状态

阻塞/非阻塞:关注调用者在等待结果返回之前的状态

  • 阻塞:blocking,指IO操作需要彻底完成后才返回到用户空间,调用结果返回之前,调用者被挂起,干不了别的事情。
  • 非阻塞:nonblocking,指IO操作被调用后立即返回给用户一个状态值,而无需等到IO操作彻底完成,在最终的调用结果返回之前,调用者不会被挂起,可以去做别的事情

1.3.2 网络I/O模型

阻塞型、非阻塞型、复用型、信号驱动型、异步
1.3.2.1 阻塞型I/O模型(blocking IO)

  • 用户线程在内核进行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.3.2.2 非阻塞型I/O模型(nonblocking IO)

用户线程发起IO请求时立即返回。但并未读取到任何数据,用户线程需要不断地发起IO请求,直到数据到达后,才真正读取到数据,继续执行。即 “轮询机制存在两个问题:如果有大量文件描述符都要等,那么就得一个一个的read。这会带来大量的Context Switchread是系统调用,每调用一次就得在用户态和核心态切换一次)。轮询的时间不好把握。这里是要猜多久之后数据才能到。等待时间设的太长,程序响应延迟就过大;设的太短,就会造成过于频繁的重试,干耗CPU而已,是比较浪费CPU的方式,一般很少直接使用这种模型,而是在其他IO模型中使用非阻塞IO这一特性。
非阻塞:程序向内核发送请I/O求后一直等待内核响应,如果内核处理请求的IO操作不能立即返回IO结果,进程将不再等待,而且继续处理其他请求,但是仍然需要进程隔一段时间就要查看内核I/O是否完成。
查看上图可知,在设置连接为非阻塞时,当应用进程系统调用 recvfrom 没有数据返回时,内核会立即返回一个 EWOULDBLOCK 错误,而不会一直阻塞到数据准备好。如上图在第四次调用时有一个数据报准备好了,所以这时数据会被复制到 应用进程缓冲区 ,于是 recvfrom 成功返回数据
当一个应用进程这样循环调用 recvfrom 时,称之为轮询 polling 。这么做往往会耗费大量CPU时间,实际使用很少
1.3.2.3 多路复用I/O型(I/O multiplexing)
  • 上面的模型中,每一个文件描述符对应的IO是由一个线程监控和处理
  • 多路复用IO指一个线程可以同时(实际是交替实现,即并发完成)监控和处理多个文件描述符对应各自的IO,即复用同一个线程
  • 一个线程之所以能实现同时处理多个IO,是因为这个线程调用了内核中的SELECT,POLLEPOLL等系统调用,从而实现多路复用IO
I/O multiplexing 主要包括:selectpollepoll三种系统调用,select/poll/epoll的好处就在于单个
process就可以同时处理多个网络连接的IO
它的基本原理就是select/poll/epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。
当用户进程调用了select,那么整个进程会被block,而同时,kernel监视所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。
Apache prefork是此模式的selectworker是poll模式。
IO多路复用(IO Multiplexing) :是一种机制,程序注册一组socket文件描述符给操作系统,表示“我要监视这些fd是否有IO事件发生,有了就告诉程序处理”,IO多路复用一般和NIO一起使用的。NIOIO多路复用是相对独立的。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.3.2.4 信号驱动式I/O模型(signal-drven IO)

信号驱动I/O的意思就是进程现在不用傻等着,也不用去轮询。而是让内核在数据就绪时,发送信号通知进程。
调用的步骤是,通过系统调用 sigaction ,并注册一个信号处理的回调函数,该调用会立即返回,然后主程序可以继续向下执行,当有I/O操作准备就绪,即内核数据就绪时,内核会为该进程产生一个 SIGIO信号,并回调注册的信号回调函数,这样就可以在信号回调函数中系统调用 recvfrom 获取数据,将用户进程所需要的数据从内核空间拷贝到用户空间
此模型的优势在于等待数据报到达期间进程不被阻塞。用户主程序可以继续执行,只要等待来自信号处理函数的通知。
在信号驱动式 I/O 模型中,应用程序使用套接口进行信号驱动 I/O,并安装一个信号处理函数,进程继续运行并不阻塞
当数据准备好时,进程会收到一个 SIGIO 信号,可以在信号处理函数中调用 I/O 操作函数处理数据。
优点:线程并没有在等待数据时被阻塞,内核直接返回调用接收信号,不影响进程继续处理其他请求因此可以提高资源的利用率
缺点:信号 I/O 在大量 IO 操作时可能会因为信号队列溢出导致没法通知
异步阻塞:程序进程向内核发送IO调用后,不用等待内核响应,可以继续接受其他请求,内核收到进程请求后进行的IO如果不能立即返回,就由内核等待结果,直到IO完成后内核再通知进程。

1.3.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库,例如libeventlibev、libuv。
异步非阻塞:程序进程向内核发送IO调用后,不用等待内核响应,可以继续接受其他请求,内核调用的IO如果不能立即返回,内核会继续处理其他事物,直到IO完成后将结果通知给内核,内核在将IO完成的结果返回给进程,期间进程可以接受新的请求,内核也可以处理新的事物,因此相互不影响,可以实现较大的同时并实现较高的IO复用,因此异步非阻塞使用最多的一种通信方式。

1.3.3 五种IO对比

这五种 I/O 模型中,越往后,阻塞越少,理论上效率也是最优,前四种属于同步 I/O,因为其中真正的 I/O操作(recvfrom)将阻塞进程/线程,只有异步 I/O 模型才与 POSIX 定义的异步 I/O 相匹配

1.3.4 I/O的具体实现方式

1.3.4.1 I/O常见实现
Nginx支持在多种不同的操作系统实现不同的事件驱动模型,但是其在不同的操作系统甚至是不同的系统版本上面的实现方式不尽相同,主要有以下实现方式:
  • select:select库是在linuxwindows平台都基本支持的 事件驱动模型库,并且在接口的定义也基本相同,只是部分参数的含义略有差异,最大并发限制1024,是最早期的事件驱动模型。
  • poll:在Linux 的基本驱动模型,windows不支持此驱动模型,是select的升级版,取消了最大的并发限制,在编译nginx的时候可以使用--with-poll_module--without-poll_module这两个指定是否编译select库。
  • epoll:epoll是库是Nginx服务器支持的最高性能的事件驱动库之一,是公认的非常优秀的事件驱动模型,它和select和poll有很大的区别,epollpoll的升级版,但是与poll有很大的区别.epoll的处理方式是创建一个待处理的事件列表,然后把这个列表发给内核,返回的时候在去轮询检查这个表,以判断事件是否发生,epoll支持一个进程打开的最大事件描述符的上限是系统可以打开的文件的最大数,同时epoll库的I/O效率不随描述符数目增加而线性下降,因为它只会对内核上报的活跃的描述符进行操作。
  • kqueue:用于支持BSD系列平台的高校事件驱动模型,主要用在FreeBSD 4.1及以上版本、OpenBSD 2.0级以上版本NetBSD级以上版本及Mac OS X 平台上,该模型也是poll库的变种,因此和epoll没有本质上的区别,都是通过避免轮询操作提供效率。
  • Iocp:Windows系统上的实现方式,对应第5种(异步I/O)模型。
  • rtsig:不是一个常用事件驱动,最大队列1024,不是很常用
  • /dev/poll:用于支持unix衍生平台的高效事件驱动模型,主要在Solaris 平台、HP/UX,该模型是sun公司在开发Solaris系列平台的时候提出的用于完成事件驱动机制的方案,它使用了虚拟的/dev/poll设备,开发人员将要见识的文件描述符加入这个设备,然后通过ioctl()调用来获取事件通知,因此运行在以上系列平台的时候请使用/dev/poll事件驱动机制。
  • eventport:该方案也是sun公司在开发Solaris的时候提出的事件驱动库,只是Solaris 10以上的版本,该驱动库看防止内核崩溃等情况的发生。
1.3.4.2 常用I/O模型比较
selectpollepoll
操作方式遍历遍历回调
底层实现数组链表哈希表
IO效率每次调回都进行线性遍历,时间复杂度为O(n)同左事件通知方式,每当fd就绪,系统注册的回调函数就会被调用,将就绪的fd放到rdlist里,时间复杂度O(1)
最大连接数

1024(x86)

2048(x64)

无上限无上限
fd拷贝每次调用select都需要把fd集合从用户拷贝到内核态每次调用poll,都需要把fd集合从用户态拷贝到内核态调用epoll_ct时拷贝进内核并保存,之后每次epoll_wait不拷贝
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内核中提出的selectpoll的增强版本支持水平触发LT和边缘触发ET,最大的特点在于边缘触发,它只告诉进程哪些fd刚刚变为就需态,并且只会通知一次使用事件的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fdepoll_wait便可以收到通知
优点: 没有最大并发连接的限制:能打开的FD的上限远大于1024(1G的内存能监听约10万个端口),具体查看/proc/sys/fs/file-max,此值和系统内存大小相关
效率提升:非轮询的方式,不会随着FD数目的增加而效率下降;只有活跃可用的FD才会调用callback函数,即epoll最大的优点就在于它只管理活跃的连接,而跟连接总数无关内存拷贝,利用mmap(Memory Mapping)加速与内核空间的消息传递;epoll使用mmap减少复制开销
总结:
1epoll只是一组API,比起select这种扫描全部的文件描述符,epoll只读取就绪的文件描述符,再加入基于事件的就绪通知机制,所以性能比较好
2、基于epoll的事件多路复用减少了进程间切换的次数,使得操作系统少做了相对于用户任务来说的无用功。
3epollselect等多路复用方式来说,减少了遍历循环及内存拷贝的工作量,因为活跃连接只占总并发连接的很小一部分。

1.4 零拷贝

1.4.1 零拷贝介绍

1.4.1.1 传统Linux中I/O的问题

传统的 Linux 系统的标准 I/O 接口(readwrite)是基于数据拷贝的,也就是数据都是 copy_to_user或者 copy_from_user,这样做的好处是,通过中间缓存的机制,减少磁盘 I/O 的操作,但是坏处也很明显,大量数据的拷贝,用户态和内核态的频繁切换,会消耗大量的 CPU 资源,严重影响数据传输的性能,统计表明,在Linux协议栈中,数据包在内核态和用户态之间的拷贝所用的时间甚至占到了数据包整个处理流程时间的57.1%
1.4.1.2 什么是零拷贝
零拷贝就是上述问题的一个解决方案,通过尽量避免拷贝操作来缓解 CPU 的压力。零拷贝并没有真正做到“0”拷贝,它更多是一种思想,很多的零拷贝技术都是基于这个思想去做的优化

1.4.2 零拷贝相关技术

1.4.2.1 MMAP(Memory Mapping)

mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进行访问。
mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。
实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。
内存映射减少数据在用户空间和内核空间之间的拷贝操作,适合大量数据传输
1.4.2.2 SENDFILE

1.4.2.3 DMA辅助的SENDFILE

2 Nginx架构和安装

2.1 Nginx概述

2.1.1 nginx介绍

Nginx是免费的、开源的、高性能的HTTP和反向代理服务器、邮件代理服务器、以及TCP/UDP代理服务器
解决C10K问题(10K Connections
nginx官网:http://nginx.org
nginx其它的二次发行版:
  • Tengine:由淘宝网发起的Web服务器项目。它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性。Tengine的性能和稳定性已经在大型的网站如淘宝网,天猫商城等得到了很好的检验。它的最终目标是打造一个高效、稳定、安全、易用的Web平台。从201112月开始,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服务相关的功能

2.2 nginx架构和进程

  • 虚拟主机(server)
  • 支持keep-alive和管道连接(利用一个连接做多次请求)
  • 访问日志(支持基于日志缓冲提高其性能)
  • url rewirte
  • 路径别名
  • 基于IP及用户的访问控制
  • 支持速率限制及并发数限制
  • 重新配置和在线升级而无需中断客户的工作进程

2.2.2 nginx进程结构

web请求处理机制:

  • 多进程方式:服务器每接收到一个客户端请求就有服务器的主进程生成一个子进程响应客户端,直到用户关闭连接,这样的优势是处理速度快,子进程之间相互独立,但是如果访问过大会导致服务器资源耗尽而无法提供请求
  • 多线程方式:与多进程方式类似,但是每收到一个客户端请求会有服务进程派生出一个线程和此客户端进行交互,一个线程的开销远远小于一个进程,因此多线程方式在很大程度减轻了web服务器对系统资源的要求,但是多线程也有自己的缺点,即当多个线程位于同一个进程内工作的时候,可以相互访问同样的内存地址空间,所以他们相互影响,一旦主进程挂掉则所有子线程都不能工作了,IIS服务器使用了多线程的方式,需要间隔一段时间就重启一次才能稳定。
Nginx是多进程组织模型,而且是一个由Master主进程和Worker工作进程组成。

主进程(master)的功能:

  • 对外接口:接收外部的操作(信号)
  • 对内转发:根据外部的操作的不同,通过信号管理worker
  • 监控:监控worker进程的运行状态,worker进程异常终止后,自动重启worker进程
  • 读取nginx配置文件并验证其有效性和正确性
  • 建立、绑定和关闭socker连接
  • 按照配置生成、管理和结束工作进程
  • 接收外界指令,如重启、升级及退出服务器等指令
  • 不中断服务,实现平滑升级,重启服务并应用新的配置
  • 开启日志文件,获取文件描述符
  • 不中断服务,实现平滑升级,升级失败进行回滚处理
  • 编译和处理perl脚本

工作进程(worker)的功能:

  • 所有worker进程都是平等的
  • 实际处理:网络请求,由worker进程处理
  • worker进程数量:一般设置为核心数,充分利用CPU资源,同时避免进程数量过多,导致进程竞争CPU资源
  • 增加上下文切换的损耗
  • 接受处理客户的请求
  • 将请求依次送入各个功能模块进行处理
  • I/O调用,获取响应数据
  • 与后端服务器通信,接收后端服务器的处理结果
  • 缓存数据,访问缓存索引,查询和调用缓存数据
  • 发送请求结果,响应客户的请求
  • 接收主程序指令,比如重启、升级和退出等

2.2.3 nginx进程间通信

工作进程是由主进程生成的,主进程使用fork()函数,在Nginx服务器启动过程中主进程根据配置文件决定启动工作进程的数量,然后建立一张全局的工作表用于存放当前未退出的所有的工作进程,主进程生成工作进程后会将新生成的工作进程加入到工作进程表中,并建立一个单向的管道并将其传递给工作进程,该管道与普通的管道不同,它是由主进程指向工作进程的单向通道,包含了主进程向工作进程发出的指令、工作进程ID、工作进程在工作进程表中的索引和必要的文件描述符等信息。
主进程与外界通过信号机制进行通信,当接收到需要处理的信号时,它通过管道向相关的工作进程发送正确的指令,每个工作进程都有能力捕获管道中的可读事件,当管道中有可读事件的时候,工作进程就会从管道中读取并解析指令,然后采取相应的执行动作,这样就完成了主进程与工作进程的交互。
worker进程之间的通信原理基本上和主进程与worker进程之间的通信是一样的,只要worker进程之间能够取得彼此的信息,建立管道即可通信,但是由于worker进程之间是完全隔离的,因此一个进程想要知道另外一个进程的状态信息,就只能通过主进程来实现。
为了实现worker进程之间的交互,master进程在生成worker进程之后,在worker进程表中进行遍历,将该新进程的PID以及针对该进程建立的管道句柄传递给worker进程中的其他进程,为worker进程之间的通信做准备,当worker进程1worker进程2发送指令的时候,首先在master进程给它的其他worker进程工作信息中找到2的进程PID,然后将正确的指令写入指向进程2的管道,worker进程2捕获到管道中的事件后,解析指令并进行相关操作,这样就完成了worker进程之间的通信。
worker进程可以通过共享内存来通讯的,比如upstream中的zone,或者limit_reqlimit_conn中的zone等。操作系统提供了共享内存机制。

2.2.4 nginx启动和HTTP连接建立

2.3 nginx模块介绍

nginx有多种模块:

  • nginx启动时,master进程加载配置文件
  • master进程,初始化监听的socket
  • master进程,fork出多个worker进程
  • worker进程,竞争新的连接,获胜方通过三次握手,建立socket连接,并处理请求
  • 核心模块:是 Nginx 服务器正常运行必不可少的模块,提供错误日志记录 、配置文件解析 、事件驱动机制 、进程管理等核心功能
  • 标准HTTP模块:提供 HTTP 协议解析相关的功能,比如: 端口配置 、 网页编码设置 、 HTTP响应头设置等
  • 可选HTTP模块:主要用于扩展标准的 HTTP 功能,让 Nginx 能处理一些特殊的服务,比如: Flash多媒体传输 、解析 GeoIP 请求、 网络传输压缩 、 安全协议 SSL 支持等
  • 邮件服务模块:主要用于支持 Nginx 的 邮件服务 ,包括对 POP3 协议、 IMAP 协议和 SMTP协议的支持
  • Stream服务模块: 实现反向代理功能,包括TCP协议代理
  • 第三方模块:是为了扩展 Nginx 服务器应用,完成开发者自定义功能,比如: Json 支持、 Lua 持等
nginx高度模块化,但其模块早期不支持DSO机制;1.9.11 版本支持动态装载和卸载
核心模块:core module
标准模块:HTTP模块:ngx_http_*HTTP Core modulesHTTP Optional modules    # 需编译时指定Mail模块:ngx_mail_*Stream模块:ngx_stream_*

参考:勿忘初心,进无止尽!https://www.cnblogs.com/Soy-technology/p/11355597.html

2.4 nginx安装

2.4.1 nginx版本和安装方式

nginx版本:

  • Mainline version 主要开发版本,一般为奇数版本号,如1.19
  • Stable version 当前最稳定版本,一般为偶数版本,如1.20
  • Legacy version 旧的稳定版,一般为偶数版本,如1.18

nginx安装可以使用yum或源码安装,但是推荐使用源码编译安装

2.4.2 nginx编译安装

编译器介绍:

  • yum的版本比较旧
  • 编译安装可以更方便自定义相关路径
  • 使用源码编译可以自定义相关功能,更方便业务上的使用
源码安装需要提前准备标准的编译器,GCC的全称是(GNU Compiler collection),其有GNU开发,并以GPL即LGPL许可,是自由的类UNIX即苹果电脑Mac OS X操作系统的标准编译器,因为GCC原本只能处理C语言,所以原名为GNU C语言编译器,后来得到快速发展,可以处理C++,Fortranpascalobjective C,java以及Ada等其他语言,此外还需要Automake工具,以完成自动创建Makefile的工作,Nginx的一些模块需要依赖第三方库,比如: pcre(支持rewrite),zlib(支持gzip模块)和openssl(支持ssl模块)等。
2.4.2.1 编译安装nginx

官方源码包下载地址:

nginx: downloadhttps://nginx.org/en/download.html

编译安装示例:

注意:编译安装前请确保SELinux和防火墙为关闭状态,本地yum或网络yum配置正常,网络通畅

[root@Nginx ~]# yum install gcc pcre-devel zlib-devel openssl-devel -y
[root@Nginx ~]# tar zxf nginx-1.24.0.tar.gz
[root@Nginx ~]# cd nginx-1.24.0
[root@Nginx nginx-1.24.0]# useradd -s /sbin/nologin -M nginx
[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 \ # 指定 Nginx 的安装目录为 /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

nginx完成安装后有四个主要目录

[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二进制启动脚本,可以接受不同的参数以实现不同的功能。
2.4.2.2 验证版本及编译参数
# 将 Nginx 的可执行程序目录(/usr/local/nginx/sbin)添加到系统环境变量 PATH 中
[root@Nginx ~]# vim ~/.bash_profile
export PATH=$PATH:/usr/local/nginx/sbin
[root@Nginx ~]# source ~/.bash_profile # 使刚修改的环境变量配置立即生效[root@Nginx ~]# nginx -V # 查看 Nginx 的版本信息和编译配置参数
nginx version: nginx/1.24.0
built by gcc 11.4.1 20231218 (Red Hat 11.4.1-3) (GCC)
built with OpenSSL 3.0.7 1 Nov 2022
TLS SNI support enabled
configure arguments: --group=nginx --with-http_ssl_module --with-http_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
2.4.2.3 使用安装完成的二进制文件nginx
[root@Nginx ~]# vim /usr/local/nginx/conf/nginx.conf # 编辑 Nginx 的主配置文件
[root@Nginx ~]# nginx -g "worker_processes 4;" # 启动 Nginx 服务并临时指定工作进程数为4
[root@Nginx ~]# ps aux | grep nginx # 查看当前系统中与 nginx 相关的进程状态
2.4.2.4 nginx启动文件

为 Nginx 创建一个 systemd 服务配置文件,以便通过系统服务管理器来管理 Nginx(启动、停止、开机自启等)

[root@Nginx ~]# vim /lib/systemd/system/nginx.service
[Unit]
# 服务描述信息,说明这是 Nginx HTTP 服务器和反向代理服务
Description=The NGINX HTTP and reverse proxy server
# 指定 Nginx 启动的依赖顺序,需在这些服务(系统日志、网络、远程文件系统、DNS 解析)启动之后再启动 Nginx
After=syslog.target network-online.target remote-fs.target nss-lookup.target
# 期望网络就绪后再启动nginx
Wants=network-online.target
[Service]
Type=forking # Nginx 是fork模式启动(主进程会创建子进程,主进程退出后子进程继续运行)
PIDFile=/usr/local/nginx/logs/nginx.pid # 指定Nginx主进程PID文件路径(与nginx.conf中pid配置一致)
ExecStartPre=/usr/local/nginx/sbin/nginx -t # 启动前执行的命令,nginx -t用于检查配置文件语法是否正确,确保配置无误后才启动
ExecStart=/usr/local/nginx/sbin/nginx # 启动Nginx的命令(执行 Nginx 二进制文件)
ExecReload=/usr/local/nginx/sbin/nginx -s reload # 重载配置的命令(nginx -s reload 平滑重启,不中断服务)
ExecStop=/bin/kill -s QUIT $MAINPID # 停止服务的命令
PrivateTmp=true # 为Nginx分配独立的临时目录
[Install]
WantedBy=multi-user.target
[root@Nginx ~]# systemctl daemon-reload # 重新加载systemd服务配置,使新创建的nginx.service生效
[root@Nginx ~]# systemctl start nginx # 启动Nginx服务

2.6 平滑升级和回滚

    有时候我们需要对Nginx版本进行升级以满足对其功能的需求,例如添加新模块,需要新功能,而此时Nginx又在跑着业务无法停掉,这时我们就可能选择平滑升级

    2.6.1 平滑升级流程

    1. 将旧Nginx二进制文件换成新Nginx程序文件(注意先备份)
    2. master进程发送USR2信号
    3. master进程修改pid文件名加上后缀.oldbin,成为nginx.pid.oldbin
    4. master进程用新Nginx文件启动新master进程成为旧master的子进程,系统中将有新旧两个Nginx进程共同提供Web服务,当前新的请求仍然由旧Nginxworker进程进行处理,将新生成的master程的PID存放至新生成的pid文件nginx.pid
    5. 向旧的Nginx服务进程发送WINCH信号,使旧的Nginx worker进程平滑停止
    6. 向旧master进程发送QUIT信号,关闭老master,并删除Nginx.pid.oldbin文件
    7. 如果发现升级有问题,可以回滚∶向老master发送HUP,向新master发送QUIT

    2.6.2 平滑升级和回滚案例

    [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 --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
    #查看两个版本
    [root@Nginx nginx-1.26.1]# ll objs/nginx /usr/local/nginx/sbin/nginx
    -rwxr-xr-x 1 root root 1239416 Jul 18 15:08 objs/nginx
    -rwxr-xr-x 1 root root 5671488 Jul 18 11:41 /usr/local/nginx/sbin/nginx
    #把之前的旧版的nginx命令备份
    [root@Nginx ~]# cd /usr/local/nginx/sbin/
    [root@Nginx sbin]# cp nginx nginx.24
    #把新版本的nginx命令复制过去
    [root@Nginx sbin]# cp -f /root/nginx/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 # 查看进程ID
    root 48732 0.0 0.1 9868 2436 ? Ss 14:17 0:00 nginx: master
    process /usr/local/nginx/sbin/nginx
    nobody 48733 0.0 0.2 14200 4868 ? S 14:17 0:00 nginx: worker
    process
    root 52075 0.0 0.3 9876 6528 ? S 15:41 0:00 nginx: master
    process /usr/local/nginx/sbin/nginx
    nobody 52076 0.0 0.2 14208 4868 ? S 15:41 0:00 nginx: worker
    process[root@Nginx sbin]# kill -USR2 48732 #nginx worker ID
    #USR2 平滑升级可执行程序,将存储有旧版本主进程PID的文件重命名为nginx.pid.oldbin,并启动新的nginx
    #此时两个master的进程都在运行,只是旧的master不在监听,由新的master监听80
    #此时Nginx开启一个新的master进程,这个master进程会生成新的worker进程,这就是升级后的Nginx进
    #程,此时老的进程不会自动退出,但是当接收到新的请求不作处理而是交给新的进程处理。[root@Nginx sbin]# curl -I localhost
    HTTP/1.1 200 OK
    Server: nginx/1.24.0 # 此时依旧是旧版本生生效
    Date: Thu, 18 Jul 2025 07:45:58 GMT
    Content-Type: text/html
    Content-Length: 615
    Last-Modified: Thu, 18 Jul 2025 03:41:13 GMT
    Connection: keep-alive
    ETag: "66988ed9-267"
    Accept-Ranges: bytes#回收旧版本
    [root@Nginx sbin]# kill -WINCH 48732 # 减少工作进程数量,主进程保持运行,跟旧主进程ID
    [root@Nginx sbin]# ps aux | grep nginx
    root 48732 0.0 0.1 9868 2436 ? Ss 14:17 0:00 nginx: master
    process /usr/local/nginx/sbin/nginx
    root 52075 0.0 0.3 9876 6528 ? S 15:41 0:00 nginx: master
    process /usr/local/nginx/sbin/nginx
    nobody 52076 0.0 0.2 14208 4868 ? S 15:41 0:00 nginx: worker
    process
    #检测版本信息
    [root@Nginx sbin]# curl -I localhost
    HTTP/1.1 200 OK
    Server: nginx/1.26.1 #新版本生效
    Date: Thu, 18 Jul 2025 07:59:45 GMT
    Content-Type: text/html
    Content-Length: 615
    Last-Modified: Thu, 18 Jul 2025 03:41:13 GMT
    Connection: keep-alive
    ETag: "66988ed9-267"
    Accept-Ranges: bytes#回滚
    #如果升级的版本发现问题需要回滚,可以重新拉起旧版本的worker
    [root@Nginx sbin]# cp nginx nginx.26
    [root@Nginx sbin]# ls
    nginx nginx.24 nginx.26
    [root@Nginx sbin]# mv nginx.24 nginx
    mv: overwrite 'nginx'? y# kill -HUP ID
    # 检查新配置文件的语法是否正确(若错误则不重载,保持旧配置运行)。
    # 用新配置启动新的工作进程。
    # 逐步关闭旧工作进程(等待它们处理完当前请求)。
    [root@Nginx sbin]# kill -HUP 48732
    [root@Nginx sbin]# ps aux | grep nginx
    root 48732 0.0 0.1 9868 2436 ? Ss 14:17 0:00 nginx: master
    process /usr/local/nginx/sbin/nginx
    root 52075 0.0 0.3 9876 6528 ? S 15:41 0:00 nginx: master
    process /usr/local/nginx/sbin/nginx
    nobody 52076 0.0 0.2 14208 5124 ? S 15:41 0:00 nginx: worker
    process
    nobody 52130 0.0 0.2 14200 4868 ? S 16:30 0:00 nginx: worker
    process
    [root@Nginx sbin]# kill -WINCH 52075
    [root@Nginx sbin]# ps aux | grep nginx
    root 48732 0.0 0.1 9868 2436 ? Ss 14:17 0:00 nginx: master
    process /usr/local/nginx/sbin/nginx
    root 52075 0.0 0.3 9876 6528 ? S 15:41 0:00 nginx: master
    process /usr/local/nginx/sbin/nginx
    nobody 52130 0.0 0.2 14200 4868 ? S 16:30 0:00 nginx: worker
    process
    root 52137 0.0 0.1 221664 2176 pts/0 S+ 16:31 0:00 grep --
    color=auto nginx
    [root@Nginx sbin]# curl -I localhost
    HTTP/1.1 200 OK
    Server: nginx/1.24.0 ##版本回滚完成
    Date: Thu, 18 Jul 2025 08:31:51 GMT
    Content-Type: text/html
    Content-Length: 615
    Last-Modified: Thu, 18 Jul 2025 03:41:13 GMT
    Connection: keep-alive
    ETag: "66988ed9-267"
    Accept-Ranges: bytes

    3 nginx核心配置详解

    3.1 配置文件说明

    nginx官方帮助文档:nginx documentationhttp://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模块引入,可直接引用
    自定义变量:由用户使用set命令定义,格式: set variable_name value;
    引用变量:$variable_name
    主配置文件结构:四部分
    main block:主配置段,即全局配置段,对http,mail都有效
    #事件驱动相关的配置
    event {
    ...
    }#http/https 协议相关配置段
    http {
    默认的nginx.conf 配置文件格式说明
    ...
    }#默认配置文件不包括下面两个块
    #mail 协议相关配置段
    mail {
    ...
    }#stream 服务器相关配置段
    stream {
    ...
    }

    默认的nginx.conf配置文件格式说明:

    # 全局配置端,对全局生效,主要设置nginx的启动用户/组,启动的工作进程数量,工作模式,Nginx的PID路
    径,日志路径等。
    user  nobody; # 这里使用nginx
    worker_processes  1; # 指定工作进程数量,一般设置为auto# error_log  文件路径  日志级别;
    #error_log  logs/error.log; 
    #error_log  logs/error.log  notice;
    #error_log  logs/error.log  info;#pid        logs/nginx.pid; # 指定主进程PID文件路径# events块专门用于设置Nginx与客户端连接相关的底层参数,决定了Nginx如何处理网络事件(如接收连接、处理请求等),这些配置直接影响 Nginx 的并发处理能力
    events {worker_connections  1024; # 设置单个nginx工作进程可以接受的最大并发# 作为web服务器的时候最大并发数为# worker_processes * worker_connections# 作为反向代理的时候最大并发数为# (worker_connections * worker_processes)/2
    }# http块是Nginx服务器配置中的重要部分,缓存、代理和日志格式定义等绝大多数功能和第三方模块都
    # 可以在这设置,http块可以包含多个server块,而一个server块中又可以包含多个location块,
    # server块可以配置文件引入、MIME-Type定义、日志自定义、是否启用sendfile、连接超时时间和
    # 单个链接的请求上限等。
    http {include       mime.types;default_type  application/octet-stream;#log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '#                  '$status $body_bytes_sent "$http_referer" '#                  '"$http_user_agent" "$http_x_forwarded_for"';#access_log  logs/access.log  main;sendfile        on; # 作为web服务器的时候打开sendfile加快静态文件传输,# 数据传输路径为:磁盘 → 内核缓存 → 网络协议栈 → 网卡,# 省略了用户态与内核态之间的拷贝,减少 CPU 占用,提升传输速度,# 被称之为零拷贝。#tcp_nopush     on;#keepalive_timeout  0;keepalive_timeout  65; # 长连接超时时间,单位是秒# 当客户端(如浏览器)发起请求时,若双方支持长连接,# 连接不会在单次请求后立即关闭,而是保持一段时间,供后续请求复用。# 避免每次请求都重新进行 TCP 三次握手,降低网络延迟和服务器资源消耗# 际配置时需根据业务场景(并发量、请求频率)调整,# 静态资源多的服务可适当延长,高并发动态服务可适当缩短。#gzip  on;# server:设置一个虚拟机主机,可以包含自己的全局块,同时也可以包含多个location模块
    # 比如本虚拟机监听的端口、本虚拟机的名称和IP配置,多个server可以使用一个端口
    # 比如都使用80端口提供web服务server {listen       80; # 配置server监听的端口server_name  localhost; # 本server的名称,当访问此名称的时候# nginx会调用当前serevr内部的配置进程匹配#charset koi8-r;#access_log  logs/host.access.log  main;# location是Nginx配置中用于匹配客户端请求URL路径的核心指令,
    # 主要作用是根据请求的URL路径,定义不同的处理规则(如返回静态文件、反向代理到后端服务、
    # 重定向等)。它必须嵌套在 server 块或其他 location 块中,是实现 URL 路由的关键。location / {root   html; # 相当于默认页面的目录名称,默认是安装目录的相对路径,# 可以使用绝对路径配置。index  index.html index.htm; # 默认的页面文件名称}#error_page  404              /404.html;# redirect server error pages to the static page /50x.html# 当服务器返回 500、502、503、504 这些服务器端错误状态码时,# Nginx 会自动将请求重定向到 /50x.html 页面error_page   500 502 503 504  /50x.html; location = /50x.html { # location处理对应的不同错误码的页面定义到/50x.htmlroot   html; # 定义默认页面所在的目录}# proxy the PHP scripts to Apache listening on 127.0.0.1:80##location ~ \.php$ {#    proxy_pass   http://127.0.0.1;#}# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000##location ~ \.php$ {#    root           html;#    fastcgi_pass   127.0.0.1:9000;#    fastcgi_index  index.php;#    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;#    include        fastcgi_params;#}# deny access to .htaccess files, if Apache's document root# concurs with nginx's one##location ~ /\.ht {#    deny  all;#}}# another virtual host using mix of IP-, name-, and port-based configuration##server {#    listen       8000;#    listen       somename:8080;#    server_name  somename  alias  another.alias;#    location / {#        root   html;#        index  index.html index.htm;#    }#}# HTTPS server##server {#    listen       443 ssl;#    server_name  localhost;#    ssl_certificate      cert.pem;#    ssl_certificate_key  cert.key;#    ssl_session_cache    shared:SSL:1m;#    ssl_session_timeout  5m;#    ssl_ciphers  HIGH:!aNULL:!MD5;#    ssl_prefer_server_ciphers  on;#    location / {#        root   html;#        index  index.html index.htm;#    }#}
    # include /usr/local/nginx/conf.d/*.conf # 导入其他路径的配置文件
    }

    3.2 全局配置

    • main全局配置段常见的配置指令分类:
    • 正常运行必备的配置
    • 优化性能相关的配置
    • 用于调试及定位问题相关的配置
    • 事件驱动相关的配置

    全局配置说明:

    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号CPU
    #           00000010:1号CPU
    #           10000000:7号CUP
    # 示例:
    # worker_cpu_affinity 0001 0010 0100 1000;第0号至第3号CPU
    # worker_cpu_affinity 01 10;第0号至第1号cpu
    # 查看配置
    [root@centos8 ~]# ps axo pid,cmd,psr | grep nginx
    31093 nginx: master process /apps 1
    34474 nginx: worker process 1
    34475 nginx: worker process 3
    34476 nginx: worker process 5
    34477 nginx: worker process 7
    # a:显示所有用户的进程
    # x:显示没有控制终端的进程(如后台服务进程)
    # o pid,cmd,psr:自定义输出格式,仅显示三个字段
    # pid:进程 ID。
    # cmd:启动进程的命令(包括参数)。
    # psr:进程当前运行的 CPU 核心编号error_log /usr/local/nginx/logs/error.log error; # 指定错误日志路径和错误级别pid /usr/local/nginx/logs/nginx.pid; # pid文件的保存路径worker_priority 0; # 工作进程的优先级,进程优先级范围通常为-20到19,通常保持默认0即可# 数值越小,优先级越高(如 -20 是最高优先级)# 数值越大,优先级越低(如 19 是最低优先级)# 默认值通常为 0(与系统中其他普通进程优先级相同)# 若服务器专门用于 Nginx 服务,且需要优先保障其响应速度,# 可适当降低数值(提高优先级),如 worker_priority -5;# 若 Nginx 并非服务器核心服务(如同时运行高优先级的计算任务),# 可提高数值(降低优先级),如 worker_priority 5;
    worker_rlimit_nofile 65536; # 所有worker进程能打开的文件数量上限,# 包括:Nginx的所有连接(例如与代理服务器的连接等)# 而不仅仅是与客户端的连接# 另一个考虑因素是实际的并发连接数不能超过# 系统级别的最大打开文件数的限制# 最好与ulimit -n 或者limits.conf的值保持一致
    # 修改pam限制
    [root@Nginx ~]# sudo -u nginx ulimit -n
    1024
    [root@Nginx ~]# vim /etc/security/limits.conf
    * - nofile 100000
    [root@Nginx ~]# sudo -u nginx ulimit -n
    100000daemon off; #前台运行Nginx服务用于测试、docker等环境
    master_process off|on; # 是否开启Nginx的master-worker工作模式,仅用于开发调试场景,默认为onevents {worker_connections 65535; # 设置单个工作进程的最大并发连接数use epoll;                # 使用epoll事件驱动(Linux推荐epoll,性能最优),# Nginx支持众多的事件驱动,# 比如:select、poll、epoll,只能设置在events模块中accept_mutex on; # 惊群问题:当多个 Nginx 工作进程同时监听同一端口时,新连接到达时,# 所有工作进程会被同时唤醒竞争连接,但最终只有一个进程能获取连接,# 其余进程被唤醒后发现无连接可处理,造成 CPU 资源浪费# on时,同一时间只允许一个工作进程尝试接收新连接,避免多进程同时竞争,# 减少 CPU 无效消耗,提高连接处理效率,建议设置为onmulti_accept on; # 允许单个工作进程(worker process)一次性接收多个新连接# 减少accept()调用次数和进程唤醒频率,降低CPU上下文切换开销# 建议开启
    }

    3.2.1 实现nginx的高并发配置

    注意:测试环境由于硬件问题,并发量写小一点(对硬件要求较高)

    1.修改nginx默认配置文档

    [root@server2 conf]# vim /usr/local/nginx/conf/nginx.conf

    2.修改pam限制

    [root@server2 conf]# vim /etc/security/limits.conf

    3.查看pam是否生效

    [root@server2 ~]# sudo -u nginx ulimit -n
    50000

    4.测试并发性能

    [root@server2 ~]# ab -c 1500 -n 50000 http://192.168.36.136/index.html

     -n:请求总量

    -c:并发量

    总共50000个请求,每次发送1500个并发

    3.3 http配置块

    # 在响应报文中将指定的文件扩展名映射至MIME对应的类型
    include /etc/nginx/mime.types;
    default_type application/octet-stream; # 除mime.types中的类型外# 指定其它文件的默认MIME类型,浏览器一般会提示下载
    types {
    text/html html;
    image/gif gif;
    image/jpeg jpg;
    }

    示例:

    [root@Nginx ~]# vim /usr/local/nginx/html/lee.php
    <?php
    phpinfo();
    ?>
    [root@Nginx ~]# curl -I 192.168.36.136/lee.php
    HTTP/1.1 200 OK
    Server: nginx/1.26.1
    Content-Type: application/octet-stream
    Content-Length: 24
    Last-Modified: Fri, 19 Jul 2025 09:38:52 GMT
    Connection: keep-alive
    ETag: "669a342c-18"
    Accept-Ranges: bytes
    [root@Nginx ~]# vim /usr/local/nginx/conf/nginx.conf
    default_type text/html;
    [root@Nginx ~]# nginx -s reload
    [root@Nginx ~]# curl -I 192.168.36.136/lee.php
    HTTP/1.1 200 OK
    Server: nginx/1.26.1
    Date: Fri, 19 Jul 2025 09:49:49 GMT
    Content-Type: text/html
    Content-Length: 24
    Last-Modified: Fri, 19 Jul 2025 09:38:52 GMT
    Connection: keep-alive
    ETag: "669a342c-18"
    Accept-Ranges: bytes

    3.4 核心配置示例

    基于不同的IP、不同的端口以及不用得域名实现不同的虚拟主机,依赖于核心模块
    ngx_http_core_module实现。

    3.4.1 新建一个 PC web 站点

    1.添加子配置文件路径(在配置文件的最后面添加此行,不要放在最前面,会导致前面的命令无法

    生效
    [root@server2 sbin]# vim /usr/local/nginx/conf/nginx.conf

    2.创建虚拟主机网站配置

    [root@server2 sbin]# mkdir -p /usr/local/nginx/conf.d/
    [root@server2 sbin]# vim /usr/local/nginx/conf.d/vhosts.conf
    [root@server2 sbin]#

    3.重新读取配置文件

    [root@server2 sbin]# nginx -s reload

    3.添加域名映射

    [root@server2 sbin]# vim /etc/hosts

    4.测试域名访问效果

    [root@server2 ~]# mkdir -p /web/html
    [root@server2 ~]# vim /web/html/index.html
    web_html
    [root@server2 ~]# curl www.timinglee.org
    web_html

    3.4.2 root与alias

    location中使用root指令和alias指令的意义不同 

    1.root查找路径方式 

    location /dirtest {root /mnt;}
    

     客户实请求路径:curl www.timinglee.org/dirtest/index.html

    Nginx 实际查找的文件路径:/nmt/dirtest/index.html(root路径 + location路径 + 请求资源

    2.alias查找路径方式

    location /alias {alias /mnt/dirtest;}
    

    客户请求路径:curl www.timinglee.org/dirtest/

    nginx实际查找文件路径:/nmt/dirtest/index.html(alias路径 + 请求资源,忽略location路径)

    3.4.3 location的详细使用

    • 在一个serverlocation配置段可存在多个,用于实现从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.4.3.1 匹配案例-精准匹配
    server部分使用location配置一个web界面,例如:当访问nginx 服务器的/logo.jpg的时候要显示指定html文件的内容,精确匹配一般用于匹配组织的logo等相对固定的URL,匹配优先级最高
    1.精确匹配logo
    [root@Nginx ~]# mkdir /webdata/nginx/timinglee.org/lee/images -p
    [root@Nginx ~]# ls /webdata/nginx/timinglee.org/lee/images
    [root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
    server {listen 80;server_name lee.timinglee.org;location / {root /webdata/nginx/timinglee.org/lee/html;}location = /logo.png {root /webdata/nginx/timinglee.org/lee/images;}
    }
    #上传logo.jpg图片到/webdata/nginx/timinglee.org/lee/images,重启Nginx并访问测试
    #访问测试:http://www.timinglee.org/logo.png
    3.1.3.2 匹配案例-区分大小写
    ~ 实现区分大小写的模糊匹配. 以下案例中, 如果访问uri中包含大写字母的logo.PNG,则以下location匹配logo.png条件不成功,因为 ~ 区分大小写,当用户的请求被执行匹配时发现location中定义的是小写的png,本次访问的uri匹配失败,后续要么继续往下匹配其他的location(如果有),要么报错给客户端
    server {listen 80;server_name lee.timinglee.org;location / {root /webdata/nginx/timinglee.org/lee/html;}location ~ /logo.PNG {root /webdata/nginx/timinglee.org/lee/images;}
    }
    #重启Nginx并访问测试
    #http://www.timinglee.org/logo.PNG #访问失败,系统中没有logo.PNG文件
    3.4.3.3 匹配案例-不区分大小写
    ~* 用来对用户请求的uri做模糊匹配,uri中无论都是大写、都是小写或者大小写混合,此模式也都会匹配,通常使用此模式匹配用户request中的静态资源并继续做下一步操作,此方式使用较多
    注意: 此方式中,对于Linux文件系统上的文件仍然是区分大小写的,如果磁盘文件不存在,仍会提示404
    server {listen 80;server_name lee.timinglee.org;location / {root /webdata/nginx/timinglee.org/lee/html;}location ~* /logo.PNG {root /webdata/nginx/timinglee.org/lee/images;}
    }
    #重启Nginx并访问测试
    #http://www.timinglee.org/logo.png
    3.4.3.4 匹配案例-URI开始
    [root@Nginx ~]# mkdir /webdata/nginx/timinglee.org/lee/images/images{1,2}
    [root@Nginx ~]# echo image1 > /webdata/nginx/timinglee.org/lee/images/images1/index.html
    [root@Nginx ~]# echo image1 > /webdata/nginx/timinglee.org/lee/images/images2/index.html
    server {listen 80;server_name lee.timinglee.org;location / {root /webdata/nginx/timinglee.org/lee/html;}location ^~ /images {root /webdata/nginx/timinglee.org/lee/images;index index.html;}location /images1 {root /webdata/nginx/timinglee.org/lee/images;}
    }
    #重启Nginx并访问测试,实现效果是访问/images1和/images2返回内容一样
    [root@node100 ~]# curl 192.168.36.100/images1/
    image1
    [root@node100 ~]# curl 192.168.36.100/images2/
    image1
    3.4.3.5 匹配案例-文件名后缀
    [root@Nginx ~]# mkdir /webdata/nginx/timinglee.org/lee/images
    #上传一个图片到/webdata/nginx/timinglee.org/lee/images
    server {listen 80;server_name lee.timinglee.org;location / {root /webdata/nginx/timinglee.org/lee/html;}location ~* \.(gif|jpg|jpeg|bmp|png|tiff|tif|ico|wmf|js|css)$ {root /webdata/nginx/timinglee.org/lee/images;index index.html;}
    }
    #重启Nginx并访问测试
    192.168.36.200/logo.png
    3.4.3.6 匹配案例-优先级
    server {
    listen 80;server_name lee.timinglee.org;location / {root /webdata/nginx/timinglee.org/lee/html;}location ^~ /images {root /webdata/nginx/timinglee.org/lee/images;index index.html;}location /images1 {root /webdata/nginx/timinglee.org/lee/images;}location ~* \.(gif|jpg|jpeg|bmp|png|tiff|tif|ico|wmf|js)$ {root /data/nginx/static3;index index.html;}
    }
    #匹配优先级:=, ^~, ~/~*,/
    location优先级:(location =) > (location ^~ 路径) > (location ~,~* 正则顺序) >
    (location 完整路径) > (location 部分起始路径) > (/)
    3.4.3.7 生产使用案例
    #直接匹配网站根会加速Nginx访问处理
    location = /index.html {......;
    }
    location / {......;
    }#静态资源配置方法1
    location ^~ /static/ {......;
    }#静态资源配置方法2,应用较多
    location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {......;
    }#多应用配置
    location ~* /app1 {......;
    }
    location ~* /app2 {......;
    }

    3.4.4 Nginx 账户认证功能

    ngx_http_auth_basic_module 模块提供此功能
    示例:
    [root@Nginx ~]# htpasswd -cmb /usr/local/nginx/conf/.htpasswd admin lee #-b 表
    示非交互建立用户认证
    Adding password for user admin
    [root@Nginx ~]# htpasswd -mb /usr/local/nginx/conf/.htpasswd lee lee
    Adding password for user lee
    [root@Nginx ~]# cat /usr/local/nginx/conf/.htpasswd
    admin:$apr1$haGCKgCT$myogggALmqNecTyNupsWQ/
    lee:$apr1$H97AyQPF$kGU.Tc4zn1E4Zkp/M4R6G.
    [root@Nginx ~]# mkdir /webdata/nginx/timinglee.org/lee/login
    [root@Nginx ~]# echo login > /webdata/nginx/timinglee.org/lee/login/index.html
    [root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
    server {
    listen 80;
    server_name lee.timinglee.org;
    location /login {
    root /webdata/nginx/timinglee.org/lee;
    index index.html;
    auth_basic "login password";
    auth_basic_user_file "/usr/local/nginx/conf/.htpasswd";
    }
    }
    #重启Nginx并访问测试
    [root@node100 ~]# curl lee.timinglee.org/login/ -u lee:lee
    login
    [root@node100 ~]# curl lee.timinglee.org/login/ -u admin:lee
    login

    实验验证:

    基于用户的访问

    [root@server2 ~]# mkdir -p /web/login/
    [root@server2 ~]# touch index.html
    [root@server2 ~]# echo "login" > /web/login/index.html
    [root@server2 ~]# cat /web/login/index.html 
    login
    [root@server2 ~]#
    [root@server2 conf.d]# htpasswd -cm /usr/local/nginx/.htpasswd admin # 创建nginx所需认证文件和用户
    # -c创建新的文件会覆盖旧文件
    New password: 
    Re-type new password: 
    Adding password for user admin
    [root@server2 conf.d]# htpasswd -m /usr/local/nginx/.htpasswd lee
    New password: 
    Re-type new password: 
    Adding password for user lee
    [root@server2 conf.d]# cat /usr/local/nginx/.htpasswd 
    admin:$apr1$.0fUA3Pl$e6CqYByBBLgDfrZAps32y/
    lee:$apr1$pPwPp51g$/PBcT9Xl293rX5ciMdaE4.
    [root@server2 conf.d]# 
    
    [root@server2 conf.d]# vim vhosts.conf 
    [root@server2 conf.d]# pwd
    /usr/local/nginx/conf.d
    

    验证是否成功

    [root@server2 ~]# 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@server2 ~]# nginx -s reload
    [root@server2 ~]# curl www.timinglee.org/login/
    <html>
    <head><title>401 Authorization Required</title></head>
    <body>
    <center><h1>401 Authorization Required</h1></center>
    <hr><center>nginx/1.24.0</center>
    </body>
    </html>
    [root@server2 ~]# curl -uadmin:lee www.timinglee.org/login/
    login
    [root@server2 ~]#

    3.4.5 自定义错误页面和错误日志

    自定义错误和日志

    [root@server2 web]# mkdir errorpage
    [root@server2 web]# echo "错误" > error.html
    [root@server2 web]# cat error.html 
    错误
    

    [root@server2 logs]# touch timinglee.org.err
    [root@server2 logs]# touch timinglee.org.acc
    [root@server2 logs]# pwd
    /usr/local/nginx/logs
    [root@server2 logs]#

     验证

    3.4.7 检测文件是否存在

    try_files会按顺序检查文件是否存在,返回第一个找到的文件或文件夹(结尾加斜线表示为文件夹),如果所有文件或文件夹都找不到,会进行一个内部重定向到最后一个参数。只有最后一个参数可以引起一个内部重定向,之前的参数只设置内部URI的指向。最后一个参数是回退URI且必须存在,否则会出现内部500错误。
    示例:如果不存在页面,就转到default.html页面
    [root@Nginx ~]# echo "index.html is not exist" >
    /webdata/nginx/timinglee.org/lee/error/default.html
    [root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
    server {listen 80;server_name lee.timinglee.org;root /webdata/nginx/timinglee.org/lee;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 /webdata/nginx/timinglee/lee/errors;}
    }

    实验验证:

    [root@server2 conf.d]# echo default > /web/errorpage/default.html
    [root@server2 conf.d]# cat /web/errorpage/default.html 
    default
    

    测试

    3.4.8 长连接配置

    keepalive_timeout timeout [header_timeout]; # 设定保持连接超时时长,0表示禁止长连接,默认为75s# 通常配置在http字段作为站点全局配置
    keepalive_requests 数字;                     # 在一次长连接上所允许请求的资源的最大数量# 默认为100次,建议适当调大,比如:500

    示例:

    keepalive_requests 3;
    keepalive_timeout 65 60;
    #开启长连接后,返回客户端的会话保持时间为60s,单次长连接累计请求达到指定次数请求或65秒就会被断
    开,第二个数字60为发送给客户端应答报文头部中显示的超时时间设置为60s:如不设置客户端将不显示超时时
    间。
    Keep-Alive:timeout=60 #浏览器收到的服务器返回的报文
    #如果设置为0表示关闭会话保持功能,将如下显示:
    #Connection:close 浏览器收到的服务器返回的报文
    #使用命令测试:
    [root@node100 ~]# telnet lee.timinglee.org 80
    Trying 172.25.254.200...
    Connected to lee.timinglee.org.
    Escape character is '^]'.
    GET / HTTP/1.1 ##输入动作
    HOST: lee.timinglee.org ##输入访问HOST
    ##输入回车
    HTTP/1.1 200 OK
    Server: nginx/1.24.0
    Date: Sat, 20 Jul 2024 12:54:16 GMT
    Content-Type: text/html
    Content-Length: 15
    Last-Modified: Sat, 20 Jul 2024 08:49:12 GMT
    Connection: keep-alive
    ETag: "669b7a08-f"
    Accept-Ranges: bytes
    172.25.254.200
    GET / HTTP/1.1 #第二次操作
    HOST: lee.timinglee.org #第二次操作
    #第二次操作
    HTTP/1.1 200 OK
    Server: nginx/1.24.0
    Date: Sat, 20 Jul 2024 12:54:25 GMT
    Content-Type: text/html
    Content-Length: 15
    Last-Modified: Sat, 20 Jul 2024 08:49:12 GMT
    Connection: close
    ETag: "669b7a08-f"
    Accept-Ranges: bytes
    172.25.254.200
    Connection closed by foreign host. #自动断开链接

    实验验证

    [root@server2 conf]# vim nginx.conf # 长链接位于nginx主配置文件
    [root@server2 conf]# pwd
    /usr/local/nginx/conf
    [root@server2 conf]# 

    [root@server2 ~]# yum install telnet -y

    3.4.9 作为下载服务器配置

    ngx_http_autoindex_module 模块处理以斜杠字符 "/" 结尾的请求,并生成目录列表,可以做为下载服务配置使用
    相关指令:
    autoindex on | off; # 自动文件索引功能,默为off
    autoindex_exact_size on | off; # 计算文件确切大小(单位bytes),off 显示大概大小(单位K、M),默认on
    autoindex_localtime on | off ; # 显示本机时间而非GMT(格林威治)时间,默认off
    autoindex_format html | xml | json | jsonp; # 显示索引的页面文件风格,默认html
    limit_rate rate; # 限制响应客户端传输速率(除GET和HEAD以外的所有方法),单位B/s,bytes/second,# 默认值0,表示无限制,此指令由ngx_http_core_module提供
    set $limit_rate 4k; # 也可以通变量限速,单位B/s,同时设置,此项优级高.

    示例:实现下载站点

    #注意:download不需要index.html文件
    [root@Nginx ~]# mkdir -p /webdata/nginx/timinglee.org/lee/download
    [root@Nginx ~]# cp /root/anaconda-ks.cfg /webdata/nginx/timinglee.org/lee/download
    [root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
    server {listen 80;server_name lee.timinglee.org;root /webdata/nginx/timinglee.org/lee;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 /webdata/nginx/timinglee/lee/errors;}location /download {autoindex on; #自动索引功能autoindex_exact_size on; #计算文件确切大小(单位bytes),此为默认值,off只显示大概大小(单位kb、mb、gb)autoindex_localtime on; #on表示显示本机时间而非GMT(格林威治)时间,默为为off显示GMT时间limit_rate 1024k; #限速,默认不限速 }
    }
    #重启Nginx并访问测试下载页面

    实验实现:

    1.建立实验素材 

    2.下载服务器 

     3.测试

    4 nginx高级配置

    4.1 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)

    4.1 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;

    示例:

    #重启nginx并进行访问测试压缩功能
    [root@Nginx ~]# mkdir /webdata/nginx/timinglee.org/lee/data
    [root@Nginx ~]# cp /usr/local/nginx/logs/access.log
    /webdata/nginx/timinglee.org/lee/data/data.txt
    [root@Nginx ~]# echo test > /webdata/nginx/timinglee.org/lee/data/test.html #
    小于1k的文件测试是否会压缩
    [root@Nginx ~]# vim /usr/local/nginx/conf/nginx.conf
    @@@@省略内容@@@@
    gzip on;
    gzip_comp_level 5;
    gzip_min_length 1k;
    gzip_types text/plain application/javascript application/x-javascript text/css
    application/xml text/javascript application/x-httpd-php image/gif image/png;
    gzip_vary on;
    #重启Nginx并访问测试:
    [root@client ~]# curl --head --compressed lee.timinglee.org/data/test.html
    HTTP/1.1 200 OK
    Server: nginx/1.26.1
    Date: Sun, 21 Jul 2024 15:42:46 GMT
    Content-Type: text/html
    Content-Length: 5
    Last-Modified: Sun, 21 Jul 2024 15:40:35 GMT
    Connection: keep-alive
    ETag: "669d2bf3-5"
    Accept-Ranges: bytes
    [root@client ~]# curl --head --compressed lee.timinglee.org/data/data.txt
    HTTP/1.1 200 OK
    Server: nginx/1.26.1
    Date: Sun, 21 Jul 2024 15:43:17 GMT
    Content-Type: text/plain
    Last-Modified: Sun, 21 Jul 2024 15:40:13 GMT
    Connection: keep-alive
    Vary: Accept-Encoding
    ETag: W/"669d2bdd-3e25b5"
    Content-Encoding: gzip

    实验验证:

    1.准备压缩材料

    [root@server2 conf.d]# cp /usr/local/nginx/logs/timinglee.org.acc /web/html/big.html
    [root@server2 conf.d]# echo hello > /web/html/small.html
    [root@server2 conf.d]# cat /web/html/small.html 
    hello
    

    2.编辑配置文件

    测试压缩效果

    [root@server2 conf.d]# cp /usr/local/nginx/logs/timinglee.org.acc /web/html/big.html

    [root@server2 conf.d]# curl --head --compressed www.timinglee.org/small.html

    4.3 nginx的版本隐藏

    用户在访问nginx的时候,我们可以从报文中获得nginx的版本,相对于裸漏版本号的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 内置变量

    官方文档:Alphabetical index of variableshttp://nginx.org/en/docs/varindex.html

    常用内置变量:

    $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为任意请求报文首部字段,表示记录请求报文的首部字段,name的对应的首部字段名需要为小写,如果有
    横线需要替换为下划线
    #示例:
    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 ~]# vim /usr/local/nginx/conf.d/vhosts.conf
    server {listen 80;server_name lee.timinglee.org;root /webdata/nginx/timinglee.org/lee;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;}
    }[root@client ~]# curl -b "title=lee;key1=lee,key2=timinglee"
    "lee.timinglee.org/var?search=lee&&id=666666"
    172.25.254.20
    search=lee&&id=666666
    /webdata/nginx/timinglee.org/lee
    /var
    lee.timinglee.org
    curl/7.29.0
    /webdata/nginx/timinglee.org/lee/var
    http
    http://lee.timinglee.org/var?search=lee&&id=666666
    title=lee;key1=lee,key2=timinglee
    timinglee
    */*
    实验验证:
    1.实验前需要导入echo-nginx-module-0.63模块(前面并没有安装此模块)
    [root@server2 ~]# rm -rf /usr/local/nginx/
    [root@server2 ~]# cd /usr/local/
    [root@server2 local]# rm -rf nginx-1.26.3/
    [root@server2 ~]# cd /usr/local/
    [root@server2 local]# tar zxf /root/nginx-1.26.3.tar.gz
    [root@server2 local]# tar zxf /root/echo-nginx-module-0.63.tar.gz
    [root@server2 nginx-1.26.3]# ./configure --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 --add-module=/usr/local/echo-nginx-module-0.63
    [root@server2 nginx-1.26.3]# make && make install

     验证

    [root@server2 conf.d]# nginx -s reload
    [root@server2 conf.d]# curl -A "timinglee" -b "lee=a,key1=2" -ulee:lee www.timinglee.org/vars?name=lee

    4.4.2 自定义变量

    假如需要自定义变量名称和值,使用指令set $variable value;
    示例:
    set $name timinglee;
    echo $name;
    set $my_port $server_port;
    echo $my_port;
    echo "$server_name:$server_port";
    [root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
    server {listen 80;server_name lee.timinglee.org;root /webdata/nginx/timinglee.org/lee;location /var {default_type text/html;set $name timinglee;echo $name;set $web_port $server_port;echo $web_port;}
    }
    测试输出
    [root@client ~]# curl lee.timinglee.org/var
    timinglee
    80

    5 Nginx Rewrite 相关功能

    • Nginx服务器利用 ngx_http_rewrite_module 模块解析和处理rewrite请求
    • 此功能依靠 PCRE(perl compatible regular expression),因此编译之前要安装PCRE
    • rewritenginx服务器的重要功能之一,用于实现URL的重写,URL的重写是非常有用的功能
    • 比如它可以在我们改变网站结构之后,不需要客户端修改原来的书签,也无需其他网站修改我们的链接,就可以设置为访问
    • 另外还可以在一定程度上提高网站的安全性。

    5.1 ngx_http_rewrite_module 模块指令

    官方文档:Module ngx_http_rewrite_modulehttps://nginx.org/en/docs/http/ngx_http_rewrite_module.html

    5.2 rewrite 案例: break last

     rewrite中break与last区别

    [root@server2 ~]# mkdir /web/html/{test1,test2,break,last}
    [root@server2 ~]# echo test1 > /web/html/test1/index.html
    [root@server2 ~]# echo test2 > /web/html/test2/index.html
    [root@server2 ~]# echo break > /web/html/break/index.html
    [root@server2 ~]# echo last > /web/html/last/index.html
    [root@server2 ~]#

     测试

    5.2.1 rewrite案例: 自动跳转 https

    案例:基于通信安全考虑公司网站要求全站 https,因此要求将在不影响用户请求的情况下将http请求全部自动跳转至 https,另外也可以实现部分 location 跳转https加密基本配置及全站加密策略

    [root@server2 conf.d]# openssl req -newkey rsa:2048 -nodes -sha256 -keyout /usr/local/nginx/certs/timinglee.org.key -x509 -days 365 -out /usr/local/nginx/certs/timinglee.org.crt
    

     

    测试

    5.2.2 rewrite 案例: 判断文件是否存在

    案例:当用户访问到公司网站的时输入了一个错误的URL,可以将用户重定向至官网首页

    [root@centos8 ~]#vim /apps/nginx/conf.d/pc.conf
    location / {root /data/nginx/html/pc;index index.html;if (!-e $request_filename) {rewrite .* http://www.timinglee.org/index.html; #实现客户端浏览器的302跳转#rewrite .* /index.html; #web服务器内部跳转}
    }
    #重启Nginx并访问测试

     判断文件是否存在

    5.3 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

    5.3.1 实现盗链

    在一个web 站点盗链另一个站点的资源信息,比如:图片、视频等
    示例:
    #新建一个主机172.25.254.20,盗取另一台主机lee.timinglee.org/images/lee.png的图片
    [root@client ~]# yum install httpd -y
    [root@client html]# vim /var/www/html/index.html
    #准备盗链web页面:
    <html>
    <head>
    <meta http-equiv=Content-Type content="text/html;charset=utf-8">
    <title>盗链</title>
    </head>
    <body>
    <img src="http://www.timinglee.org/images/lee.png" >
    <h1 style="color:red">欢迎大家</h1>
    <p><a href=http://www.timinglee.org>狂点老李</a>出门见喜</p>
    </body>
    </html>
    ~
    #重启apache并访问http://172.25.254.20 测试
    #验证两个域名的日志,是否会在被盗连的web站点的日志中出现以下盗链日志信息:
    [root@Nginx ~]# cat /usr/local/nginx/logs/access.log
    172.25.254.1 - - [22/Jul/2024:09:50:01 +0800] "GET /images/logo.png HTTP/1.1" 304
    0 "http://172.25.254.20/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64)
    AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
    Edg/126.0.0.0"
    172.25.254.1 - - [22/Jul/2024:09:50:18 +0800] "GET / HTTP/1.1" 304 0
    "http://172.25.254.20/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64)
    AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
    Edg/126.0.0.0"

    5.3.2 实现防盗链

    基于访问安全考虑,nginx支持通过ngx_http_referer_module模块,检查访问请求的referer信息是否有效实现防盗链功能
    官方文档:Module ngx_http_referer_modulehttps://nginx.org/en/docs/http/ngx_http_referer_module.html

    示例:定义防盗链

    [root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
    server {listen 80;server_name www.timinglee.org;root /data/web/html;index index.html;location / {valid_referers none blocked server_names *.timinglee.org ~/.baidu/.;if ($invalid_referer){return 404;}
    }location /images {valid_referers none blocked server_names *.timinglee.org ~/.baidu/.;if ($invalid_referer){rewrite ^/ http://www.timinglee.org/daolian.png permanent; #注意此图片不能和正常图片放在一个目录中}}
    }
    #重启Nginx并访问测试
    http://172.25.254.20

    6 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协议转发至指定服务器处理
    逻辑调用关系:

    访问逻辑图:
    • 同构代理:用户不需要其他程序的参与,直接通过http协议或者tcp协议访问后端服务器
    • 异构代理:用户访问的资源时需要经过处理后才能返回的,比如phppython,等等,这种访问资源需要经过处理才能被访问

    6.1 实现http反向代理

    官方文档:Module ngx_http_proxy_modulehttps://nginx.org/en/docs/http/ngx_http_proxy_module.html

    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.timinglee.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.conf
    LogFormat "\"%{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 服务器
    要求:将用户对域 www.timinglee.org 的请求转发给后端服务器处理
    [root@centos8 ~]# cat /apps/nginx/conf/conf.d/pc.conf
    server {listen 80;server_name www.timinglee.org;location / {proxy_pass http://172.25.254.30;}
    }
    #重启Nginx 并访问测试
    6.1.1.3 实战案例: 指定 location 实现反向代理
    6.1.1.3.1 针对指定的 location
    server {
    listen 80;server_name www.timinglee.org;location / {proxy_pass http://172.25.254.30;}location ~ /static {proxy_pass http://172.25.254.20:8080;}
    }
    # 后端web服务器必须要有相对于的访问URL
    [root@apache20 ~]# mkdir /var/www/html/static
    [root@apache20 ~]# echo static 172.25.254.20 > /var/www/html/static/index.html
    [root@apache30 ~]# echo 172.25.254.30 > /var/www/html/index.html
    # 重启Nginx并访问测试:
    [2025-07-25 17:09.35] ~
    [Administrator.DESKTOP-P19CNDN] ➤ curl www.timinglee.org/static/
    static 172.25.254.20
    [2025-07-25 17:09.39] ~
    [Administrator.DESKTOP-P19CNDN] ➤ curl www.timinglee.org
    172.25.254.30
    6.1.1.3.2 针对特定的资源实现代理

    [root@Nginx ~]# vim /apps/nginx/conf.d/vhost.conf
    server {listen 80;server_name www.timinglee.org;location / {proxy_pass http://172.25.254.30;}location ~ \.(png|jpg|gif) {proxy_pass http://172.25.254.20:8080;}
    }
    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:http
    proxy_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个左右的key
    inactive=120s # 缓存有效时间
    max_size=10g; # 最大磁盘占用空间,磁盘存入文件内容的缓存空间最大值
    # 调用缓存功能,需要定义在相应的配置段,如server{...};或者location等
    proxy_cache proxycache;
    proxy_cache_key $request_uri; # 对指定的数据进行MD5的运算做为缓存的key
    proxy_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.1.4.1 非缓存场景压测
    # 准备后端httpd服务器
    [root@apache20 app1]# pwd
    /var/www/html/static
    [root@apache20 static]# cat /var/log/messages > ./log.html # 准备测试页面
    [root@apache30 ~]# ab -n1000 -c100 http://www.timinglee.org/static/index.html
    Concurrency Level: 100
    Time taken for tests: 23.238 seconds
    Complete requests: 1000
    Failed requests: 0
    Total transferred: 2011251000 bytes
    HTML transferred: 2010991000 bytes
    Requests per second: 43.03 [#/sec] (mean)
    Time per request: 2323.789 [ms] (mean)
    Time per request: 23.238 [ms] (mean, across all concurrent requests)
    Transfer rate: 84521.97 [Kbytes/sec] received
    6.1.1.4.2 准备缓存配置
    [root@Nginx ~]# vim /apps/nginx/conf/nginx.conf
    @@@@内容省略@@@@
    # gzip on;
    proxy_cache_path /apps/nginx/proxy_cache levels=1:2:2 keys_zone=proxycache:20m
    inactive=120s max_size=1g; #配置在nginx.conf http配置段
    [root@Nginx ~]# vim /apps/nginx/conf.d/vhost.conf
    location ~ /static { # 要缓存的URL 或者放在server配置项对所有URL都进行缓存proxy_pass http://172.25.254.20:8080;proxy_cache proxycache;proxy_cache_key $request_uri;proxy_cache_valid 200 302 301 10m;proxy_cache_valid any 1m; # 必须指定哪些响应码的缓存
    }
    # /data/nginx/proxycache/ 目录会自动生成
    [root@Nginx ~]# ll /apps/nginx/proxy_cache/ -d
    drwx------ 3 nginx root 4096 7月 25 20:07 /apps/nginx/proxy_cache/
    [root@Nginx ~]# tree /apps/nginx/proxy_cache/
    /data/nginx/proxycache/
    0 directories, 0 files
    6.1.1.4.3 访问并验证缓存文件
    #访问web并验证缓存目录
    [root@apache30 ~]# ab -n1000 -c100 http://www.timinglee.org/static/index.html
    [root@centos8 ~]# ab -n 2000 -c200 http://www.timinglee.org/static/log.html
    Concurrency Level: 100
    Time taken for tests: 10.535 seconds
    Complete requests: 1000
    Failed requests: 0
    Total transferred: 2011251000 bytes
    HTML transferred: 2010991000 bytes
    Requests per second: 94.92 [#/sec] (mean)
    Time per request: 1053.507 [ms] (mean)
    Time per request: 10.535 [ms] (mean, across all concurrent requests)
    Transfer rate: 186435.60 [Kbytes/sec] received# 验证缓存目录结构及文件大小
    [root@Nginx ~]# tree /apps/nginx/proxy_cache/
    /apps/nginx/proxy_cache/
    └── e
    └── 50
    └── 99
    └── 319432ef3663735a9d3cb4e0c1d9950e
    3 directories, 0 files

    6.1.2 http 反向代理负载均衡

    在上一个节中Nginx可以将客户端的请求转发至单台后端服务器但是无法转发至特定的一组的服务器,而且不能对后端服务器提供相应的服务器状态监测,Nginx 可以基于·ngx_http_upstream_module模块提 供服务器分组转发、权重分配、状态监测、调度算法等高级功能nginx做反向代理
    官方文档:Module ngx_http_upstream_modulehttps://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而不用重启Nginx
    hash KEY [consistent];
    # 基于指定请求报文中首部字段或者URI等key做hash计算,使用consistent参数,将使用ketama一致性
    hash算法,适用于后端是Cache服务器(如varnish)时使用,consistent定义使用一致性hash运算,一致
    性hash基于取模运算
    hash $request_uri consistent; # 基于用户请求的uri做hash
    hash $cookie_sessionid # 基于cookie中的sessionid这个key进行hash调度,实现会话绑定
    ip_hash;
    # 源地址hash调度方法,基于的客户端的remote_addr(源地址IPv4的前24位或整个IPv6地址)做hash计
    算,以实现会话保持
    least_conn;
    # 最少连接调度算法,优先将客户端请求调度到当前连接最少的后端服务器,相当于LVS中的WLC
    6.1.2.2 反向代理示例: 后端多台 web服务器
    环境说明:
    172.25.254.10 # Nginx 代理服务器
    172.25.254.20 # 后端web A,Apache部署
    172.25.254.30 # 后端web B,Apache部署
    部署后端 Apache服务器
    [root@apache20 ~]# yum install httpd -y
    [root@apache20 ~]# echo "web1 172.25.254.20" > /var/www/html/index.html
    [root@apache20 ~]# systemctl enable --now httpd
    [root@apache30 ~]# yum install httpd -y
    [root@apache30 ~]# echo "web2 172.25.254.30" >> /var/www/html/index.html
    [root@apache30 ~]# systemctl enable --now httpd# 访问测试
    [root@centos8 ~]# curl http://172.25.254.20
    web1 172.25.254.20
    [root@centos8 ~]# curl http://172.25.254.30
    web2 172.25.254.30
    配置 nginx 反向代理
    注意: 本节实验过程中先关闭缓存
    [root@centos8 ~]# cat /apps/nginx/conf/conf.d/pc.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.30:80 weight=1 fail_timeout=15s max_fails=3;server 172.25.254.10:80 backup;
    }
    server {listen 80;server_name www.timinglee.org;location ~ / {proxy_pass http://webserver;}
    }# 重启Nginx 并访问测试
    [Administrator.DESKTOP-P19CNDN] ➤ curl www.timinglee.org
    172.25.254.20 web
    [Administrator.DESKTOP-P19CNDN] ➤ curl www.timinglee.org
    172.25.254.30 web
    #关闭172.25.254.20和172.25.254.30,测试nginx backup服务器可用性:
    [Administrator.DESKTOP-P19CNDN] ➤ while true;do curl
    http://www.timinglee.org;sleep 1;done
    实战案例: 基于Cookie 实现会话绑定
    [root@Nginx ~]# vim /apps/nginx/conf.d/vhost.conf
    http {upstream websrvs {hash $cookie_hello; # hello是cookie的key的名称server 10.0.0.101:80 weight=2;server 10.0.0.102:80 weight-1;}
    }[root@centos8 ~]# vim /apps/nginx/conf/conf.d/pc.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.30:80 weight=1 fail_timeout=15s max_fails=3;# server 172.25.254.10:80 backup;
    }
    server {listen 80;server_name www.timinglee.org;location ~ / {proxy_pass http://webserver;}
    }
    #测试
    [Administrator.DESKTOP-P19CNDN] ➤ curl -b lee=1 www.timinglee.org

    6.2 实现 Nginx 四层负载均衡

    Nginx1.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模块

    6.2.1 tcp负载均衡配置参数

    注意:tcp的负载均衡要卸载http语句块之外
    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 负载均衡实例: MySQL

    1.后端服务器安装 MySQL
    #在apache20中安装mysql
    [root@apache20 ~]# yum install mariadb-server -y
    [root@apache20 ~]# vim /etc/my.cnf.d/mariadb-server.cnf
    [mysqld]
    server-id=20
    [root@apache20 ~]# systemctl start mariadb
    [root@apache20 ~]# mysql -e "grant all on *.* to lee@'%' identified by 'lee';"
    [root@apache30 ~]# mysql -ulee -plee -h172.25.254.20 -e "select @@server_id"
    +-------------+
    | @@server_id |
    +-------------+
    | 20 |
    +-------------+
    #在apache30重复以上步骤并在apache20上测试
    2.nginx配置
    [root@Nginx ~]# vim /apps/nginx/conf/tcp/tcp.conf
    stream {
    upstream mysql_server {
    server 172.25.254.20:3306 max_fails=3 fail_timeout=30s;
    server 172.25.254.30:3306 max_fails=3 fail_timeout=30s;
    }
    server {
    listen 172.25.254.10:3306;
    proxy_pass mysql_server;
    proxy_connect_timeout 30s;
    proxy_timeout 300s;
    }
    }
    # 重启nginx并访问测试:
    [root@Nginx ~]# nginx -s reload
    # 测试通过nginx负载连接MySQL:
    [root@apache30 ~]# mysql -ulee -plee -h172.25.254.10 -e "select @@server_id"
    +-------------+
    | @@server_id |
    +-------------+
    | 20 |
    +-------------+
    [root@apache30 ~]# mysql -ulee -plee -h172.25.254.10 -e "select @@server_id"
    +-------------+
    | @@server_id |
    +-------------+
    | 30 |
    +-------------+
    # 在10.0.0.28停止MySQL服务
    [root@apache20 ~]# systemctl stop mariadb
    # 再次测试访问,只会看到mysql-server1.timinglee.org进行响应
    [root@apache30 ~]# mysql -ulee -plee -h172.25.254.10 -e "select @@server_id"
    +-------------+
    | @@server_id |
    +-------------+
    | 30 |
    +-------------+
    [root@apache30 ~]# mysql -ulee -plee -h172.25.254.10 -e "select @@server_id"
    +-------------+
    | @@server_id |
    +-------------+
    | 30 |
    +-------------+

    6.2.3 udp 负载均衡实例: DNS

    stream {upstream dns_server{server 172.25.254.20:53 max_fails=3 fail_timeout=30s;server 172.25.254.30:53 max_fails=3 fail_timeout=30s;}server {listen 172.25.254.10:53 udp;proxy_pass dns_server;proxy_timeout 1s;proxy_responses 1; # 使用UDP协议时,设置代理服务器响应客户端期望的数据报文数# 该值作为会话的终止条件error_log logs/dns.log;}
    }测试:
    [root@apache30 named]# dig www.timinglee.org @172.25.254.10
    ; <<>> DiG 9.16.23 <<>> www.timinglee.org @172.25.254.10
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33888
    ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 1232
    ; COOKIE: 701447f1bdd8acea0100000066a27b465426b2b4bc7f1dc3 (good)
    ;; QUESTION SECTION:
    ;www.timinglee.org. IN A
    ;; ANSWER SECTION:
    www.timinglee.org. 86400 IN A 172.25.254.20
    ;; Query time: 2 msec
    ;; SERVER: 172.25.254.10#53(172.25.254.10)
    ;; WHEN: Fri Jul 26 00:20:22 CST 2024
    ;; MSG SIZE rcvd: 90
    [root@apache30 named]# dig www.timinglee.org @172.25.254.10
    ; <<>> DiG 9.16.23 <<>> www.timinglee.org @172.25.254.10
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8932
    ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 1232
    ; COOKIE: 8ecb61bbfe2716df0100000066a27b47a3bb0c3d8e537858 (good)
    ;; QUESTION SECTION:
    ;www.timinglee.org. IN A
    ;; ANSWER SECTION:
    www.timinglee.org. 86400 IN A 172.25.254.30
    ;; Query time: 1 msec
    ;; SERVER: 172.25.254.10#53(172.25.254.10)
    ;; WHEN: Fri Jul 26 00:20:23 CST 2024
    ;; MSG SIZE rcvd: 90

    6.3 实现 FastCGI

    CGI的由来:
    最早的Web服务器只能简单地响应浏览器发来的HTTP请求,并将存储在服务器上的HTML文件返回给浏览器,也就是静态html文件,但是后期随着网站功能增多网站开发也越来越复杂,以至于出现动态技术,比如像php(1995)java(1995)python(1991)语言开发的网站,但是nginx/apache服务器并不能直接运行 phpjava这样的文件,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代码的处理。

    6.3.1 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 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
    }

    6.3.2 FastCGI实战案例 : Nginxphp-fpm在同一服务器

    编译安装更方便自定义参数或选项,所以推荐使用源码编译
    官方网站:www.php.net
    1.源码编译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
    2.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
    3.准备php测试页面
    [root@Nginx ~]# mkdir /data/php -p
    [root@centos8 ~]# cat /data/php/index.php # php测试页面
    <?php
    phpinfo();
    ?>
    4.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 php.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
    5.访问验证php测试页面

    6.添加php环境变量
    [root@Nginx ~]# vim .bash_profile
    # .bash_profile
    # Get the aliases and functions
    if [ -f ~/.bashrc ]; then
    . ~/.bashrc
    fi
    # User specific environment and startup programs
    PATH=$PATH:$HOME/bin:/apps/nginx/sbin:/usr/local/php/bin
    export PATH
    [root@Nginx ~]# source .bash_profile

    6.3.3 php的动态扩展模块(php的缓存模块)

    1.软件下载:http://pecl.php.net/package/memcache

    2.安装memcache模块
    [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
    [root@Nginx memcache-8.2]# ./configure && make && make install
    Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-nonzts-20230831/
    [root@Nginx memcache-8.2]# ls /usr/local/php/lib/php/extensions/no-debug-non-zts-
    20230831/
    memcache.so opcache.so
    3.复制测试文件到nginx发布目录中
    [root@Nginx ~]# cd memcache-8.2/
    [root@Nginx memcache-8.2]# ls
    autom4te.cache config.log configure.ac example.php Makefile.fragments
    README
    build config.m4 config.w32 include Makefile.objects runtests.php
    config9.m4 config.nice CREDITS libtool memcache.la src
    config.h config.status docker LICENSE memcache.php
    tests
    config.h.in configure Dockerfile Makefile modules
    [root@Nginx memcache-8.2]# cp example.php memcache.php /data/php/
    [root@Nginx ~]# vim /data/php/memcache.php
    define('ADMIN_USERNAME','admin'); // Admin Username
    define('ADMIN_PASSWORD','lee'); // 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
    4.配置php加载memcache模块
    [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
    5.部署memcached
    [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
    976 1037243 186762/memcached
    [root@Nginx ~]# cat /etc/sysconfig/memcached
    PORT="11211"
    USER="memcached"
    MAXCONN="1024"
    CACHESIZE="64"
    OPTIONS="-l 127.0.0.1,::1"
    6.测试
    访问 http://php.timinglee.org/example.php 不断刷新
    访问 http://php.timinglee.org/memcache.php 查看命中效果

    7.性能对比
    [root@apache20 ~]# ab -n500 -c10 http://php.timinglee.org/index.php
    @@@内容忽略@@@
    Concurrency Level: 10
    Time taken for tests: 0.514 seconds
    Complete requests: 500
    Failed requests: 44
    (Connect: 0, Receive: 0, Length: 44, Exceptions: 0)
    [root@apache20 ~]# ab -n500 -c10 http://php.timinglee.org/example.php
    @@@内容忽略@@@
    Concurrency Level: 10
    Time taken for tests: 0.452 seconds
    Complete requests: 500
    Failed requests: 0

    6.3.4 php高速缓存

    1.部署方法
    在我们安装的nginx中默认不支持memcsrcache功能,需要借助第三方模块来让nginx支持此功能,所以nginx需要重新编译
    [root@Nginx ~]# rm -fr /apps/nginx/
    [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 --withhttp_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 /apps/nginx/conf.d/php.conf
    upstream memcache {
    server 127.0.0.1:11211;
    keepalive 512;
    }
    server {
    listen 80;
    server_name php.timinglee.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
    2.测试结果:
    [root@apache20 ~]# ab -n500 -c10 http://php.timinglee.org/index.php
    Concurrency Level: 10
    Time taken for tests: 0.255 seconds
    Complete requests: 500
    Failed requests: 0

    nginx 二次开发版本

    7.1 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/

    7.2 编译安装 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

    http://www.dtcms.com/a/323298.html

    相关文章:

  • 沿街晾晒识别误检率↓76%:陌讯多模态融合算法实战解析
  • VisionPro常用标定方式
  • 本科毕业论文怎么引用github里面数据集
  • Vue3从入门到精通: 2.2 Vue3组件通信与数据传递深度解析
  • AI热点周报(8.3~8.9):OpenAI重返开源,Anthropic放大招,Claude4.1、GPT5相继发布
  • 心灵笔记:正念冥想
  • imx6ull-驱动开发篇16——信号量与互斥体
  • SpringBoot学习日记 Day6:解锁微服务与高效任务处理
  • .NET程序跨平台ARM电脑上发布的程序格式是,so还是DLL?
  • AWT 基本组件深入浅出:Button/Label/TextField/Checkbox/Choice/List 全面实战与性能优化
  • GPT-4 vs GPT-5 深度分析
  • 逻辑回归详解:原理、应用与实践
  • n沟道增强型mos管
  • 支持 UMD 自定义组件与版本控制:从 Schema 到动态渲染
  • Beelzebub靶机通关教程
  • java 中 @NotBlank 和 @NotNull 的区别
  • 【LLM实战|llamaIndex】llamaIndex介绍和RAG
  • dnSpy:设置断点
  • Docker 容器中运行昇腾(Ascend)AI 环境
  • Vitalik谈以太坊:ETH财库储备策略“有益且有价值”
  • SELinux 入门指南
  • vue+flask大模型写诗诗词推荐与可视化系统
  • 代理人工智能的隐藏威胁
  • 【渲染流水线】[几何阶段]-[图元装配]以UnityURP为例
  • Pandas 分层索引
  • AI 大模型企业级应用落地挑战与解决方案
  • 机器翻译:需要了解的数学基础详解
  • BPMN编辑器技术实现总结AI时代的工作流编辑器
  • Ubuntu系统忘记密码怎么办?
  • 【机器学习深度学习】模型选型:如何根据现有设备选择合适的训练模型