一、WEB服务简介:
1、Web服务是什么?
Web服务是一种基于互联网进行机器之间通信的技术,它使用标准化的HTTP协议和XML语言来实现数据交换和通信。Web服务可以被许多不同的客户端应用程序访问,包括Web浏览器、移动设备应用程序、桌面应用程序等。
在Web服务中,一个服务提供者将自己的服务发布到互联网上,并提供一个标准的接口供客户端应用程序进行访问。客户端应用程序通过发送HTTP请求来调用这些服务,服务提供者收到请求后将其转换为相应的处理结果,并通过HTTP响应将处理结果返回给客户端应用程序。
Web服务的优点包括可扩展性、松耦合性、跨平台性等,使得它成为了现代应用程序开发中不可或缺的一部分。
2、Web服务的运行原理
1、客户端向Web服务发送请求:客户端可以通过浏览器、手机App等方式向Web服务发送请求,一般使用HTTP协议进行通信。
2、Web服务接收请求:Web服务接收到客户端发送的请求后,会对请求进行解析,识别出请求的资源、请求方式等信息。
3、Web服务处理请求:Web服务根据请求的信息,进行相应的处理。例如,如果是GET请求,则返回相应的资源;如果是POST请求,则对请求中包含的数据进行处理等。
4、Web服务返回响应:处理完请求后,Web服务会将响应结果返回给客户端。一般情况下,响应内容以HTML、JSON等格式进行编码,然后通过HTTP协议返回给客户端。
5、客户端接收响应:客户端接收到Web服务返回的响应后,对响应内容进行解析和处理。例如,浏览器可以将HTML格式的响应内容渲染成网页展示给用户。
3、Web服务常用软件
Web服务软件是一种基于Web技术的应用软件,能够为用户提供Web服务。目前常见的Web服务软件有以下几种:
1、Apache HTTP Server:这是一个由Apache软件基金会开发的自由软件,是最流行的Web服务器之一。它支持多种操作系统和多种编程语言,包括Perl、Python、PHP等,并且具有可扩展性和安全性等特点。
2、Nginx:这是一个轻量级的、高性能的Web服务器,也是自由软件。Nginx采用异步事件驱动的模型,能够处理大量的并发请求,同时还支持负载均衡和反向代理等功能。
3、IIS:这是由微软公司开发的Web服务器软件,主要运行在Windows操作系统上。IIS具有易用性和安全性等优点,并且与其他微软产品的集成度非常高。
4、Tomcat:这是一个开源的Servlet容器,也可以充当Web服务器。它支持Java Servlet和JavaServer Pages(JSP)等技术,适用于Java Web应用程序的开发和部署。
5、Lighttpd:这是一个轻量级、高性能的Web服务器,特别适合于静态内容的服务。它采用事件驱动和非阻塞I/O技术,能够快速响应大量并发请求。
二、 服务端 I/O 流程
I/O 在计算机中指 Input/Output , IOPS (Input/Output Per Second) 即每秒的输入输出量 ( 或读写次数 ) ,是衡量磁盘性能的主要指标之一。IOPS 是指单位时间内系统能处理的 I/O 请求数量,一般以每秒处理的I/O请求数量为单位, I/O 请求通常为读或写数据操作请求。
一次完整的 I/O 是用户空间的进程数据与内核空间的内核数据的报文的完整交换,但是由于内核空间与用户空间是严格隔离的,所以其数据交换过程中不能由用户空间的进程直接调用内核空间的内存数据,而是需要经历一次从内核空间中的内存数据copy 到用户空间的进程内存当中,所以简单说 I/O 就是把数据从内核空间中的内存数据复制到用户空间中进程的内存当中。
2.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
2.2 网络 I/O
网络通信就是网络协议栈到用户空间进程的 IO 就是网络 IO
图解:
三、I/O模型
3.1 I/O 模型相关概念
同步 / 异步:关注的是消息通信机制,即调用者在等待一件事情的处理结果时,被调用者是否提供
完成状态的通知。
- 同步:synchronous,被调用者并不提供事件的处理结果相关的通知消息,需要调用者主动询问事情是否处理完成
- 异步:asynchronous,被调用者通过状态、通知或回调机制主动通知调用者被调用者的运行状态
阻塞/非阻塞:关注调用者在等待结果返回之前所处的状态
- 阻塞:blocking,指IO操作需要彻底完成后才返回到用户空间,调用结果返回之前,调用者被挂起,干不了别的事情。
- 非阻塞:nonblocking,指IO操作被调用后立即返回给用户一个状态值,而无需等到IO操作彻底完成,在最终的调用结果返回之前,调用者不会被挂起,可以去做别的事情。
3.2 网络I/O模型
基于网络IO进行数据读写,根据同步调用或异步调用、是否阻塞调用等维度,可将网络IO模型细分为5种:(1) 阻塞IO(Blocking IO)模型、非阻塞IO(Nonblocking IO)模型、I/O多路复用(IO Multiplexing)模型、信号驱动IO(Signal Driven IO)模型、异步IO(Asynchronous IO)模型。接下来将以UDP的数据报接收为例,介绍下五种网络IO模型。之所以选择UDP而不是TCP,是因为TCP会复杂化网络IO模型的介绍。此外,将recvfrom函数看成系统调用。这里屏蔽掉不同操作系统的实现细节。
阻塞IO(Blocking IO)模型
对于阻塞IO模型来说,应用进程会阻塞在recvfrom的调用。具体执行流程如下图所示:
应用进程在从调用recvfrom开始到该函数返回的这段时间内是被阻塞的。recvfrom成功返回后,应用进程才开始处理数据报。
非阻塞IO(Nonblocking IO)模型
对于非阻塞IO模型来说,应用进程会循环调用recvfrom并马上返回(轮询)。应用进程持续轮询内核,以查看某个操作是否就绪。具体执行流程如下图所示:
对于非阻塞IO模型来说,轮询操作会耗费大量CPU时间,使用场景较少。
I/O多路复用(IO Multiplexing)模型
对于I/O多路复用模型来说,应用进程阻塞在select/poll调用,等待数据报变为可读。当select/poll返回套接字可读这一条件时,应用进程调用recvfrom把所读数据报复制到应用进程缓冲区。具体执行流程如下图所示:
相比阻塞IO模型,I/O多路复用模型并没有明显优势,事实上由于使用增加了select系统调用,I/O多路复用模型要稍显劣势(多了一次系统调用)。I/O多路复用模型的优势主要体现在可以等待多个数据报就绪。
与I/O多路复用模型密切相关的另一种模型是在多线程中使用阻塞IO模型。这种模型与I/O多路复用模型的区别是,相对于I/O多路复用模型使用select/poll等系统函数阻塞在多个数据上,而是使用多线程,这样每个线程都可自由调用recvfrom。
信号驱动IO(Signal Driven IO)模型
对于信号驱动IO模型来说,应用进程首先通过sigaction系统调用并注册一个信号处理函数,然后立即返回。当数据报准备好后,内核就为该进程产生一个SIGIO信号。然后信号处理函数就被执行。而信号处理函数中会调用recvfrom读取数据报。具体执行流程如下图所示:
异步IO(Asynchronous IO)模型
对于异步IO模型来说,应用进程首先调用aio_read系统调用,告诉内核当整个操作完成时如何通知应用进程,然后立即返回。内核自行将数据从内核复制到应用进程的缓存区,并在完成后通知应用进程。具体执行流程如下图所示:
异步IO模型和信号驱动IO模型类似,区别在于信号驱动IO模型是由内核通知应用进程何时可以启动一个IO操作,而异步IO模型是由内核通知IO操作何时完成。异步IO模型的信号直到数据已复制到应用进程缓冲区才产生,而信号驱动IO模型的信号是在数据报准备好就产生。
IO模型比较
对于以上五种IO模型,阻塞 IO 模型、非阻塞 IO 模型、IO 多路复用模型 和 信号驱动 IO 模型都属于同步IO模型,因为应用进程都会阻塞在数据从内核复制到应用进程的缓冲区。相反,异步IO模型委托内核将数据复制到缓冲区。五种IO模型的详细比较,如下图所示:
3.3 I/O 的常用实现方式
1、select
select系统调用的功能是对多个文件描述符进行监视,当有文件描述符的文件读写操作完成,发生异常或者超时,该调用会返回这些文件描述符。
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);
用户进程调用select系统调用时,select会将需要监控的readfds集合拷贝到内核空间(以可读socket为例),然后遍历自己监控的socket,以检查该socket是否可读。如果没有一个socket可读,那么select会调用schedule_timeout进入schedule循环,使用户进程进入睡眠。如果在timeout时间内存在Socket可读,或者timeout时间达到,则用户进程会被唤醒,然后select将可读的socket返回给用户进程。
分析select系统调用实现,存在三个问题:
(1) 一个进程所能打开的最大连接数有限。单个进程所能打开的最大连接数由FD_SETSIZE宏定义。当然可以对宏FD_SETSIZE进行修改,然后重新编译内核,但是性能可能会受到影响。一般情况下,32位机默认1024个,64位默认2048。
(2) 需要额外的用户进程和内核的数据拷贝操作。select调用需要将监控的socket集合从用户进程拷贝到内核,然后在执行完毕时,将可读/可写的socket集合从内核拷贝到用户进程。
(3) 随着连接数增加,带来的性能问题。因为每次调用时都会对连接进行线性遍历,所以随着连接数的增加,会造成遍历速度的"线性下降"问题。
2、poll
poll的实现和select相似,只是描述文件描述符的方式不同。poll使用pollfd结构,而不是select的fd_set结构。poll使用链表存储文件描述符,解决了select中固定大小的问题。但poll和select一样,需要将文件描述符的数组整体复制于用户进程和内核之间,且其性能开销随着文件描述符的增加而线性增大。
int poll(struct pollfd *ufds, unsigned int nfds, int timeout);
struct pollfd {
int fd; /*文件描述符*/
short events; /*监控的事件*/
short revents; /*监控事件中满足条件返回的事件*/
};
int poll(struct pollfd *fds, nfds_tnfds, int timeout);
3、epoll
epoll 是库是 Nginx 服务器支持的最高性能的事件驱动库之一,是公认的非常优秀的事件驱动模型,它和select和 poll 有很大的区别, epoll 是 poll 的升级版,但是与 poll 有很大的区别 .epoll 的处理方式是创建一个待处理的事件列表,然后把这个列表发给内核,返回的时候在去轮询检查这个表,以判断事件是否发生,epoll 支持一个进程打开的最大事件描述符的上限是系统可以打开的文件的最大数,同时 epoll 库的I/O效率不随描述符数目增加而线性下降,因为它只会对内核上报的 “ 活跃 ” 的描述符进行操作。
// 创建一个epoll句柄
int epoll_create(int size);
// 向 epoll 对象中添加/修改/删除要管理的连接
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
// 等待epoll管理的连接上的 IO 事件
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
调用 epoll_create 系统调用,可以创建一个epoll的句柄,其中size用来告诉内核这个监听的数目一共有多大。需要注意的是,当创建好epoll句柄后,它就是会占用一个fd值,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。
调用 epoll_ctl 系统调用,注册要监听的事件类型。
调用 epoll_wait 系统调用,等待事件的产生,收集在 epoll 监控的事件中已经发送的事件,作用类似于 select() 调用。
select、poll、epoll选型
select,poll,epoll都是IO多路复用的实现,所以select,poll,epoll等本质上都是同步I/O,因为其读写内核中数据都是阻塞的。
select 单个进程所能打开的最大连接数由FD_SETSIZE宏定义。而 poll 则没有最大连接数的限制,因为它是基于链表来存储文件描述符。对epoll而言,虽然连接数有上限,但1G内存的机器上可以打开10万左右的连接,2G内存的机器可以打开20万左右的连接。
select 和 poll 需要额外的用户进程和内核的数据拷贝操作。即将监控的socket集合从用户进程拷贝到内核,然后在执行完毕时,将可读/可写的socket集合从内核拷贝到用户进程。且随着连接数增加,会造成遍历速度的"线性下降"问题。对epoll而言,监控的socket集合首次调用epoll_ctl拷贝,后续调用epoll_wait则不需要拷贝。
在选择select,poll,epoll时,要根据具体的使用场合以及这三种方式的自身特点。表面上看epoll的性能最好,但是在连接数少并且连接都十分活跃的情况下,select和poll的性能可能比epoll好。而且,基于epoll实现网络编程,需要使用到三个系统调用,其实现复杂度要高于select和poll。
零拷贝
零拷贝,通过尽量避免拷贝操作来缓解 CPU 的压力。零拷贝并没有真正做到“0”拷贝,它更多是一种思想,很多的零拷贝技术都是基于这个思想去做的优化
四、Nginx简介架构及安装
4.1、Nginx简介
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模块)等功能,并且支持第三方的功能扩展。
工作场景:
Nginx 功能介绍:
- 静态的web资源服务器html,图片,js,css,txt等静态资源
- http/https协议的反向代理
- 结合FastCGI/uWSGI/SCGI等协议反向代理动态资源请求
- tcp/udp协议的请求转发(反向代理)
- imap4/pop3协议的反向代理
基础特性:
- 模块化设计,较好的扩展性
- 高可靠性
- 支持热部署:不停机更新配置文件,升级版本,更换日志文件
- 低内存消耗:10000个keep-alive连接模式下的非活动连接,仅需2.5M内存
- event-driven,aio,mmap,sendfile
Web 服务相关的功能
- 虚拟主机(server)
- 支持 keep-alive 和管道连接(利用一个连接做多次请求)
- 访问日志(支持基于日志缓冲提高其性能)
- url rewirte
- 路径别名
- 基于IP及用户的访问控制
- 支持速率限制及并发数限制
- 重新配置和在线升级而无须中断客户的工作进程
4.2、Nginx 架构和进程
Nginx 进程结构
web 请求处理机制
- 单进程方式:服务器每接收到一个客户端请求就有服务器的主进程生成一个子进程响应客户端,直到用户关闭连接,这样的优势是处理速度快,子进程之间相互独立,但是如果访问过大会导致服务器资源耗尽而无法提供请求
- 多线程方式:与多进程方式类似,但是每收到一个客户端请求会有服务进程派生出一个线程和此客户端进行交互,一个线程的开销远远小于一个进程,因此多线程方式在很大程度减轻了web服务器对系统资源的要求,但是多线程也有自己的缺点,即当多个线程位于同一个进程内工作的时候,可以相互访问同样的内存地址空间,所以他们相互影响,一旦主进程挂掉则所有子线程都不能工作了,IIS服务器使用了多线程的方式,需要间隔一段时间就重启一次才能稳定。
主进程 (master process) 的功能:
- 对外接口:接收外部的操作(信号)
- 对内转发:根据外部的操作的不同,通过信号管理 Worker
- 监控:监控 worker 进程的运行状态,worker 进程异常终止后,自动重启 worker 进程
- 读取Nginx 配置文件并验证其有效性和正确性
- 建立、绑定和关闭socket连接
- 按照配置生成、管理和结束工作进程
- 接受外界指令,比如重启、升级及退出服务器等指令
- 不中断服务,实现平滑升级,重启服务并应用新的配置
- 开启日志文件,获取文件描述符
- 不中断服务,实现平滑升级,升级失败进行回滚处理
- 编译和处理perl脚本
工作进程( worker process )的功能:
- 所有 Worker 进程都是平等的
- 实际处理:网络请求,由 Worker 进程处理
- Worker进程数量:一般设置为核心数,充分利用CPU资源,同时避免进程数量过多,导致进程竞争CPU资源,
- 增加上下文切换的损耗
- 接受处理客户的请求
- 将请求依次送入各个功能模块进行处理
- I/O调用,获取响应数据
- 与后端服务器通信,接收后端服务器的处理结果
- 缓存数据,访问缓存索引,查询和调用缓存数据
- 发送请求结果,响应客户的请求
- 接收主程序指令,比如重启、升级和退出等
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等。操作系统提供了共享内存机制
Nginx模块介绍
nginx 有多种模块
- 核心模块:是 Nginx 服务器正常运行必不可少的模块,提供错误日志记录 、配置文件解析 、事件驱动机制 、进程管理等核心功能
- 标准HTTP模块:提供 HTTP 协议解析相关的功能,比如: 端口配置 、 网页编码设置 、 HTTP响应头设置 等等
- 可选HTTP模块:主要用于扩展标准的 HTTP 功能,让 Nginx 能处理一些特殊的服务,比如: Flash
- 多媒体传输 、解析 GeoIP 请求、 网络传输压缩 、 安全协议 SSL 支持等
- 邮件服务模块:主要用于支持 Nginx 的 邮件服务 ,包括对 POP3 协议、 IMAP 协议和 SMTP协议的支持
- Stream服务模块: 实现反向代理功能,包括TCP协议代理
- 第三方模块:是为了扩展 Nginx 服务器应用,完成开发者自定义功能,比如: Json 支持、 Lua 支持等
模块分类:
核心模块:core module
标准模块:
HTTP 模块: ngx_http_*
HTTP Core modules #默认功能
HTTP Optional modules #需编译时指定
Mail 模块: ngx_mail_*
Stream 模块 ngx_stream_*
第三方模块
4.3、Nginx的安装
官方源码包下载地址:https://nginx.org/en/download.html
编译安装示例:
# 安装依赖包
[root@nginx ~]# dnf install gcc pcre-devel zlib-devel openssl-devel -y
[root@nginx nginx]# tar zxf nginx-1.26.1.tar.gz
[root@nginx nginx]# cd nginx-1.26.1/
[root@Nginx nginx-1.26.1]# ./configure --prefix=/usr/local/nginx \
--user=nginx \ # 指定nginx运行用户
--group=nginx \ # 指定nginx运行组
--with-http_ssl_module \ # 支持https://
--with-http_v2_module \ # 支持http版本2
--with-http_realip_module \ # 支持ip透传
--with-http_stub_status_module \ # 支持状态页面
--with-http_gzip_static_module \ # 支持压缩
--with-pcre \ # 支持正则
--with-stream \ # 支持tcp反向代理
--with-stream_ssl_module \ # 支持tcp的ssl加密
[root@Nginx nginx-1.26.1]# make && make install
Nginx四个主要目录
[root@nginx nginx-1.26.1]# ls /usr/local/nginx/ conf html logs sbin
conf html logs sbin
conf:保存nginx所有的配置文件,其中nginx.conf是nginx服务器的最核心最主要的配置文件,其他 的.conf则是用来配置nginx相关的功能的,例如fastcgi功能使用的是fastcgi.conf和fastcgi_params 两个文件,配置文件一般都有一个样板配置文件,是以.default为后缀,使用时可将其复制并将default后缀 去掉即可。
html目录中保存了nginx服务器的web文件,但是可以更改为其他目录保存web文件,另外还有一个50x的web 文件是默认的错误页面提示页面。
logs:用来保存nginx服务器的访问日志错误日志等日志,logs目录可以放在其他路径,比 如/var/logs/nginx里面。
sbin:保存nginx二进制启动脚本,可以接受不同的参数以实现不同的功能。
Nginx 启动文件
[root@Nginx ~]# vim /lib/systemd/system/nginx.service
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target Wants=network-online.target
[Service]
Type=forking PIDFile=/usr/local/nginx/logs/nginx.pid ExecStartPre=/usr/local/nginx/sbin/nginx -t
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
[root@Nginx ~]# systemctl daemon-reload
[root@Nginx ~]# systemctl start nginx
平滑升级和回滚
有时候我们需要对Nginx版本进行升级以满足对其功能的需求,例如添加新模块,需要新功能,而此时 Nginx又在跑着业务无法停掉,这时我们就可能选择平滑升级
平滑升级流程
- 将旧Nginx二进制文件换成新Nginx程序文件(注意先备份)
- 向master进程发送USR2信号
- master进程修改pid文件名加上后缀.oldbin,成为nginx.pid.oldbin
- master进程用新Nginx文件启动新master进程成为旧master的子进程,系统中将有新旧两个Nginx主进程共同提供Web服务,当前新的请求仍然由旧Nginx的worker进程进行处理,将新生成的master进程的PID存放至新生成的pid文件nginx.pid
- 向旧的Nginx服务进程发送WINCH信号,使旧的Nginx worker进程平滑停止
- 向旧master进程发送QUIT信号,关闭老master,并删除Nginx.pid.oldbin文件
- 如果发现升级有问题,可以回滚∶向老master发送HUP,向新master发送QUIT
五、Nginx 核心配置详解
5.1、配置文件说明
nginx 官方帮助文档:http://nginx.org/en/docs/
Nginx 的配置文件的组成部分:
- 主配置文件:nginx.conf
- 子配置文件: include conf.d/*.conf
- fastcgi, uwsgi,scgi 等协议相关的配置文件
- mime.types:支持的mime类型,MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型,MIME消息能包含文本、图像、音频、视频以及其他应用程序专用的数据,是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
主配置文件结构:四部分
main block:主配置段,即全局配置段,对http,mail都有效
#事件驱动相关的配置
event {
...
}
#http/https 协议相关配置段
http {
...
}
#默认配置文件不包括下面两个块
#mail 协议相关配置段
mail {
...
}
#stream 服务器相关配置段
stream {
...
}
5.2、默认的nginx.conf 配置文件格式说明
#全局配置端,对全局生效,主要设置nginx的启动用户/组,启动的工作进程数量,工作模式,Nginx的PID路径,日志路径等。
user nginx nginx;
worker_processes 1; #启动工作进程数数量
events { #events #设置快,主要影响nginx服务器与用户的网络连接,比如是否允许同时接受多
个网络连接,使用哪种事件驱动模型 #处理请求,每个工作进程可以同时支持的最大连接数,是否开启对多工作进程下的网络连接进行序列化等。
worker_connections 1024; #设置单个nginx工作进程可以接受的最大并发,作为web服务器的时候最大并发数为 #worker_connections *
worker_processes,作为反向代理的时候为
#(worker_connections * worker_processes)/2
}
http { #http块是Nginx服务器配置中的重要部分,缓存、代理和日志格式定义等绝大多数功能和第三方模块都 #可以在这设置,http块可以包含多个server块,而一个server块中又可以包含多个location块,
#server块可以配置文件引入、MIME-Type定义、日志自定义、是否启用sendfile、连接超时时间和 #单个链接的请求上限等。
include mime.types;
default_type application/octet-stream;
sendfile on; #作为web服务器的时候打开sendfile加快静态文件传输,指定是否使用
#sendfile系统调用来传输文件
#sendfile系统调用在两个文件描述符之间直接传递数据(完全在内核中操作)
#从而避免了数据在内核缓冲区和用户缓冲区之间的拷贝,操作效率很高,被称之为零拷贝,
#硬盘 >> kernel buffer (快速拷贝到kernelsocket
buffer) >>协议栈。
keepalive_timeout 65; #长连接超时时间,单位是秒
server { #设置一个虚拟机主机,可以包含自己的全局快,同时也可以包含多个location模块
#比如本虚拟机监听的端口、本虚拟机的名称和IP配置,多个server 可以使用一个端口比如都使用 #80端口提供web服务
listen 80; #配置server监听的端口
server_name localhost; #本server的名称,当访问此名称的时候nginx会调用当前serevr内部的配置进程匹配。
location / { #location其实是server的一个指令,为nginx服务器提供比较多而且灵活的指令
#都是在location中体现的,主要是基于nginx接受到的请求字符串
#对用户请求的UIL进行匹配,并对特定的指令进行处理
#包括地址重定向、数据缓存和应答控制等功能都是在这部分实现
#另外很多第三方模块的配置也是在location模块中配置。
root html; #相当于默认页面的目录名称,默认是安装目录的相对路径,可以使用绝对路径配置。
index index.html index.htm; #默认的页面文件名称
}
error_page 500 502 503 504 /50x.html; #错误页面的文件名称
location = /50x.html { #location处理对应的不同错误码的页面定义到/50x.html
#这个跟对应其server中定义的目录下。
root html; #定义默认页面所在的目录
}
}
#和邮件相关的配置
#mail {
# ...
# } mail 协议相关配置段
#tcp代理配置,1.9版本以上支持
#stream {
# ...
# } stream 服务器相关配置段
#导入其他路径的配置文件
#include /apps/nginx/conf.d/*.conf
}
5.3 全局配置
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号CPU
#示例
worker_cpu_affinity 0001 0010 0100 1000;第0号---第3号CPU
worker_cpu_affinity 0101 1010;
#示例
worker_processes 4;
worker_cpu_affinity 00000010 00001000 00100000 10000000;
[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
#错误日志记录配置,语法:error_log file [debug | info | notice | warn | error | crit
| alert | emerg]
#error_log logs/error.log;
#error_log logs/error.log notice;
error_log /usr/local/nginx/logs/error.log error;
#pid文件保存路径
pid /usr/local/nginx/logs/nginx.pid;
worker_priority 0; #工作进程优先级,-20~20(19)
worker_rlimit_nofile 65536; #所有worker进程能打开的文件数量上限,
#包括:Nginx的所有连接(例如与代理服务器的连接等)
#而不仅仅是与客户端的连接
#另一个考虑因素是实际的并发连接数不能超过系统级别的最大打开文件数的限制
#最好与ulimit -n 或者limits.conf的值保持一致,
#修改pam限制
[root@Nginx ~]# sudo -u nginx ulimit -n
1024
[root@Nginx ~]# vim /etc/security/limits.conf
* - nofile 100000
[root@Nginx ~]# sudo -u nginx ulimit -n
100000
daemon off; #前台运行Nginx服务用于测试、docker等环境。
master_process off|on; #是否开启Nginx的master-worker工作模式,仅用于开发调试场景,默认为
on
events {
worker_connections 65535; #设置单个工作进程的最大并发连接数
use epoll; #使用epoll事件驱动,
#Nginx支持众多的事件驱动,
#比如:select、poll、epoll,只能设置在events模块中设置
accept_mutex on; #on为同一时刻一个请求轮流由work进程处理,
#而防止被同时唤醒所有worker
#避免多个睡眠进程被唤醒的设置,默认为off
#新请求会唤醒所有worker进程,此过程也称为"惊群"
#因此nginx刚安装完以后要进行适当的优化。建议设置为on
multi_accept on; #on时Nginx服务器的每个工作进程可以同时接受多个新的网
络连接
#此指令默认为off,
#即默认为一个工作进程只能一次接受一个新的网络连接
#打开后几个同接受多个。建议设置为on
}
5.4、核心配置示例
5.4.1 新建一个 PC web 站点
#定义子配置文件路径
[root@nginx ~]# mkdir /usr/local/nginx/conf.d/
[root@nginx ~]# vim /usr/local/nginx/conf/nginx.conf
http {
......
include /apps/nginx/conf/conf.d/*.conf; #在配置文件的最后面添加此行
#注意不要放在最前面,会导致前面的命令无法
生效
}
#创建虚拟主机网站配置
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
server {
listen 80;
server_name www.fangbo.org;
location / {
root /webdata/nginx/timinglee.org/lee/html;
}
}
[root@Nginx ~]# mkdir -p /webdata/nginx/timinglee.org/lee/html
[root@Nginx ~]# echo lee.timinglee.org >
/webdata/nginx/timinglee.org/lee/html/index.html
[root@Nginx ~]# nginx -s reload
#访问测试
[root@node100 ~]# curl www.fangbo.org #注意在访问主机中设解析
www.fangbo.org
5.4.2 location用法
- 在一个server中location配置段可存在多个,用于实现从uri到文件系统的路径映射;
- ngnix会根据用户请求的URI来检查定义的所有location,按一定的优先级找出一个最佳匹配,
- 而后应用其配置在没有使用正则表达式的时候,nginx会先在server中的多个location选取匹配度最高的一个uri
- uri是用户请求的字符串,即域名后面的web文件路径
- 然后使用该location模块中的正则url和字符串,如果匹配成功就结束搜索,并使用此location处理此请求。
语法规则:
location [ = | ~ | ~* | ^~ ] uri { ... }
= #只能精确指定文件,用于标准uri前,需要请求字串与uri精确匹配,大小敏感,如果匹配成功就停止向下匹配并立即处理请求
^~ #用于标准uri前,表示包含正则表达式,并且匹配以指定的正则表达式开头
\#对uri的最左边部分做匹配检查,不区分字符大小写
~ #用于标准uri前,表示包含正则表达式,并且区分大小写
~* #用于标准uri前,表示包含正则表达式,并且不区分大写
不带符号 #匹配起始于此uri的所有的uri
\ #用于标准uri前,表示包含正则表达式并且转义字符。可以将 . * ?等转义为普通符号
\#匹配优先级从高到低:
对目录(~ = ~*)> 不带符号 > ^~ > = =不支持目录所以排在最后
对文件匹配 = > (~ = ~*)>不带符号> ^~
匹配优先级案例
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 部分起始路径) > (/)
5.4.3 Nginx 账户认证功能
由 ngx_http_auth_basic_module 模块提供此功能
六、Nginx反向代理
6.1 http反向代理
逻辑调用关系
6.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 请求后,等待的超时时间,默认 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.2 http 反向代理负载均衡
Nginx 可以基于 ngx_http_upstream_module 模块提供服务器分组转发、权重分配、状态监测、调度算法等高级功能
6.2.1http 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
七、实验部分
1、用户认证
由 ngx_http_auth_basic_module 模块提供此功能
[root@nginx ~]# htpasswd -cm /usr/local/nginx/.htpasswd admin
New password:
Re-type new password:
Adding password for user admin
[root@nginx ~]# cat /usr/local/nginx/.htpasswd admin:$apr1$tHb1w5bt$Zx1wcAZIcRmHdn5W4RRFg1
[root@nginx ~]# htpasswd -m /usr/local/nginx/.htpasswd lee
New password:
Re-type new password:
Adding password for user lee
[root@nginx ~]# cat /usr/local/nginx/.htpasswd admin:$apr1$tHb1w5bt$Zx1wcAZIcRmHdn5W4RRFg1 lee:$apr1$jnV/eFoy$8QLCa5pQ9fGnsriHcdKl5/
[root@nginx ~]# mkdir /data/web/lee
[root@nginx ~]# echo lee > /data/web/lee/index.html
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
重启后便可测试访问
2、自定义错误页面
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
[root@nginx ~]# nginx -s reload
[root@nginx ~]# mkdir -p /data/web/errorpage
[root@nginx ~]# echo error page > /data/web/errorpage/40x.html
3、自定义错误日志
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
[root@nginx ~]# mkdir /var/log/timinglee.org
[root@nginx ~]# nginx -s reload
4、检测文件是否存在
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
[root@nginx ~]# nginx -s reload
[root@nginx ~]# mkdir /data/web/html/error
[root@nginx ~]# echo error default > /data/web/html/error/default.html
[root@nginx ~]# cat /data/web/html/error/index.html
cat: /data/web/html/error/index.html: 没有那个文件或目录
[root@nginx ~]# cat /data/web/html/error/default.html
error default
6、Nginx状态页
- 基于nginx 模块 ngx_http_stub_status_module 实现,
- 在编译安装nginx的时候需要添加编译参数 --with-http_stub_status_module
- 否则配置完成之后监测会是提示法错误
- Note
- 注意 : 状态页显示的是整个服务器的状态 , 而非虚拟主机的状态
# 状态页用于输出 nginx 的基本状态信息:
# 输出信息示例:
Active connections: 291
server accepts handled requests
16630948 16630948 31070465
上面三个数字分别对应 accepts,handled,requests 三个值
Reading: 6 Writing: 179 Waiting: 106
Active connections: # 当前处于活动状态的客户端连接数
# 包括连接等待空闲连接数 =reading+writing+waiting
accepts : # 统计总值, Nginx 自启动后已经接受的客户端请求连接的总数。
handled: # 统计总值, Nginx 自启动后已经处理完成的客户端请求连接总数
# 通常等于 accepts ,除非有因 worker_connections 限制等被拒绝的连接
requests: # 统计总值, Nginx 自启动后客户端发来的总的请求数
Reading: # 当前状态,正在读取客户端请求报文首部的连接的连接数
# 数值越大 , 说明排队现象严重 , 性能不足
Writing: # 当前状态,正在向客户端发送响应报文过程中的连接数 , 数值越大 , 说明访问量很大
Waiting: # 当前状态,正在等待客户端发出请求的空闲连接数
开启 keep-alive 的情况下 , 这个值等于 active – (reading+writing)
[root@nginx ~]# vim /usr/local/nginx/conf.d/status.conf
[root@nginx ~]# nginx -s reload
7、Nginx压缩功能
# 启用或禁用 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;
8、Nginx 变量使用
- nginx的变量可以在配置文件中引用,作为功能判断或者日志等场景使用
- 变量可以分为内置变量和自定义变量
- 内置变量是由nginx模块自带,通过变量可以获取到众多的与客户端访问相关的值。
常用内置变量
$remote_addr;
# 存放了客户端的地址,注意是客户端的公网 IP
$args;
# 变量中存放了 URL 中的所有参数
# 例如 :https://search.jd.com/Search?keyword= 手机 &enc=utf-8
# 返回结果为 : keyword= 手机 &enc=utf-8
$is_args
# 如果有参数为 ? 否则为空
$document_root;
# 保存了针对当前资源的请求的系统根目录 , 例如 :/webdata/nginx/timinglee.org/lee 。
$document_uri;
# 保存了当前请求中不包含参数的 URI ,注意是不包含请求的指令
# 比如 :http://lee.timinglee.org/var?\id=11111 会被定义为 /var
# 返回结果为 :/var
$host;
# 存放了请求的 host 名称
limit_rate 10240;
echo $limit_rate;
# 如果 nginx 服务器使用 limit_rate 配置了显示网络速率,则会显示,如果没有设置, 则显示 0
$remote_port;
# 客户端请求 Nginx 服务器时随机打开的端口,这是每个客户端自己的端口
$remote_user;
# 已经经过 Auth Basic Module 验证的用户名
$request_body_file;
# 做反向代理时发给后端服务器的本地资源的名称
$request_method; # 请求资源的方式, GET/PUT/DELETE 等
$request_filename;
# 当前请求的资源文件的磁盘路径,由 root 或 alias 指令与 URI 请求生成的文件绝对路径,
# 如 :webdata/nginx/timinglee.org/lee/var/index.html
$request_uri;
# 包含请求参数的原始 URI ,不包含主机名,相当于 :$document_uri?$args,
# 例如: /main/index.do?id=20190221&partner=search
$scheme;
# 请求的协议,例如 :http , https,ftp 等
$server_protocol;
# 保存了客户端请求资源使用的协议的版本,例如 :HTTP/1.0 , HTTP/1.1 , HTTP/2.0 等
$server_addr;
# 保存了服务器的 IP 地址
$server_name;
# 虚拟主机的主机名
$server_port;
# 虚拟主机的端口号
$http_user_agent;
# 客户端浏览器的详细信息
$http_cookie;
# 客户端的所有 cookie 信息
$cookie_<name>
#name 为任意请求报文首部字部 cookie 的 key 名
$http_<name>
#name 为任意请求报文首部字段 , 表示记录请求报文的首部字段, ame 的对应的首部字段名需要为小写,如果有横线需要替换为下划线
# 示例 :
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/vars.conf
[root@nginx ~]# nginx -s reload
[root@nginx ~]# curl -b "key1=lee,key2=lee1" -u lee:lee var.timinglee.org/var?name=lee&&id=6666
9、网页重启
if (条件匹配) {
action
}
= #比较变量和字符串是否相等,相等时if指令认为该条件为true,反之为false
!= #比较变量和字符串是否不相等,不相等时if指令认为条件为true,反之为false
~ #区分大小写字符,可以通过正则表达式匹配,满足匹配条件为真,不满足匹配条件为假
!~ #区分大小写字符,判断是否匹配,不满足匹配条件为真,满足匹配条件为假
~* #不区分大小写字符,可以通过正则表达式匹配,满足匹配条件为真,不满足匹配条件为假
!~* #不区分大小字符,判断是否匹配,满足匹配条件为假,不满足匹配条件为真
-f 和 !-f #判断请求的文件是否存在和是否不存在
-d 和 !-d #判断请求的目录是否存在和是否不存在
-x 和 !-x #判断文件是否可执行和是否不可执行
-e 和 !-e #判断请求的文件或目录是否存在和是否不存在(包括文件,目录,软链接)
\#注意:
\#如果$变量的值为空字符串或0,则if指令认为该条件为false,其他条件为true。
\#nginx 1.0.1之前$变量的值如果以0开头的任意字符串会返回false
[root@nginx ~]# vim /usr/local/nginx/conf.d/vars.conf
[root@nginx ~]# nginx -s reload
[root@nginx ~]# curl var.timinglee.org/test2/index.html
/data/web/html/test2/index.html is not exist
[root@nginx ~]# mkdir -p /data/web/html/test2
[root@nginx ~]# echo test2 > /data/web/html/test2/index.html
[root@nginx ~]# curl var.timinglee.org/test2/index.html
test2
set 指令
指定key并给其定义一个变量,变量可以调用Nginx内置变量赋值给key 另外set定义格式为set $key value,value可以是text, variables和两者的组合。
break 指令
用于中断当前相同作用域(location)中的其他Nginx配置 与该指令处于同一作用域的Nginx配置中,位于它前面的配置生效 位于后面的 ngx_http_rewrite_module 模块中指令就不再执行 Nginx服务器在根据配置处理请求的过程中遇到该指令的时候,回到上一层作用域继续向下读取配置,、 该指令可以在server块和locationif块中使用
注意: 如果break指令在location块中后续指令还会继续执行,只是不执行 ngx_http_rewrite_module 模块的指令,其它指令还会执行
return 指令
return用于完成对请求的处理,并直接向客户端返回响应状态码,比如:可以指定重定向URL(对于特殊重 定向状态码,301/302等) 或者是指定提示文本内容(对于特殊状态码403/500等),处于此指令后的所有配 置都将不被执行,return可以在server、if 和 location块进行配置
10、全站加密
[root@nginx ~]# cd /usr/local/nginx/
[root@nginx nginx]# mkdir certs -p
[root@nginx nginx]# 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
[root@nginx nginx]# cd certs/
[root@nginx certs]# ls timinglee.org.crt timinglee.org.key
[root@nginx nginx]# vim /usr/local/nginx/conf.d/vhost.conf
[root@nginx nginx]# nginx -s reload
11、防盗链
防盗链基于客户端携带的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
[root@nginx nginx]# vim /usr/local/nginx/conf.d/vhost.conf
[root@nginx nginx]# nginx -s reload
12、反向代理负载均衡
七层负载
[root@nginx html]# vim /usr/local/nginx/conf.d/vhost.conf
[root@nginx html]# nginx -s reload
ip_hash
[root@nginx html]# vim /usr/local/nginx/conf.d/vhost.conf
hash $request_uri consistent
[root@nginx html]# vim /usr/local/nginx/conf.d/vhost.conf
hash $cookie_lee
四层负载
[root@web10 named]# dnf install mariadb-server -y
[root@web20 named]# dnf install mariadb-server -y
[root@web20 named]# vim /etc/my.cnf.d/mariadb-server.cnf
[root@web10 named]# vim /etc/my.cnf.d/mariadb-server.cnf
[root@web10 named]# systemctl start mariadb.service
[root@web20 named]# systemctl start mariadb.service
[root@nginx tcpconf.d]# vim /usr/local/nginx/tcpconf.d/dns.conf
13、实现 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配置指令
Nginx 基于模块 ngx_http_fastcgi_module 实现通过 fastcgi 协议将指定的客户端请求转发至 php-fpm 处理,其配置指令如下:
fastcgi_pass address:port;
# 转发请求到后端服务器, address 为后端的 fastcgi server 的地址,可用位置: location, if in
location
fastcgi_index name;
#fastcgi 默认的主页资源,示例: fastcgi_index index.php;
fastcgi_param parameter value [if_not_empty];
# 设置传递给 FastCGI 服务器的参数值,可以是文本,变量或组合,可用于将 Nginx 的内置变量赋值给自定义
key
fastcgi_param REMOTE_ADDR $remote_addr; # 客户端源 IP
fastcgi_param REMOTE_PORT $remote_port; # 客户端源端口
fastcgi_param SERVER_ADDR $server_addr; # 请求的服务器 IP 地址
fastcgi_param SERVER_PORT $server_port; # 请求的服务器端口
fastcgi_param SERVER_NAME $server_name; # 请求的 server name
Nginx 默认配置示例:
location ~ \.php$ {
root /scripts;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # 默认脚本路径
#fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params; # 此文件默认系统已提供 , 存放的相对路径为
prefix/conf
}
源码安装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优化:
[root@Nginx ~]# mkdir /data/php -p
[root@Nginx ~]# cat /data/php/index.php #php测试页面
<?php
phpinfo();
?>
添加php环境变量
vim .bash_profile
安装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
配置php加载memcache模块
[root@nginx etc]# ls /usr/local/php/etc/ php-fpm.conf php-fpm.conf.default php-fpm.d php.ini[root@nginx etc]# vim /usr/local/php/etc/php.ini
[root@nginx php]# php -m | grep mem memcache
[root@nginx php]# systemctl reload php-fpm.service
[root@nginx etc]# systemctl restart php-fpm.service
部署memcached
[root@nginx etc]# dnf install memcached -y
[root@nginx etc]# vim /etc/sysconfig/memcached
复制测试文件到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/
14、nginx 二次开发版本
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是个不错的选择
[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
测试: