高性能web服务器详解

目录

一、Web服务的基础介绍

 1.1 Web服务介绍

1.1.1  Apache 经典的Web服务端 

1.1.1.1 Apache perfork 模型

1.1.1.2  Apache worker 模型

1.1.1.3 Apache event模型

1.2 Nginx-高性能的Web服务端

1.2.1服务端 I/O 流程

1.2.1.1 磁盘 I/O

1.2.1.2 网络 I/O

1.2.2 I/O 模型

1.2.2.1 I/O 模型相关概念

1.2.2.2  网络 I/O模型

1.2.2.2.1 阻塞型 I/O 模型(blocking IO)

1.2.2.2.2 非阻塞型 I/O 模型 (nonblocking IO)

1.2.2.2.3 多路复用 I/O 型(I/O multiplexing)

 1.2.2.2.4 信号驱动式 I/O 模型 (signal-driven IO)

1.2.2.2.5 异步 I/O 模型 (asynchronous IO)

 1.3 零拷贝介绍

1.3.1 什么是零拷贝

 1.3.2 零拷页相关技术

1.3.2.1 MMAP ( Memory Mapping )

1.3.2.2 SENDFILE

1.3.2.3 DMA 辅助的 SENDFILE

二、Nginx的架构和安装

2.1 Nginx的概述

2.1.1 Nginx的功能介绍

2.1.2 基础特性

2.1.3 Web 服务相关的功能

2.2 Nginx 架构和进程

2.2.1 Nginx 进程结构

2.2.2 Nginx 进程间通信

2.2.3 Nginx 启动和 HTTP 连接建立

2.2.4 HTTP处理过程

2.3 Nginx 模块介绍

2.4 Nginx安装

2.4.1 Nginx版本和安装方式

2.4.2 Nginx 编译安装

2.4.2.1 编译安装Nginx

2.4.2.2 正则表达式访问文件优先级:

 2.4.2.3  正则表达式访问目录优先级:

三、Nginx的核心配置

 3.1 nginx的平滑升级及版本回滚

3.2 启动脚本的编写

3.3 nginx配置中的root和alias

3.4 nginx的账户认证功能

3.5 nginx的自定义错误页面

3.6  nginx-自定义日志

3.7nginx中的文件检测

3.8 nginx中的长链接管理

3.9 nginx-下载服务器的设定及优化

四、Nginx的高级配置

4.1 nginx-数据压缩功能

4.2 内置变量的使用

4.2.1  nginx -- 内置变量

4.2.2 Nginx -- 自定义变量 

五、nginx 中rewrite模块功能

5.1 if指令

5.2 set 指令

5.3 break指令

5.4 return指令

​5.4.1 rewrite案例:域名永久与临时重定向(permanent和redirect)

5.4.2 break和last

5.4.2.1 rewrite-自动跳转https(全站加密)

5.4.2.2 访问不存在的文件,自动跳转到本地路径访问

5.5 nginx-盗链及防盗链

5.5.1 实现盗链 

5.5.2 防盗链

 六、Nginx的正反向代理功能机负载均衡

6.1 反向代理的配置参数

6.1.1 指定 location 实现反向代理

6.1.2 针对特定资源实现反向代理 

 6.1.3 nginx反向代理的缓存功能

 6.2 HTTP反向代理的负载均衡

6.2.1 七层:

6.2.2 四层: 

6.2.2.1 DNS 负载均衡(udp)

 6.2.2.2 MySQL的四层负载均衡

6.3  FastCGI

6.3.1 FastCGI配置指令

6.3.2 Nginx与php-fpm在同一服务器

6.3.2.1 源码编译php

6.3.2.2 Nginx和php整合

6.3.3 Nginx-php的缓存优化

6.3.3.1 Nginx-memcache高速缓存

七、 Nginx-二次开发版本

7.1 openresty

 7.2 编译安装openresty


一、Web服务的基础介绍

正常情况下单次web服务访问的流程简图:

 1.1 Web服务介绍

这里介绍的是  Apache    NGINX

1.1.1  Apache 经典的Web服务端 

        Apache 起初由美国的伊利诺伊大学香槟分校的国家超级计算机应用中心开发
目前经历了两大版本分别是 1.X 2.X ,其可以通过编译安装实现特定的功能

1.1.1.1 Apache perfork 模型
  • 预派生模式,有一个主控制进程,然后生成多个子进程,使用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.2 Nginx-高性能的Web服务端

        Nginx是由 1994 年毕业于俄罗斯国立莫斯科鲍曼科技大学的同学为俄罗斯 rambler.ru 公司开发的,开发 工作最早从2002 年开始,第一次公开发布时间是 2004 10 4 日,版本号是 0.1.0
2019 3 11 F5 NGINX 达成协议 ,F5 将收购 NGINX 的所有已发行股票,总价值约为 6.7 亿美元。 6.7亿美金约合 44.97 亿人民币 ,nginx 核心模块代码长度 198430 (包括空格、注释),所以一行代码约为 2.2万人民币
官网地址 www.nginx.org
        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 或者进行二次开发

NGINX的工作场景:

1.2.1服务端 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.1.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.1.2 网络 I/O
网络通信就是网络协议栈到用户空间进程的IO就是网络IO
网络 I/O 处理过程
  • 获取请求数据,客户端与服务器建立连接发出请求,服务器接受请求(1-3
  • 构建响应,当服务器接收完请求,并在用户空间处理客户端的请求,直到构建响应完成(4
  • 返回数据,服务器将已构建好的响应再通过内核空间的网络 I/O 发还给客户端(5-7
不论磁盘和网络 I/O
每次 I/O ,都要经由两个阶段:
  • 第一步:将数据从文件先加载至内核内存空间(缓冲区),等待数据准备完成,时间较长
  • 第二步:将数据从内核缓冲区复制到用户空间的进程的内存中,时间较短

1.2.2 I/O 模型

1.2.2.1 I/O 模型相关概念
        同步/ 异步:关注的是消息通信机制,即调用者在等待一件事情的处理结果时,被调用者是否提供完成状 态的通知。
  • 同步:synchronous,被调用者并不提供事件的处理结果相关的通知消息,需要调用者主动询问事
  • 情是否处理完成
  • 异步:asynchronous,被调用者通过状态、通知或回调机制主动通知调用者被调用者的运行状态

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

1.2.2.2  网络 I/O模型
阻塞型、非阻塞型、复用型、信号驱动型、异步
1.2.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.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.2.3 多路复用 I/O (I/O multiplexing)

上面的模型中 , 每一个文件描述符对应的 IO 是由一个线程监控和处理
        多路复用IO 指一个线程可以同时(实际是交替实现,即并发完成)监控和处理多个文件描述符对应各自 的IO ,即复用同一个线程
        一个线程之所以能实现同时处理多个IO, 是因为这个线程调用了内核中的 SELECT,POLL EPOLL 等系统调 用,从而实现多路复用IO
  • 优点:可以基于一个阻塞对象,同时在多个描述符上等待就绪,而不是使用多个线程(每个文件描述符一个线程),这样可以大大节省系统资源
  • 缺点:当连接数较少时效率相比多线程+阻塞 I/O 模型效率较低,可能延迟更大,因为单个连接处理 需要 2 次系统调用,占用时间会有增加

 IO多路复用适用如下场合:

  • 当客户端处理多个描述符时(一般是交互式输入和网络套接口),必须使用I/O复用
  • 当一个客户端同时处理多个套接字时,此情况可能的但很少出现
  • 当一个服务器既要处理监听套接字,又要处理已连接套接字,一般也要用到I/O复用
  • 当一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用
  • 当一个服务器要处理多个服务或多个协议,一般要使用I/O复用
 1.2.2.2.4 信号驱动式 I/O 模型 (signal-driven IO)

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

1.2.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.3 零拷贝介绍

1.3.1 什么是零拷贝

        零拷贝就是上述问题的一个解决方案,通过尽量避免拷贝操作来缓解 CPU 的压力。零拷贝并没有真正做 到“0” 拷贝,它更多是一种思想,很多的零拷贝技术都是基于这个思想去做的优化

 1.3.2 零拷页相关技术

1.3.2.1 MMAP ( Memory Mapping )

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

1.3.2.2 SENDFILE

1.3.2.3 DMA 辅助的 SENDFILE

二、Nginx的架构和安装

2.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.org
nginx 的其它的二次发行版:
  • Tengine:由淘宝网发起的Web服务器项目。它在Nginx的基础上,针对大访问量网站的需求,添加 了很多高级功能和特性。Tengine的性能和稳定性已经在大型的网站如淘宝网,天猫商城等得到了 很好的检验。它的最终目标是打造一个高效、稳定、安全、易用的Web平台。从201112月开始, Tengine成为一个开源项目官网: http://tengine.taobao.org/
  • OpenResty:基于 Nginx Lua 语言的高性能 Web 平台, 章亦春团队开发,官网:http://openr esty.org/cn/

2.1.1 Nginx的功能介绍

  • 静态的web资源服务器html,图片,jscsstxt等静态资源
  • http/https协议的反向代理
  • 结合FastCGI/uWSGI/SCGI等协议反向代理动态资源请求
  • tcp/udp协议的请求转发(反向代理)
  • imap4/pop3协议的反向代理

2.1.2 基础特性

  • 模块化设计,较好的扩展性
  • 高可靠性
  • 支持热部署:不停机更新配置文件,升级版本,更换日志文件
  • 低内存消耗:10000keep-alive连接模式下的非活动连接,仅需2.5M内存

2.1.3 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、工作进程在工作进程表中的索引和必要的文件描述符等信息。
        主进程与外界通过信号机制进行通信,当接收到需要处理的信号时,它通过管道向相关的工作进程发送 正确的指令,每个工作进程都有能力捕获管道中的可读事件,当管道中有可读事件的时候,工作进程就 会从管道中读取并解析指令,然后采取相应的执行动作,这样就完成了主进程与工作进程的交互。
        worker进程之间的通信原理基本上和主进程与 worker 进程之间的通信是一样的,只要 worker 进程之间能够 取得彼此的信息,建立管道即可通信,但是由于worker 进程之间是完全隔离的,因此一个进程想要知道另外一 个进程的状态信息, 就只能通过主进程来实现。
        为了实现worker 进程之间的交互, master 进程在生成 worker 进程之后,在 worker 进程表中进行遍历,将该新进程的PID 以及针对该进程建立的管道句柄传递给 worker 进程中的其他程,为 worker 进程之间的通信做准备,当worker 进程 1 worker 进程 2 发送指令的时候,首先在 master 进程给它的其他 worker 进程工作信息中找到2 的进程 PID ,然后将正确的指令写入向进程 2 的管道, worker 进程 2 捕获到管道中的事件后,解析指令并进行相关操作,这样就完成了worker 进程之间的通信。
        另worker 进程可以通过共享内存来通讯的,比如 upstream 中的 zone ,或者 limit_req limit_conn 中的zone等。操作系统提供了共享内存机制

2.2.3 Nginx 启动和 HTTP 连接建立

  • Nginx 启动时,Master 进程,加载配置文件
  • Master 进程,初始化监听的 socket
  • Master 进程,fork 出多个 Worker 进程
  • Worker 进程,竞争新的连接,获胜方通过三次握手,建立 Socket 连接,并处理请求

2.2.4 HTTP处理过程

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模块)等

2.4.2.1 编译安装Nginx

拖入软件压缩包到xshell

 

示例:

安装:
[root@nginx-node1 ~]# tar zxf nginx-1.24.0.tar.gz  ---解压

进入目录:
[root@nginx-node1 ~]# cd nginx-1.24.0/
[root@nginx-node1 nginx-1.24.0]# 

安装依赖性:
[root@nginx-node1 nginx-1.24.0]# dnf install gcc pcre-devel zlib-devel openssl-devel -y

[root@nginx-node1 nginx-1.24.0]# useradd -s /sbin/nologin -M nginx   ---- 添加使用用户

编译模块:
[root@nginx-node1 nginx-1.24.0]# ./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 \
 --add-module=/root/echo-nginx-module-0.63 \
 --add-module=/root/memc-nginx-module-0.20 \
 --add-module=/root/srcache-nginx-module-0.33 

过了之后会生成Makefile文件,make规则
make clean ---- 可以让之前做的编译模块还原

执行make install
[root@nginx-node1 nginx-1.24.0]# make && make install

把nginx软件的命令执行添加到环境变量中
[root@nginx-node1 ~]# vim ~/.bash_profile 

# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs
export PATH=$PATH:/usr/local/nginx/sbin    ---- 添加这个

[root@nginx-node1 ~]# source ~/.bash_profile 
[root@nginx-node1 ~]# du -sh /usr/local/nginx/sbin/nginx 

进到这个目录下开启nginx:
[root@nginx-node1 ~]# cd /usr/local/nginx/sbin/
[root@nginx-node1 sbin]# ls
nginx
[root@nginx-node1 sbin]# 
[root@nginx-node1 sbin]# ./nginx 
[root@nginx-node1 sbin]# 
查看进程和端口:
[root@nginx-node1 sbin]# ps aux | grep nginx
root       10018  0.0  0.0   9868  2056 ?        Ss   08:55   0:00 nginx: master process ./nginx
nginx      10019  0.0  0.1  14200  5128 ?        S    08:55   0:00 nginx: worker process
root       10021  0.0  0.0 221664  2304 pts/1    S+   08:56   0:00 grep --color=auto nginx
[root@nginx-node1 sbin]# netstat -antlupe | grep nginx
tcp        0      0 0.0.0.0:80        0.0.0.0:*        LISTEN      0      44612      10018/nginx: master 
[root@nginx-node1 sbin]# 

如何关闭nginx:
[root@nginx-node1 ~]# /usr/local/nginx/sbin/nginx -s stop

关闭debug模式:
[root@nginx-node1 nginx-1.24.0]# vim auto/cc/gcc

查看版本:
[root@nginx-node1 ~]# curl -I 172.25.254.200
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Thu, 15 Aug 2024 13:15:50 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Thu, 15 Aug 2024 12:54:39 GMT
Connection: keep-alive
ETag: "66bdfa8f-267"
Accept-Ranges: bytes


更改版本名:
[root@nginx-node1 ~]# cd nginx-1.24.0/
[root@nginx-node1 nginx-1.24.0]# cd src/
[root@nginx-node1 src]# cd core/
[root@nginx-node1 core]# ls
[root@nginx-node1 core]# vim nginx.h 

/*
 * Copyright (C) Igor Sysoev
 * Copyright (C) Nginx, Inc.
 */


#ifndef _NGINX_H_INCLUDED_
#define _NGINX_H_INCLUDED_


#define nginx_version      1024000
#define NGINX_VERSION      "1.0"
#define NGINX_VER          "timingding/" NGINX_VERSION   ---- 这里更改

#ifdef NGX_BUILD
#define NGINX_VER_BUILD    NGINX_VER " (" NGX_BUILD ")"
#else
#define NGINX_VER_BUILD    NGINX_VER
#endif

#define NGINX_VAR          "NGINX"
#define NGX_OLDPID_EXT     ".oldbin"


#endif /* _NGINX_H_INCLUDED_ */
2.4.2.2 正则表达式访问文件优先级:

 2.4.2.3  正则表达式访问目录优先级:

三、Nginx的核心配置

 3.1 nginx的平滑升级及版本回滚

输入网址nginx.org,然后找到新版本复制链接用wget命令下载
[root@nginx-node1 ~]# wget https://nginx.org/download/nginx-1.26.2.tar.gz

 拖入所需模块:

解压:
[root@nginx-node1 ~]# tar zxf echo-nginx-module-0.63.tar.gz 
[root@nginx-node1 ~]# tar zxf nginx-1.26.2.tar.gz 

进入目录,编译:
[root@nginx-node1 nginx-1.26.2]#  ./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 

这里直接make就可以了
[root@nginx-node1 nginx-1.26.2]# make

平滑升级:
对旧版本的命令进行备份:
旧版本:
[root@nginx-node1 sbin]# nginx -s stop
[root@nginx-node1 ~]# rm -rf /usr/local/nginx/
[root@nginx-node1 ~]# cd /root/nginx-1.24.0/
[root@nginx-node1 nginx-1.24.0]# make install

[root@nginx-node1 nginx-1.24.0]# cd /usr/local/nginx/
[root@nginx-node1 nginx]# ls
conf  html  logs  sbin
[root@nginx-node1 nginx]# cd sbin/
[root@nginx-node1 sbin]# ls
nginx
[root@nginx-node1 sbin]# nginx 

root@nginx-node1 objs]# cd /usr/local/nginx/sbin/
[root@nginx-node1 sbin]# ls
nginx
[root@nginx-node1 sbin]# cp nginx nginx.old
[root@nginx-node1 sbin]# 

[root@nginx-node1 sbin]# \cp -f /root/nginx-1.26.2/objs/nginx /usr/local/nginx/sbin/
[root@nginx-node1 sbin]# ps aux | grep nginx
root       14254  0.0  0.0   9868  1928 ?        Ss   09:54   0:00 nginx: master process nginx
nginx      14255  0.0  0.1  14200  5128 ?        S    09:54   0:00 nginx: worker process
root       14275  0.0  0.0 221664  2304 pts/2    S+   09:58   0:00 grep --color=auto nginx

使用kill -USR2创建新的worker进程,但不会监听端口:
[root@nginx-node1 sbin]# kill -USR2 14254
[root@nginx-node1 sbin]# ps aux | grep nginx
root       14254  0.0  0.0   9868  2184 ?        Ss   09:54   0:00 nginx: master process nginx
nginx      14255  0.0  0.1  14200  5128 ?        S    09:54   0:00 nginx: worker process
root       14276  0.0  0.1   9896  6656 ?        S    09:59   0:00 nginx: master process nginx
nginx      14277  0.0  0.1  14228  5136 ?        S    09:59   0:00 nginx: worker process
root       14279  0.0  0.0 221664  2304 pts/2    S+   09:59   0:00 grep --color=auto nginx
[root@nginx-node1 sbin]# 

把旧的worker进程回收:
[root@nginx-node1 sbin]# kill -WINCH 14254
[root@nginx-node1 sbin]# ps aux | grep nginx
root       14254  0.0  0.0   9868  2184 ?        Ss   09:54   0:00 nginx: master process nginx
root       14276  0.0  0.1   9896  6656 ?        S    09:59   0:00 nginx: master process nginx
nginx      14277  0.0  0.1  14228  5136 ?        S    09:59   0:00 nginx: worker process
root       14293  0.0  0.0 221664  2304 pts/2    S+   10:04   0:00 grep --color=auto nginx
[root@nginx-node1 sbin]# 

[root@nginx-node1 ~]# cd nginx-1.24.0/
[root@nginx-node1 nginx-1.24.0]# cd src/
[root@nginx-node1 src]# cd core/
[root@nginx-node1 core]# curl -I 172.25.254.200
HTTP/1.1 200 OK
Server: nginx/1.26.2               ----- 平滑升级成功
Date: Thu, 15 Aug 2024 14:10:49 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Thu, 15 Aug 2024 13:53:46 GMT
Connection: keep-alive
ETag: "66be086a-267"
Accept-Ranges: bytes


版本回滚:
把旧版本激活,新版本回收:

激活:
[root@nginx-node1 sbin]# kill -HUP 14254
[root@nginx-node1 sbin]# ps aux | grep nginx
root       14254  0.0  0.0   9868  2184 ?        Ss   09:54   0:00 nginx: master process nginx
root       14276  0.0  0.1   9896  6656 ?        S    09:59   0:00 nginx: master process nginx
nginx      14277  0.0  0.1  14228  5392 ?        S    09:59   0:00 nginx: worker process
nginx      14339  0.0  0.1  14200  5144 ?        S    10:12   0:00 nginx: worker process   --- 新的
root       14341  0.0  0.0 221664  2304 pts/2    S+   10:12   0:00 grep --color=auto nginx
[root@nginx-node1 sbin]# 

回收:
[root@nginx-node1 sbin]# kill -WINCH 14276
[root@nginx-node1 sbin]# ps aux | grep nginx
root       14254  0.0  0.0   9868  2184 ?        Ss   09:54   0:00 nginx: master process nginx
root       14276  0.0  0.1   9896  6656 ?        S    09:59   0:00 nginx: master process nginx
nginx      14339  0.0  0.1  14200  5144 ?        S    10:12   0:00 nginx: worker process
root       14343  0.0  0.0 221664  2304 pts/2    S+   10:14   0:00 grep --color=auto nginx
[root@nginx-node1 sbin]# 

回到旧版本了:
[root@nginx-node1 core]# curl -I 172.25.254.200
HTTP/1.1 200 OK
Server: timingding/1.0
Date: Thu, 15 Aug 2024 14:15:36 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Thu, 15 Aug 2024 13:53:46 GMT
Connection: keep-alive
ETag: "66be086a-267"
Accept-Ranges: bytes

把新的进程杀掉:
[root@nginx-node1 sbin]# cp nginx nginx.new
[root@nginx-node1 sbin]# \cp -f nginx.old nginx
[root@nginx-node1 sbin]# ls
nginx  nginx.new  nginx.old
[root@nginx-node1 sbin]# ps aux | grep nginx
root       14254  0.0  0.0   9868  2184 ?        Ss   09:54   0:00 nginx: master process nginx
root       14276  0.0  0.1   9896  6656 ?        S    09:59   0:00 nginx: master process nginx
nginx      14339  0.0  0.1  14200  5400 ?        S    10:12   0:00 nginx: worker process
root       14362  0.0  0.0 221664  2304 pts/2    S+   10:17   0:00 grep --color=auto nginx
[root@nginx-node1 sbin]# kill -9 14276
[root@nginx-node1 sbin]# ps aux | grep nginx
root       14254  0.0  0.0   9868  2184 ?        Ss   09:54   0:00 nginx: master process nginx
nginx      14339  0.0  0.1  14200  5400 ?        S    10:12   0:00 nginx: worker process
root       14364  0.0  0.0 221664  2304 pts/2    S+   10:18   0:00 grep --color=auto nginx
[root@nginx-node1 sbin]#

3.2 启动脚本的编写

[root@nginx-node1 sbin]# 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-node1 logs]# systemctl daemon-reload 
[root@nginx-node1 logs]# nginx -s stop
[root@nginx-node1 logs]# ps aux | grep nginx
root       14510  0.0  0.0 221664  2304 pts/2    S+   10:22   0:00 grep --color=auto nginx
[root@nginx-node1 logs]# systemctl enable --now nginx
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.
[root@nginx-node1 logs]# ps aux | grep nginx
root       14544  0.0  0.0   9864  2052 ?        Ss   10:23   0:00 nginx: master process /usr/local/nginx/sbin/nginx
nginx      14545  0.0  0.1  14196  4996 ?        S    10:23   0:00 nginx: worker process
root       14547  0.0  0.0 221664  2304 pts/2    S+   10:23   0:00 grep --color=auto nginx
[root@nginx-node1 logs]# 

3.3 nginx配置中的root和alias

新建一个web站点:
[root@nginx-node1 core]# vim /usr/local/nginx/conf/nginx.conf
events {
    worker_connections  1024;
    use epoll;   ---- 加上这个,运用epoll
}

    #gzip  on;
    include "/usr/local/nginx/conf.d/*.conf";  ------ 再加上子配置文件

创建子配置文件目录:
[root@nginx-node1 core]# mkdir /usr/local/nginx/conf.d -p
[root@nginx-node1 core]# vim /usr/local/nginx/conf.d/vhost.conf
server {
        listen 80;
        server_name www.timingding.org;
        root /data/web/html;
        index index.html;
}

[root@nginx-node1 core]# mkdir -p /data/web/html
[root@nginx-node1 core]# echo www.timingding.org > /data/web/html/index.html
[root@nginx-node1 core]# 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-node1 core]# nginx -s reload   ---- 刷新

访问172.25.254.200

去访问另外的路径,root和alias
[root@nginx-node1 core]# vim /usr/local/nginx/conf.d/vhost.conf
root:

server {
        listen 80;
        server_name www.timingding.org;
        root /data/web/html;
        index index.html;
        location /test1/ {
                root /data/web;
        }
}
[root@nginx-node1 core]# mkdir /data/web/test1 -p
[root@nginx-node1 core]# echo /data/web/test1 > /data/web/test1/index.html
[root@nginx-node1 core]# nginx -s reload   --- 刷新一下

访问172.25.254.100/test1

alias:
[root@nginx-node1 core]# vim /usr/local/nginx/conf.d/vhost.conf
server {
        listen 80;
        server_name www.timingding.org;
        root /data/web/html;
        index index.html;
        location /test1/ {
                root /data/web;
        }
        location /test2 {
                alias /data/web/test1;
        }
}

[root@nginx-node1 core]# nginx -s reload   --- 刷新一下

访问172.25.254.200/test2/

3.4 nginx的账户认证功能

创建账户路径:
[root@nginx-node1 ~]# htpasswd -cm /usr/local/nginx/.htpasswd admin
New password: 
Re-type new password: 
Adding password for user admin
[root@nginx-node1 ~]# htpasswd -m /usr/local/nginx/.htpasswd ding
New password: 
Re-type new password: 
Adding password for user ding
[root@nginx-node1 ~]# 
[root@nginx-node1 ~]# cat /usr/local/nginx/.htpasswd 
admin:$apr1$m/VIu7Dx$D.uCAJi2GsAR4MVbn2caY0
ding:$apr1$mJBsFc9R$BzRaDwhgw2E/qQ9sYqBPf1
[root@nginx-node1 ~]#

编写配置文件
[root@nginx-node1 ~]# vim /usr/local/nginx/conf.d/vhost.conf 

server {
        listen 80;
        server_name www.timingding.org;
        root /data/web/html;
        index index.html;
        location /ding {
                root /data/web;
                auth_basic "login passwd !!!";
                auth_basic_user_file "/usr/local/nginx/.htpasswd";
        }
}

创建文件目录:
[root@nginx-node1 ~]# mkdir /data/web/ding
[root@nginx-node1 ~]# echo ding > /data/web/ding/index.html
[root@nginx-node1 ~]# nginx -s reload

访问www.timingding.org/ding

3.5 nginx的自定义错误页面

创建文件目录:
[root@nginx ~]# mkdir /data/web/errorpage -p
[root@nginx ~]# echo error page > /data/web/erroepage/40x.html
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf 
server {
  listen 80;
  server_name www.timingding.org;
  root /data/web/html;
  index index.html;
  error_page 404 /40x.html;
  #error_log /var/log/timingding.org/error.log;
  #access_log /var/log/timingding.org/access.log;

  location /ding {
        root /data/web;
        auth_basic "login passwd";
        auth_basic_user_file "/usr/local/nginx/.htpasswd";
  }
  location = /40x.html {
        root /data/web/errorpage;
  }
}

[root@nginx ~]# systemctl restart nginx.service 

网页访问,输入一个错误的uri,172.25.254.100/ppd

3.6  nginx-自定义日志

[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf 
server {
  listen 80;
  server_name www.timingding.org;
  root /data/web/html;
  index index.html;
  error_page 404 /40x.html;
  error_log /var/log/timingding.org/error.log;      ----- 加这两行
  access_log /var/log/timingding.org/access.log;

  location /ding {
        root /data/web;
        auth_basic "login passwd";
        auth_basic_user_file "/usr/local/nginx/.htpasswd";
  }
  location /40x.html {
        root /data/web/errorpage;
  }
}

建立日志文件目录:
[root@nginx ~]# mkdir /var/log/timingding.org/ -p
[root@nginx ~]# systemctl restart nginx.service 
[root@nginx ~]# curl www.timingding.org
www.timingding.org

访问正确的域名:
[root@nginx ~]# curl www.timingding.org
www.timingding.org
[root@nginx ~]# cat /var/log/timingding.org/access.log 
172.25.254.100 - - [16/Aug/2024:08:07:07 -0400] "GET / HTTP/1.1" 200 19 "-" "curl/7.76.1"

访问错误的域名:
[root@nginx ~]# curl www.timingding.org/aaad
error page
[root@nginx ~]# cat /var/log/timingding.org/error.log 
2024/08/16 08:07:51 [error] 15474#0: *2 open() "/data/web/html/aaad" failed (2: No such file or directory), client: 172.25.254.100, server: www.timingding.org, request: "GET /aaad HTTP/1.1", host: "www.timingding.org"
[root@nginx ~]# 

3.7nginx中的文件检测

[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
  listen 80;
  server_name www.timingding.org;
  root /data/web/html;
  index index.html;
  error_page 404 /40x.html;
  error_log /var/log/timingding.org/error.log;
  access_log /var/log/timingding.org/access.log;
  try_files $uri $uri.html $uri/index.html /error/default.html;

  location /ding {
        root /data/web;
        auth_basic "login passwd";
        auth_basic_user_file "/usr/local/nginx/.htpasswd";
  }
  location /40x.html {
        root /data/web/errorpage;
  }
}

[root@nginx ~]# systemctl restart nginx.service
[root@nginx ~]# rm -rf /data/web/html/index.html 
[root@nginx ~]# rm -rf /data/web/html/error
[root@nginx ~]# curl www.timingding.org   ---- 现在检测到文件都没有,报500的错
<html>
<head><title>500 Internal Server Error</title></head>
<body>
<center><h1>500 Internal Server Error</h1></center>
<hr><center>nginx/1.24.0</center>
</body>
</html>

创建检测文件的目录:
[root@nginx ~]# mkdir /data/web/html/error
[root@nginx ~]# echo error default > /data/web/html/error/default.html
[root@nginx ~]# curl www.timingding.org
error default
[root@nginx ~]#

还原回来
[root@nginx ~]# echo www.timingding.org > /data/web/html/index.html

3.8 nginx中的长链接管理

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

    #keepalive_timeout  0;
    keepalive_timeout  65 60;  #----65长链接默认的保持时间,后面没有请求报文了,这里设置多少时间,时间到了就自动退出
    							    60设定了之后,客户会看到这个长链接保持的时间
    keepalive_requests 2;   #默认是100,请求过程中发出的长链接数量不能超过多少

安装长链接测试用的工具telnet
[root@nginx ~]# dnf install telnet -y

[root@nginx ~]# telnet www.timingding.org 80
Trying 172.25.254.100...
Connected to www.timingding.org.
Escape character is '^]'.
GET / HTTP/1.1          ----- 手动写入请求的报文
HOST: www.timingding.org   ----- 访问的域名,端口

HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Fri, 16 Aug 2024 12:45:43 GMT
Content-Type: text/html
Content-Length: 19
Last-Modified: Fri, 16 Aug 2024 12:45:12 GMT
Connection: keep-alive
ETag: "66bf49d8-13"
Accept-Ranges: bytes

www.timingding.org
这里设置了两次,请求两次之后就会退出。

企业中一般不能断开,要一直请求访问

3.9 nginx-下载服务器的设定及优化

创建下载文件的目录:
[root@nginx ~]# mkdir /data/web/download -p
[root@nginx ~]# dd if=/dev/zero of=/data/web/download/dingfile bs=1M count=100  ---- 做一个大小为100M的文件,并放到刚才创建的目录。创建的一个数据。
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.0394146 s, 2.7 GB/s
[root@nginx ~]# 

写一个location,访问路径
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf 
server {
  listen 80;
  server_name www.timingding.org;
  root /data/web/html;
  index index.html;
  error_page 404 /40x.html;
  error_log /var/log/timingding.org/error.log;
  access_log /var/log/timingding.org/access.log;
  try_files $uri $uri.html $uri/index.html /error/default.html;

  location /ding {
        root /data/web;
        auth_basic "login passwd";
        auth_basic_user_file "/usr/local/nginx/.htpasswd";
  }
  location /40x.html {
        root /data/web/errorpage;
  }
  location /download {
        root /data/web;
        autoindex on;   ----- 让文件可以长列表显示
        autoindex_localtime on;   -----on表示显示本机时间而非GMT(格林威治)时间,默为为off显示GMT时间
        autoindex_exact_size off;  ---- 计算文件确切大小(单位bytes),此为默认值,off只显示大概大小(单位kb、mb、gb)
        limit_rate 1024k; -------- 限速,默认不限速 }
  }
}

[root@nginx ~]# wget www.timingding.org/download/dingfile
--2024-08-16 09:11:02--  http://www.timingding.org/download/dingfile
Resolving www.timingding.org (www.timingding.org)... 172.25.254.100
Connecting to www.timingding.org (www.timingding.org)|172.25.254.100|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 104857600 (100M) [application/octet-stream]
Saving to: ‘dingfile.1’

dingfile.1                               26%[===================>                                                         ]  26.00M  1.04MB/s    eta 71s 

四、Nginx的高级配置

4.1 nginx-数据压缩功能

Nginx对文件的压缩功能是依赖于模块 ngx_http_gzip_module,默认是内置模块

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

    gzip  on;
    gzip_comp_level 4;
    gzip_min_length 1k;
    gzip_http_version 1.0;
    gzip_vary on;
    gzip_types text/plain application/javascript application/x-javascript text/css
application/xml text/javascript application/x-httpd-php image/gif image/png;

示例:
[root@nginx ~]# nginx -t    ----检测下语法是否有错
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx ~]# 
[root@nginx ~]# systemctl restart nginx.service 

测试:
[root@nginx ~]# echo hello nginx > /data/web/html/small.html   ----- 写入一个小于1k的文件
[root@nginx ~]# du -sh /usr/local/nginx/logs/access.log 
208K	/usr/local/nginx/logs/access.log
[root@nginx ~]# cat /usr/local/nginx/logs/access.log > /data/web/html/big.html  ----写入一个大于1k的文件
[root@nginx ~]# 
[root@nginx ~]# curl --head --compressed 172.25.254.100/small.html   ---- 小于1k不会被压缩
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Fri, 16 Aug 2024 13:32:39 GMT
Content-Type: text/html
Content-Length: 12
Last-Modified: Fri, 16 Aug 2024 13:29:43 GMT
Connection: keep-alive
ETag: "66bf5447-c"
Accept-Ranges: bytes
                   (--head只看响应报文的头部内容不看)
[root@nginx ~]# curl --head --compressed 172.25.254.100/big.html  ----- 大于1k会被压缩
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Fri, 16 Aug 2024 13:32:46 GMT
Content-Type: text/html
Last-Modified: Fri, 16 Aug 2024 13:31:01 GMT
Connection: keep-alive
Vary: Accept-Encoding
ETag: W/"66bf5495-33553"
Content-Encoding: gzip

[root@nginx ~]# 

这里压缩并不是给文件本身压缩,是文件在传输过程中被压缩。

4.2 内置变量的使用

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

4.2.1  nginx -- 内置变量

内置变量示例:
[root@nginx ~]# vim /usr/local/nginx/conf.d/vars.conf
server {
    listen 80;
    server_name var.timingding.org;
    root /data/web/html;
    index index.html;
    
    location /var {
        default_type /text/html;
        echo $remote_addr;     ---------- 存放了客户端的地址,注意是客户端的公网IP 
        echo $args;            ---------- 变量中存放了URL中的所有参数
        echo $is_args;         ---------- 如果有参数为? 否则为空
        echo $document_root;   ---------- 保存了针对当前资源的请求的系统根目录
        echo $document_uri;    ---------- 保存了当前请求中不包含参数的URI,注意是不包含请求的指令
        echo $host;            ---------- 存放了请求的host名称
        echo $remote_port;     ---------- 客户端请求Nginx服务器时随机打开的端口,这是每个客户端自己的端口
        echo $remote_user;     ---------- 已经经过Auth Basic Module验证的用户名
        echo $request_method;  ---------- 请求资源的方式,GET/PUT/DELETE等
        echo $request_filename; --------- 当前请求的资源文件的磁盘路径,由root或alias指令与URI请求生成的文件绝对路径
        echo $request_uri;      --------- 包含请求参数的原始URI,不包含主机名,相当于:$document_uri?$args
        echo $scheme;           --------- 请求的协议,例如:http,https,ftp等
        echo $server_protocol; ---------- 保存了客户端请求资源使用的协议的版本,例如:HTTP/1.0,HTTP/1.1,HTTP/2.0等
        echo $server_addr;     ---------- 保存了服务器的IP地址
        echo $server_name;     ---------- 虚拟主机的主机名
        echo $server_port;     ---------- 虚拟主机的端口号
        echo $http_user_agent; ---------- 客户端浏览器的详细信息
        echo $http_cookie;     ---------- 客户端的所有cookie信息
        echo $cookie_key2;     ---------- name为任意请求报文首部字部cookie的key名
    }
 
}

测试:
[root@nginx conf.d]# curl -b "key1=ding,key2=xiaoding" -u ding:123 var.timingding.org/var?name=DZ&&id=203621
172.25.254.100
name=DZ
?
/data/web/html
/var
var.timingding.org
48002
ding
GET
/data/web/html/var
/var?name=DZ
http
HTTP/1.1
172.25.254.100
var.timingding.org
80
curl/7.76.1
key1=ding,key2=xiaoding
xiaoding
[root@nginx conf.d]#

4.2.2 Nginx -- 自定义变量 

自定义变量示例:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vars.conf
server {
    listen 80;
    server_name var.timinglee.org;
    root /data/web/html;
    index index.html;

    location /var {
        default_type text/html;
        set $timingding xiaoding;
        echo $timingding;
    }

测试:
[root@nginx conf.d]# curl var.timingding.org/var
xiaoding
[root@nginx conf.d]# 

五、nginx 中rewrite模块功能

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

5.1 if指令

示例:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vars.conf
server {
    listen 80;
    server_name var.timingding.org;
    root /data/web/html;
    index index.html;

    location /test2 {
       if ( !-e $request_filename ){
          echo "$request_filename is not exist";
       }
        
    }
}

测试:
此时不存在test2的目录
[root@nginx conf.d]# curl var.timingding.org/test2/index.html
/data/web/html/test2/index.html is not exist
[root@nginx conf.d]# 

测试:
存在test2的目录,有的话就直接显示内容
创建一个:
[root@nginx conf.d]# mkdir -p /data/web/html/test2/
[root@nginx conf.d]# echo test2 > /data/web/html/test2/index.html
[root@nginx conf.d]# curl var.timingding.org/test2/index.html
test2
[root@nginx conf.d]# 

5.2 set 指令

[root@nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
server {
listen 80;
server_name www.timingding.org;
root /data/nginx/timingding.org/ding;
location /test2{
set $name ding;
echo $name;
}
}
测试:
[root@nginx ~]# curl lee.timingding.org/test2
ding

5.3 break指令

示例:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vars.conf
server {
    listen 80;
    server_name var.timingding.org;
    root /data/web/html;
    index index.html;

    location /test2 {
       if ( !-e $request_filename ){ 
          echo "$request_filename is not exist";
          #return 409;
       }
    }

   location /break {
        default_type text/html;
        set $name ding;
        echo $name;
        set $id 203621;
        echo $id;
   }

}
[root@nginx conf.d]# nginx -s reload
[root@nginx conf.d]# curl var.timingding.org/break
ding
203621
[root@nginx conf.d]# 

配合if再加上break:
location /break {
        default_type text/html;
        set $name ding;
        echo $name;
        if ( $http_user_agent = "curl/7.76.1"){
                break;
        }
        set $id 203621;
        echo $id;
   }
[root@nginx conf.d]# nginx -s reload
[root@nginx conf.d]# curl var.timingding.org/break
ding

[root@nginx conf.d]# 

指定下别的浏览器,break就不生效:
[root@nginx conf.d]# curl -A "fileding" var.timingding.org/break
ding
203621
[root@nginx conf.d]# 

5.4 return指令

根据上面的实验接着往下面加,示例:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vars.conf

location /return {
      default_type text/html;
        if ( !-e $request_filename ){
          echo "$request_filename is not exist";
          return 301 http://www.baidu.com;
        }
		echo "$request_filename is not exist";
   }
}

现在没有return的目录,会定向到www.baidu.com,并且会报301
测试:
[root@nginx conf.d]# curl -I var.timingding.org/return
HTTP/1.1 301 Moved Permanently
Server: xiaoding/1.1
Date: Sun, 18 Aug 2024 11:12:55 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Keep-Alive: timeout=60
Location: http://www.baidu.com

存在return目录
测试:
[root@nginx conf.d]# mkdir -p /data/web/html/return/
[root@nginx conf.d]# 
[root@nginx conf.d]# curl -I var.timingding.org/return
HTTP/1.1 200 OK
Server: xiaoding/1.1
Date: Sun, 18 Aug 2024 11:15:25 GMT
Content-Type: text/html
Connection: keep-alive
Keep-Alive: timeout=60
Vary: Accept-Encoding

[root@nginx conf.d]# 

5.4.1 rewrite案例:域名永久与临时重定向(permanent和redirect)

永久:

示例:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vars.conf
 location / {
        root /data/web/var;
        index index.html;
        rewrite / http://www.timingding.com permanent; --- 永久重定向   301    两个不能同时启用
        #rewrite / http://www.timingding.com redirext; --- 临时重定向   302
  }
  
[root@nginx conf.d]# mkdir -p /data/web/var
[root@nginx conf.d]# echo var page > /data/web/var/index.html
[root@nginx conf.d]# nginx -s reload

测试:
curl 不支持重定向
永久的301:
[root@nginx conf.d]# curl -I var.timingding.org
HTTP/1.1 301 Moved Permanently
Server: xiaoding/1.1
Date: Sun, 18 Aug 2024 11:40:30 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Keep-Alive: timeout=60
Location: http://www.timingding.com
[root@nginx conf.d]# 

临时:

换成临时的302:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vars.conf
 location / {
        root /data/web/var;
        index index.html;
        #rewrite / http://www.timingding.com permanent; 
        rewrite / http://www.timingding.com redirext; 
  }

5.4.2 break和last

示例:
创建目录:
[root@nginx conf.d]# mkdir /data/web/html/{test1,test2,break,last} -p
[root@nginx conf.d]# echo test1 > /data/web/html/test1/index.html
[root@nginx conf.d]# echo test2 > /data/web/html/test2/index.html
[root@nginx conf.d]# echo break > /data/web/html/break/index.html
[root@nginx conf.d]# echo last > /data/web/html/last/index.html

[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vars.conf
server {
    listen 80;
    server_name var.timingding.org;
    root /data/web/html;
    index index.html;

    location /break {
        rewrite ^/break/(.*) /test1/$1;
        rewrite ^/test1/(.*) /test2/$1;
    }

    location /last {
        rewrite ^/last/(.*) /test1/$1;
        rewrite ^/test1/(.*) /test2/$1;
    }

    location /test1 {
        default_type text/html;
        return 203 "xiaoding hahahahaha";
    }

    location /test2 {
        root /data/web/html;
    }
}

访问:
[root@nginx conf.d]# curl var.timingding.org/break/
test2
[root@nginx conf.d]# curl var.timingding.org/last/
test2
[root@nginx conf.d]# curl var.timingding.org/test1/
xiaoding hahahahaha
[root@nginx conf.d]# curl var.timingding.org/test2/
test2

break和last效果示例:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vars.conf
server {
    listen 80;
    server_name var.timingding.org;
    root /data/web/html;
    index index.html;

    location /break {
        root /data/web/html;
        rewrite ^/break/(.*) /test1/$1 break;   ----- 加上break,执行到这里就不访问下面的了,看的是test1里面的内容
        rewrite ^/test1/(.*) /test2/$1;
    }

    location /last {
    	root /data/web/html;
        rewrite ^/last/(.*) /test1/$1 last;
        rewrite ^/test1/(.*) /test2/$1;
    }

    location /test1 {
        default_type text/html;
        return 203 "xiaoding hahahahaha";
    }

    location /test2 {
        root /data/web/html;
    }
}

测试
[root@nginx ~]# nginx -s reload
[root@nginx ~]# curl var.timingding.org/break/index.html #访问break时,会终止,但不会跳出当前的location
test1
[root@nginx ~]# 
[root@nginx~]# curl var.timingding.org/last/index.html #访问last时,也会终止,但是会跳出当前的location,继续寻找路径
xiaoding hahahahaha
[root@nginx ~]#

5.4.2.1 rewrite-自动跳转https(全站加密)

制作证书:
[root@nginx ~]# cd /usr/local/nginx/certs/
[root@nginx certs]#openssl req  -newkey  rsa:2048 -nodes -sha256 -keyout /usr/local/nginx/certs/timingding.org.key 
-x509  -days 365 -out /usr/local/nginx/certs/timingding.org.crt

[root@nginx certs]# ls
timingding.org.crt  timingding.org.key
[root@nginx certs]# 

写配置:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vhost.conf
server {
   listen 80;
   listen 443 ssl;
   server_name www.timingding.org;
   root /data/web/html;
   index index.html;
   ssl_certificate /usr/local/nginx/certs/timingding.org.crt;
   ssl_certificate_key /usr/local/nginx/certs/timingding.org.key;
   ssl_session_cache    shared:SSL:1m;
   ssl_session_timeout  5m;

   location / {
        if ( $scheme = http ) {
                rewrite /(.*) https://$host/$1 redirect;
        }
}

[root@nginx conf.d]# echo www.timingding.org > /data/web/html/index.html 

网页访问www.timingding.org

5.4.2.2 访问不存在的文件,自动跳转到本地路径访问

示例:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vhost.conf
server {
   listen 80;
   listen 443 ssl;
   server_name www.timingding.org;
   root /data/web/html;
   index index.html;
   ssl_certificate /usr/local/nginx/certs/timingding.org.crt;
   ssl_certificate_key /usr/local/nginx/certs/timingding.org.key;
   ssl_session_cache    shared:SSL:1m;
   ssl_session_timeout  5m;

   location / {
        if ( $scheme = http ) {
                rewrite /(.*) https://$host/$1 redirect;
        }

        if ( !-e $request_filename ){
                rewrite /(.*) https://$host/index.html redirect;
        }
   }
}

此时访问www.timingding.org后面跟上不存在的文件路径,自动跳转到本地路径,访问内容。
例如:www.timingding.org/a/b/a/

5.5 nginx-盗链及防盗链

        防盗链基于客户端携带的referer 实现, referer 是记录打开一个页面之前记录是从哪个页面跳转过来的标 记信息,如果别人只链接了自己网站图片或某个单独的资源,而不是打开了网站的整个页面,这就是盗链,referer 就是之前的那个网站域名,正常的 referer 信息有以下几种:
none : -------  请求报文首部没有 referer 首部,
                      比如用户直接在浏览器输入域名访问web网站,就没有 referer 信息。
blocked: -------  请求报文有 referer 首部,但无有效值,比如为空。
server_names :-------  referer 首部中包含本主机名及即 nginx 监听的 server_name
arbitrary_string :---------  自定义指定字符串,但可使用 * 作通配符。示例 : *.timingding.org
                                        www.timingding.*
regular expression : ---------  被指定的正则表达式模式匹配到的字符串 , 要使用 ~ 开头
                                              例如: ~.*\.timingding\.com  
示例:
[root@nginx conf.d]# mkdir -p /data/web/html/images
拖入你喜欢的照片
[root@nginx conf.d]# cd /data/web/html/images/
[root@nginx images]# ls
zrn.jpg

网页访问172.25.254.100/images/zrn.jpg

5.5.1 实现盗链 

另一台主机托入盗链:
[root@nginx-node1 ~]# dnf install httpd -y
[root@nginx-node1 ~]# cd /var/www/html/
[root@nginx-node1 html]# ls
daolian.png
[root@nginx-node1 html]# mv daolian.png /var/www/html/index.html
[root@nginx-node1 html]# ls
index.html
[root@nginx-node1 html]# cat index.html
<html>

  <head>
    <meta http-equiv=Content-Type content="text/html;charset=utf-8">
    <title>盗链</title>
</head>

  <body>
    <img src="http://www.timingding.org/images/zrn.jpg" >
    <h1 style="color:red">章若楠最乖</h1>
    <p><a href=http://www.timingding.org>狂戳若楠</a>见到若楠</p>
  </body>

</html>

[root@nginx-node1 html]# systemctl start httpd

去网页访问172.25.254.10

 

5.5.2 防盗链

示例:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vhost.conf 
server {
   listen 80;
   listen 443 ssl;
   server_name www.timingding.org;
   root /data/web/html;
   index index.html;
   ssl_certificate /usr/local/nginx/certs/timingding.org.crt;
   ssl_certificate_key /usr/local/nginx/certs/timingding.org.key;
   ssl_session_cache    shared:SSL:1m;
   ssl_session_timeout  5m;

   location /images {
        valid_referers none blocked server_names *.timingding.org ~/.baidu/.;
        if ( $invalid_referer ){
                return 404;
        }
   }
}

此时访问172.25.254.10就访问不到图片了

让别人访问过来看到的不是想要的图片:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vhost.conf 
server {
   listen 80;
   listen 443 ssl;
   server_name www.timingding.org;
   root /data/web/html;
   index index.html;
   ssl_certificate /usr/local/nginx/certs/timingding.org.crt;
   ssl_certificate_key /usr/local/nginx/certs/timingding.org.key;
   ssl_session_cache    shared:SSL:1m;
   ssl_session_timeout  5m;

   #location / {
    #   valid_referers none blocked server_names *.timingding.org ~/.baidu/.;
     #  if ( $invalid_referer ){
      #         return 404;
       #}
   #}

   location /images {
       valid_referers none blocked server_names *.timingding.org ~/.baidu/.;
       if ( $invalid_referer ){
               rewrite ^/ http://www.timingding.org/tupi.jpg;
       }
   }
}

 六、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 反向代理的配置参数

proxy_pass;   ------  用来设置将客户端请求转发给的后端服务器的主机
                               可以是主机名(将转发至后端服务做为主机头首部)、IP 地址:端口的方式
                      也可以代理到预先设置的主机群组,需要模块ngx_http_upstream_module支持

proxy_hide_header field; -------  用于 nginx 作为反向代理的时候
                                                  在返回给客户端http响应时
                                                  隐藏后端服务器相应头部的信息
                                                  可以设置在http,server或location块
proxy_pass_header field; ----------  透传
默认 nginx 在响应报文中不传递后端服务器的首部字段 Date, Server, X-Pad, X-Accel 等参数
如果要传递的话则要使用 proxy_pass_header field 声明将后端服务器返回的值传递给客户端
field 首部字段大小不敏感
proxy_pass_request_body on | off;
是否向后端服务器发送HTTP 实体部分 , 可以设置在 http,server location 块,默认即为开启
proxy_pass_request_headers on | off;
是否将客户端的请求头部转发给后端服务器,可以设置在 http,server location 块,默认即为开启
proxy_set_header;
        可更改或添加客户端的请求头部信息内容并转发至后端服务器,比如在后端服务器想要获取客户端的真实IP 的 时候,就要更改每一个报文的头部
proxy_connect_timeout time;
配置 nginx 服务器与后端服务器尝试建立连接的超时时间,默认为 60
proxy_read_timeout time;
配置 nginx 服务器向后端服务器或服务器组发起 read 请求后,等待的超时时间,默认 60s
proxy_send_timeout time;
配置 nginx 项后端服务器或服务器组发起 write 请求后,等待的超时 时间,默认 60s
proxy_http_version 1.0;
用于设置 nginx 提供代理服务的 HTTP 协议的版本,默认 http 1.0
proxy_ignore_client_abort off;
        当客户端网络中断请求时,nginx 服务器中断其对后端服务器的请求。即如果此项设置为 on 开启,则服务器、 会忽略客户端中断并一直等着代理服务执行返回,如果设置为off ,则客户端中断后 Nginx 也会中断客户端请求并立即记录499 日志,默认为 off

6.1.1 指定 location 实现反向代理

[root@nginx-node1 ~]# dnf install php -y
[root@nginx-node1 ~]# systemctl restart httpd
[root@nginx-node1 ~]# vim /var/www/html/index.php
<?php   
        phpinfo();
?>

[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf 
server {
   listen 80;
   server_name www.timingding.org;

   location ~ \.php$ {
        proxy_pass http://172.25.254.10:80;
   }

   location /static {
        proxy_pass http://172.25.254.20:8080;
   }
}
[root@nginx ~]# nginx -s reload

网页访问www.timingding.org/index.php = 172.25.254.10

 

 访问www.timingding.org/static/ 

6.1.2 针对特定资源实现反向代理 

示例:
两台主机:
172.25.254.10:
[root@nginx-node1 ~]# echo 172.25.254.10 > /var/www/html/index.html
172.25.254.20:
[root@nginx-node2 ~]# echo 172.25.254.20 > /var/www/html/index.html
[root@nginx-node2 ~]# systemctl restart httpd
[root@nginx-node2 ~]# mkdir -p /var/www/html/static
[root@nginx-node2 ~]# echo static 172.25.254.20 > /var/www/html/static/index.html

172.25.254.100:
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf 
server {
   listen 80;
   server_name www.timingding.org;

   location / {
        proxy_pass http://172.25.254.10:80;
   }

   location /static {
        proxy_pass http://172.25.254.20:8080;
   }
}

访问: www.timingding.org

 6.1.3 nginx反向代理的缓存功能

作压测:

示例:
[root@nginx-node1 ~]# ab -n1000 -c100 http://www.timingding.org/static/index.html
This is ApacheBench, Version 2.3 <$Revision: 1903618 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking www.timingding.org (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        Apache/2.4.57
Server Hostname:        www.timingding.org
Server Port:            80

Document Path:          /static/index.html
Document Length:        196 bytes

Concurrency Level:      100
Time taken for tests:   0.062 seconds
Complete requests:      1000
Failed requests:        0
Non-2xx responses:      1000
Total transferred:      394000 bytes
HTML transferred:       196000 bytes
Requests per second:    16169.72 [#/sec] (mean)
Time per request:       6.184 [ms] (mean)
Time per request:       0.062 [ms] (mean, across all concurrent requests)
Transfer rate:          6221.55 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.3      0       1
Processing:     1    6   2.0      6      13
Waiting:        1    5   2.0      6      13
Total:          2    6   1.7      6      13

Percentage of the requests served within a certain time (ms)
  50%      6
  66%      7
  75%      7
  80%      7
  90%      8
  95%      8
  98%      9
  99%     11
 100%     13 (longest request)
[root@nginx-node1 ~]# 

做缓存:

作缓存:
[root@nginx ~]# vim /usr/local/nginx/conf/nginx.conf
    #gzip  on;
    proxy_cache_path /usr/local/nginx/proxy_cache levels=1:2:2 keys_zone=proxycache:20m
inactive=120s max_size=1g;


server {
   listen 80;
   server_name www.timingding.org;

   location ~ \.php$ {
        proxy_pass http://172.25.254.10:80;
   }

   location /static {
        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;
   }
}
[root@nginx ~]# nginx -s reload

[root@nginx-node1 ~]# ab -n1000 -c100 http://www.timingding.org/static/index.html

缓存的路径,缓存到proxy_cache里面:
[root@nginx nginx]# tree proxy_cache/
proxy_cache/
└── e
    └── 50
        └── 99
            └── 319432ef3663735a9d3cb4e0c1d9950e

3 directories, 1 file
[root@nginx nginx]# 

 6.2 HTTP反向代理的负载均衡

6.2.1 七层:

配置nginx反向代理
示例:
[root@nginx nginx]# vim /usr/local/nginx/conf.d/vhost.conf 
upstream webcluster {
        server 172.25.254.10:80 fail_timeout=15s max_fails=3;
        server 172.25.254.20:8080 fail_timeout=15s max_fails=3;
        server 172.25.254.100:80 backup;
}


server {
   listen 80;
   server_name www.timingding.org;
   
   location / {
        proxy_pass http://webcluster;
   }
}

[root@nginx nginx]# nginx -s reload

默认是轮询

写算法:
[root@nginx nginx]# vim /usr/local/nginx/conf.d/vhost.conf
upstream webcluster {
        ip_hash;   ---- 算法,让同一个IP请求,访问到同一个主机上面
        server 172.25.254.10:80 fail_timeout=15s max_fails=3;
        server 172.25.254.20:8080 fail_timeout=15s max_fails=3;
        #server 172.25.254.100:80 backup;   --- hash写完不能加backup  防止调度到backup上面去
}


server {
   listen 80;
   server_name www.timingding.org;

   location / {
        proxy_pass http://webcluster;
   }
}
[root@nginx nginx]# nginx -s reload

访问的都是同一个主机

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

upstream webcluster {
        #ip_hash;
        hash $request_uri consistent;   ---- 动态算法,hash一致性
        server 172.25.254.10:80 fail_timeout=15s max_fails=3;
        server 172.25.254.20:8080 fail_timeout=15s max_fails=3;
        #server 172.25.254.100:80 backup;
}


server {
   listen 80;
   server_name www.timingding.org;

   location / {
        proxy_pass http://webcluster;
   }
}
[root@nginx nginx]# nginx -s reload

uri没变,一直访问的是20

172.25.254.10:
[root@nginx-node1 ~]# mkdir -p /var/www/html/static
[root@nginx-node1 ~]# echo 172.25.254.10 static > /var/www/html/static/index.html

改uri,这就是对uri进行hash,一致的

对cookie进行hash
[root@nginx nginx]# vim /usr/local/nginx/conf.d/vhost.conf
upstream webcluster {
        #ip_hash;
        #hash $request_uri consistent;
        hash $cookie_ding;      ------- 对cookie进行hash
        server 172.25.254.10:80 fail_timeout=15s max_fails=3;
        server 172.25.254.20:8080 fail_timeout=15s max_fails=3;
        #server 172.25.254.100:80 backup;
}


server {
   listen 80;
   server_name www.timingding.org;

   location / {
        proxy_pass http://webcluster;
   }
}

[root@nginx nginx]# nginx -s reload

对cookie值进行hash,ding=1 or ding=2 对后面的值进行hash

6.2.2 四层: 

 注意:tcp的负载均衡要写在http语句块外面

tcp 负载均衡配置参数:
stream { #定义stream相关的服务;
Context:main
upstream backend { #定义后端服务器
hash $remote_addr consistent; #定义调度算法
server backend1.example.com:12345 weight=5; #定义具体server
server 127.0.0.1:12345 max_fails=3 fail_timeout=30s;
server unix:/tmp/backend3;
}
upstream dns { #定义后端服务器
server 10.0.0.1:53; #定义具体server
server dns.example.com:53;
}
server { #定义server
listen 12345; #监听IP:PORT
proxy_connect_timeout 1s; #连接超时时间
proxy_timeout 3s; #转发超时时间
proxy_pass backend; #转发到具体服务器组
}
server {
listen 127.0.0.1:53 udp reuseport;
proxy_timeout 20s;
proxy_pass dns;
}
server {
listen [::1]:12345;
proxy_pass unix:/tmp/stream.socket;
}
}
6.2.2.1 DNS 负载均衡(udp)
示例:
172.25.254.10和20 安装bind
配置DNS
[root@nginx-node1 ~]# dnf install bind -y
[root@nginx-node2 ~]# dnf install bind -y

[root@nginx-node1 ~]# vim /etc/named.conf

//      listen-on port 53 { 127.0.0.1; };
//      listen-on-v6 port 53 { ::1; };
        directory       "/var/named";
        dump-file       "/var/named/data/cache_dump.db";
        statistics-file "/var/named/data/named_stats.txt";
        memstatistics-file "/var/named/data/named_mem_stats.txt";
        secroots-file   "/var/named/data/named.secroots";
        recursing-file  "/var/named/data/named.recursing";
//      allow-query     { localhost; };


     dnssec-validation no;  --- 改为no

[root@nginx-node1 ~]# vim /etc/named.rfc1912.zones
zone "timingding.org" IN {
        type master;
        file "timingding.org.zone";
        allow-update { none; };
};

[root@nginx-node1 ~]# cd /var/named/
[root@nginx-node1 named]# 
[root@nginx-node1 named]# cp named.localhost timingding.org.zone -p
[root@nginx-node1 named]# vim timingding.org.zone 
$TTL 1D
@       IN SOA  ns.timingding.org.   root.timingding.org. (
                                        0       ; serial
                                        1D      ; refresh
                                        1H      ; retry
                                        1W      ; expire
                                        3H )    ; minimum
        NS      ns.timingding.org.
ns      A       172.25.254.10
www     A       172.25.254.10

[root@nginx-node1 named]# systemctl start named
[root@nginx-node1 named]# systemctl start named
[root@nginx-node1 named]# dig www.timingding.org @172.25.254.10

; <<>> DiG 9.16.23-RH <<>> www.timingding.org @172.25.254.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27004
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 783e7ecaf1c29da10100000066c22dd4285bd72eb63c17c1 (good)
;; QUESTION SECTION:
;www.timingding.org.		IN	A

;; ANSWER SECTION:
www.timingding.org.	86400	IN	A	172.25.254.10

;; Query time: 0 msec
;; SERVER: 172.25.254.10#53(172.25.254.10)
;; WHEN: Sun Aug 18 13:22:28 EDT 2024
;; MSG SIZE  rcvd: 91

[root@nginx-node1 named]# 

直接传到172.25.254,20上面
[root@nginx-node1 named]# scp -p /etc/named.{conf,rfc1912.zones} root@172.25.254.20:/etc/
The authenticity of host '172.25.254.20 (172.25.254.20)' can't be established.
ED25519 key fingerprint is SHA256:JAc5p6OZrNZsG8UQHYDL8RDEOeKmzy1IWQlXlmvsuSw.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '172.25.254.20' (ED25519) to the list of known hosts.
root@172.25.254.20's password: 
named.conf                                                                                                                 100% 1727     3.0MB/s   00:00    
named.rfc1912.zones                                                                                                        100% 1129     2.8MB/s   00:00    
[root@nginx-node1 named]# 
[root@nginx-node1 named]# scp -p /var/named/timingding.org.zone \ root@172.25.254.20:/var/named/timingding.org.zone

root@172.25.254.20's password: 
timingding.org.zone                                                                                                        100%  210   394.6KB/s   00:00    
[root@nginx-node1 named]# 


[root@nginx-node2 ~]# vim /var/named/timingding.org.zone 
$TTL 1D
@       IN SOA  ns.timingding.org.   root.timingding.org. (
                                        0       ; serial
                                        1D      ; refresh
                                        1H      ; retry
                                        1W      ; expire
                                        3H )    ; minimum
        NS      ns.timingding.org.
ns      A       172.25.254.20
www     A       172.25.254.20

[root@nginx-node2 named]# chgrp named timingding.org.zone 
[root@nginx-node2 ~]# systemctl start named
[root@nginx-node2 named]# dig www.timingding.org @172.25.254.20

; <<>> DiG 9.16.23-RH <<>> www.timingding.org @172.25.254.20
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48200
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 3da0f57e7816a0bb0100000066c22fd3ea997c832e0fcd37 (good)
;; QUESTION SECTION:
;www.timingding.org.		IN	A

;; ANSWER SECTION:
www.timingding.org.	86400	IN	A	172.25.254.20

;; Query time: 0 msec
;; SERVER: 172.25.254.20#53(172.25.254.20)
;; WHEN: Sun Aug 18 13:30:59 EDT 2024
;; MSG SIZE  rcvd: 91

[root@nginx-node2 named]# 

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

include "/usr/local/nginx/tcpconf.d/*.conf";   ---- 要写在http外面

[root@nginx nginx]# vim /usr/local/nginx/conf.d/dns.conf 
stream {
        upstream dns {
           server 172.25.254.10:53 fail_timeout=15s max_fails=3;
           server 172.25.254.20:53 fail_timeout=15s max_fails=3;
        }


        server {
           listen 53 udp reuseport;
           proxy_timeout 20s;
           proxy_pass dns;
        }
}

创建目录:
[root@nginx nginx]# mkdir -p /usr/local/nginx/tcpconf.d
[root@nginx nginx]# cd /usr/local/nginx/conf.d
[root@nginx conf.d]# 
[root@nginx conf.d]# mv dns.conf /usr/local/nginx/tcpconf.d/

[root@nginx tcpconf.d]# nginx -s reload
[root@nginx tcpconf.d]# netstat -antlupe | grep 53
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN      0          25391      981/cupsd           
tcp6       0      0 ::1:631                 :::*                    LISTEN      0          25390      981/cupsd           
udp        0      0 0.0.0.0:5353            0.0.0.0:*                           70         23648      851/avahi-daemon: r 
udp        0      0 0.0.0.0:53              0.0.0.0:*                           0          86748      3832/nginx: master  
udp6       0      0 :::5353                 :::*                                70         23649      851/avahi-daemon: r 
[root@nginx tcpconf.d]# 

此时就能解析到172.25.254.10和20了
[root@nginx tcpconf.d]# dig www.timingding.org @172.25.254.100

; <<>> DiG 9.16.23-RH <<>> www.timingding.org @172.25.254.100
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15189
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 8c6fc39065ed27c50100000066c23599d6924761de822212 (good)
;; QUESTION SECTION:
;www.timingding.org.		IN	A

;; ANSWER SECTION:
www.timingding.org.	86400	IN	A	172.25.254.10

;; Query time: 1 msec
;; SERVER: 172.25.254.100#53(172.25.254.100)
;; WHEN: Sun Aug 18 13:55:37 EDT 2024
;; MSG SIZE  rcvd: 91

[root@nginx tcpconf.d]# dig www.timingding.org @172.25.254.100

; <<>> DiG 9.16.23-RH <<>> www.timingding.org @172.25.254.100
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31342
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 33a6b4e9a5b11f920100000066c235be1ce27ff22fb787ad (good)
;; QUESTION SECTION:
;www.timingding.org.		IN	A

;; ANSWER SECTION:
www.timingding.org.	86400	IN	A	172.25.254.20

;; Query time: 1 msec
;; SERVER: 172.25.254.100#53(172.25.254.100)
;; WHEN: Sun Aug 18 13:56:14 EDT 2024
;; MSG SIZE  rcvd: 91

[root@nginx tcpconf.d]# 

 6.2.2.2 MySQL的四层负载均衡
安装数据库:
[root@nginx-node1 named]# dnf install mariadb-server -y
[root@nginx-node2 named]# dnf install mariadb-server -y

[root@nginx-node1 named]# vim /etc/my.cnf.d/mariadb-server.cnf 
[root@nginx-node2 named]# vim /etc/my.cnf.d/mariadb-server.cnf 

[mysqld]
server-id=20(10)    ---- 两台机子都加个ID,用于区分
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
log-error=/var/log/mariadb/mariadb.log
pid-file=/run/mariadb/mariadb.pid

[root@nginx-node1 named]# systemctl start mariadb
[root@nginx-node2 named]# systemctl start mariadb

[root@nginx-node1 named]# mysql
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 3
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)]> CREATE USER ding@'%' identified by 'ding';
Query OK, 0 rows affected (0.001 sec)

MariaDB [(none)]> GRANT ALL ON *.* to ding@'%';
Query OK, 0 rows affected (0.001 sec)

MariaDB [(none)]> 

172.25.254.100主机上面:
[root@nginx ~]#vim /usr/local/nginx/tcpconf.d/dns.conf

stream {
        upstream dns {
           server 172.25.254.10:53 fail_timeout=15s max_fails=3;
           server 172.25.254.20:53 fail_timeout=15s max_fails=3;
        }

        upstream mysql {
          server 172.25.254.10:3306 fail_timeout=15s max_fails=3;
          server 172.25.254.20:3306 fail_timeout=15s max_fails=3;
        }

        server {
          listen 3306;
          proxy_timeout 60;
          proxy_pass mysql;
        }

        server {
           listen 53 udp reuseport;
           proxy_timeout 20s;
           proxy_pass dns;
        }
}
[root@nginx tcpconf.d]# nginx -s reload
[root@nginx tcpconf.d]# netstat -antlupe | grep 3306
tcp        0      0 0.0.0.0:3306       0.0.0.0:*    LISTEN      0      88742      3832/nginx: master  

[root@nginx tcpconf.d]# dnf install mariadb -y

[root@nginx tcpconf.d]# mysql -u ding -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 |
+-------------+
|          10 |
+-------------+
1 row in set (0.001 sec)

MariaDB [(none)]> 

再连一次:
[root@nginx tcpconf.d]# mysql -u ding -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)]> 

 

6.3  FastCGI

CGI 的由来:
        最早的Web 服务器只能简单地响应浏览器发来的 HTTP 请求,并将存储在服务器上的 HTML 文件返回给浏 览器,也就是静态html 文件,但是后期随着网站功能增多网站开发也越来越复杂,以至于出现动态技 术,比如像php(1995 ) java(1995) python(1991) 语言开发的网站,但是 nginx/apache 服务器并不 能直接运行 php java 这样的文件, apache 实现的方式是打补丁,但是 nginx 缺通过与第三方基于协议实 现,即通过某种特定协议将客户端请求转发给第三方服务处理,第三方服务器会新建新的进程处理用户 的请求,处理完成后返回数据给Nginx 并回收进程,最后 nginx 在返回给客户端,那这个约定就是通用网 关接口(common gateway interface ,简称 CGI) CGI (协议) 是 web 服务器和外部应用程序之间的接口标准,是cgi 程序和 web 服务器之间传递信息的标准化接口。

为什么会有 FastCGI
        CGI协议虽然解决了语言解析器和 Web Server 之间通讯的问题,但是它的效率很低,因为 Web Server 每收到一个请求都会创建一个CGI 进程, PHP 解析器都会解析 php.ini 文件,初始化环境,请求结束的时候再关闭进程,对于每一个创建的CGI 进程都会执行这些操作,所以效率很低,而 FastCGI 是用来提高 CGI 性能的,FastCGI 每次处理完请求之后不会关闭掉进程,而是保留这个进程,使这个进程可以处理多个请 求。这样的话每个请求都不用再重新创建一个进程了,大大提升了处理效率。
什么是 PHP-FPM

PHP-FPM(FastCGI Process Manager

  • FastCGI进程管理器)是一个实现了Fastcgi的程序,并且提供进程管理的功能。
  • 进程包括master进程和worker进程。master进程只有一个,负责监听端口,接受来自web server 的请求
  • worker进程一般会有多个,每个进程中会嵌入一个PHP解析器,进行PHP代码的处理。

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 name

6.3.2 Nginxphp-fpm在同一服务器

6.3.2.1 源码编译php
源码编译Nginx:
安装Nginx编译所需的依赖性:
[root@nginx nginx-1.26.1]# dnf install gcc pcre-devel zlib-devel openssl-devel -y
[root@nginx ~]# cd nginx-1.26.1/
[root@nginx nginx-1.26.1]# useradd -s /sbin/nologin -M nginx

[root@nginx nginx-1.26.1]# ./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  --add-module=/root/echo-nginx-module-0.63  --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 auto/cc/gcc
# debug
#CFLAGS="$CFLAGS -g"

[root@nginx ~]# vim ~/.bash_profile
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs
export PATH=$PATH:/usr/local/nginx/sbin    ---- 添加这个

[root@nginx ~]# source ~/.bash_profile
[root@nginx ~]# cd /usr/local/nginx/sbin/
[root@nginx sbin]# ./nginx

源码编译php:
安装所需依赖性:
[root@nginx ~]# yum install -y bzip2 systemd-devel libxml2-devel sqlite-devel libpng-devel
[root@nginx ~]# yum install libcurl-devel-7.76.1-29.el9_4.x86_64
[root@nginx ~]# wget -O /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo
[root@nginx ~]# yum install oniguruma-devel

解压源码并开始安装:
[root@nginx ~]# cd php-8.3.9/
[root@nginx 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 php-8.3.9]# make && make install

[root@nginx php-8.3.9]# vim /usr/local/nginx/conf/nginx.conf

   建议写到http后面
    include "/usr/local/nginx/conf.d/*.conf";
    
[root@nginx conf]# mkdir -p /usr/local/nginx/conf.d/

php相关配置优化:
[root@nginx php-8.3.9]# cd /usr/local/php/etc/
[root@nginx etc]# cp php-fpm.conf.default php-fpm.conf
[root@nginx etc]# vim php-fpm.conf
[global]
; Pid file
; Note: the default prefix is /usr/local/php/var
; Default Value: none
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]# vim 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 php-8.3.9]# 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 php-8.3.9]# cp sapi/fpm/php-fpm.service /lib/systemd/system/
[root@nginx php-8.3.9]# vim /lib/systemd/system/php-fpm.service
# Mounts the /usr, /boot, and /etc directories read-only for processes invoked by this unit.
#ProtectSystem=full   ----- 注释掉该内容

[root@nginx php-8.3.9]# systemctl daemon-reload
[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       201110     149942/php-fpm: mas 
[root@nginx php-8.3.9]# 
6.3.2.2 Nginx和php整合
把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
export PATH=$PATH:/usr/local/nginx/sbin:/usr/local/php/bin:/usr/local/php/sbin
[root@nginx ~]# source ~/.bash_profile 

创建php目录,存放php页面
[root@nginx ~]# mkdir -p /data/web/php
[root@nginx bin]# vim /data/web/php/index.php
<?php
        phpinfo();
?>

[root@nginx php]# vim /usr/local/nginx/conf.d/vhost.conf
server {
  listen 80;
  server_name www.xiaoding.org;
  root /data/web/php;
  index index.html;

  location ~ \.php$ {
        fastcgi_pass 0.0.0.0:9000;
        fastcgi_index index.php;
        include fastcgi.conf;
  }
}
[root@nginx php]# nginx -s reload

网页访问:www.xiaoding.org/index.php/

6.3.3 Nginx-php的缓存优化

安装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   ---- 用来生成configure file
Configuring for:
PHP Api Version:         20230831
Zend Module Api No:      20230831
Zend Extension Api No:   420230831
[root@nginx memcache-8.2]# 
[root@nginx memcache-8.2]# ./configure && make && make install

查看是否生成模块:
[root@nginx ~]# cd /usr/local/php/lib/php/extensions/no-debug-non-zts-20230831/
[root@nginx no-debug-non-zts-20230831]# ls
memcache.so  opcache.so

[root@nginx no-debug-non-zts-20230831]# cd
[root@nginx ~]# systemctl restart php-fpm.service


配置php加载memcache模块
[root@nginx ~]# vim /usr/local/php/etc/php.ini 
;extension=soap
;extension=sockets
;extension=sodium
;extension=sqlite3
;extension=tidy
;extension=xsl
;extension=zip

;zend_extension=opcache
extension=memcache   ---------- 加上memcache模块
;;;;;;;;;;;;;;;;;;;
; Module Settings ;
;;;;;;;;;;;;;;;;;;;


[root@nginx ~]# systemctl restart php-fpm.service 

复制测试文件到nginx发布目录中
[root@nginx memcache-8.2]# cp example.php memcache.php /data/web/php/   ---- 模拟向memcache发送数据,看效果
[root@nginx memcache-8.2]# vim /data/web/php/memcache.php

 

安装memcache模块
[root@nginx ~]# dnf install memcached -y
[root@nginx ~]# systemctl enable --now memcached.service 
Created symlink /etc/systemd/system/multi-user.target.wants/memcached.service → /usr/lib/systemd/system/memcached.service.
[root@nginx ~]# 
[root@nginx ~]# vim /etc/sysconfig/memcached    ------ 查看信息


[root@nginx ~]# systemctl start memcached.service
[root@nginx ~]# netstat -antlupe | grep mem   ---- 查看端口是否开启
tcp        0      0 127.0.0.1:11211         0.0.0.0:*               LISTEN      980        192566     187646/memcached    
tcp6       0      0 ::1:11211               :::*                    LISTEN      980        192567     187646/memcached    
[root@nginx ~]# 

去网页访问:http://www.xiaoding.org/example.php
		  http://www.xiaoding.org/memcache.php

 http://www.xiaoding.org/example.php
这个网页刷新的越多,memcache网页绿色柱状就会越多
绿色表示直接从memcache中取的值,橙色的表示不在memcache里,从外面取的值。

 

压测查看:

内存比较小,看不出来什么效果

[root@nginx ~]# ab -n1000 -c10 http://www.xiaoding.org/index.php

 

再来一次
[root@nginx ~]# ab -n1000 -c10 http://www.xiaoding.org/index.php

 

6.3.3.1 Nginx-memcache高速缓存
示例:
[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 www.xiaoding.org;
  root /data/web/php;
  index index.html;

  location /memc {
        internal;
        memc_connect_timeout 100ms;
        memc_send_timeout 100ms;
        memc_read_timeout 100ms;
        set $mem_key  $query_string;
        set $memc_exptime 300;
        memc_pass memcache;
  }     

  location ~ \.php$ {
        set $key  $uri$args;
        srcache_fetch GET /memc $key;
        srcache_store PUT /memc $key;
        fastcgi_pass 172.25.254.120:9000;
        fastcgi_index index.php;
        include fastcgi.conf;
  }
}

[root@nginx ~]# 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 ~]# nginx -s reload

再进行压测:
ab -n500 -c10 http://www.xiaoding.org/index.php

 

七、 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 ~]# nginx -s stop  ---- 停掉Nginx,别让它占用80端口
[root@nginx ~]# netstat -antlupe | grep nginx
[root@nginx ~]# 
[root@nginx ~]# tar zxf openresty-1.25.3.1.tar.gz 
[root@nginx ~]# cd openresty-1.25.3.1/
[root@nginx openresty-1.25.3.1]# dnf -y install gcc pcre-devel openssl-devel perl
[root@nginx openresty-1.25.3.1]# cd /usr/local/src
[root@nginx src]# wget https://openresty.org/download/openresty-1.17.8.2.tar.gz

编译安装openresty
[root@nginx openresty-1.25.3.1]# ./configure --prefix=/usr/local/openresty --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-http_sub_module --without-http_memcached_module --with-stream_realip_module

[root@nginx openresty-1.25.3.1]# make && make install
[root@nginx bin]# vim ~/.bash_profile
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs
export PATH=$PATH:/usr/local/nginx/sbin:/usr/local/php/bin:/usr/local/php/sbin:/usr/local/openresty/bin

[root@nginx bin]# source ~/.bash_profile 
[root@nginx bin]# openresty 
[root@nginx bin]# netstat -antlupe | grep 80
tcp        0      0 127.0.0.1:11211         0.0.0.0:*               LISTEN      980        206856     187885/memcached    
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      0          255222     211989/nginx: maste 
tcp        0      0 0.0.0.0:9000            0.0.0.0:*               LISTEN      0          230905     188036/php-fpm: mas 
tcp6       0      0 ::1:11211               :::*                    LISTEN      980        206857     187885/memcached    
udp        0      0 0.0.0.0:5353            0.0.0.0:*                           70         24380      850/avahi-daemon: r 
[root@nginx bin]# 

网页访问172.25.254.120

  • 14
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

俗庸203

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值