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

nginx高性能web服务器

.Web 服务基础介绍
正常情况下的单次web服务访问流程:
1.1 互联网发展历程回顾
199332日,中国科学院高能物理研究所租用AT&T公司的国际卫星信道建立的接入美国SLAC国家实
验室的64K专线正式开通,成为我国连入Internet的第一根专线。
1995年马云开始创业并推出了一个web网站 中国黄页。
1999年创建阿里巴巴www.alibabagroup.com
2003510日创立淘宝网。
200412月,马云创立第三方网上支付平台支付宝(蚂蚁金服旗下,共有蚂蚁金服支付宝、余额宝、招 财宝、蚂蚁聚宝、网商银行、蚂蚁花呗、芝麻信用等子业务板块)。
2009年开始举办双十一购物狂欢节,以下是历年交易成交额:
2009年双十一:5000万元
2010年双十一:9.36亿元
2011年双十一:33.6亿元
2012年双十一:191亿元
2013年双十一:350亿元
2014年双十一:571亿元
2015年双十一:912.17亿元
2016年双十一:1207亿元
2017年双十一:1682.69亿元
2018年双十一:2135亿元
2019年双十一:2684亿元
2020年双十一:4982亿元
2021年双十一:5403亿元
2022年双十一:5571亿元
2023年双十一:4013亿元
2024年双十一:5314亿元
2012111日淘宝商城正式更名为天猫
2014919日里巴巴集团于纽约证券交易所正式挂牌上市
1.2 Web 服务介绍
1.2.1 Apache 经典的 Web 服务端
Apache起初由美国的伊利诺伊大学香槟分校的国家超级计算机应用中心开发
目前经历了两大版本分别是1.X2.X
其可以通过编译安装实现特定的功能
1.2.1.1 Apache prefork 模型
预派生模式,有一个主控制进程,然后生成多个子进程,使用select模型,最大并发1024。
每个子进程有一个独立的线程响应用户请求。
相对比较占用内存,但是比较稳定,可以设置最大和最小进程数。
是最古老的一种模式,也是最稳定的模式,适用于访问量不是很大的场景。
优点:稳定
缺点:每个用户请求需要对应开启一个进程,占用资源较多,并发性差,不适用于高并发场景
1.2.1.2 Apache worker 模型
一种多进程和多线程混合的模型。
有一个控制进程,启动多个子进程。
每个子进程里面包含固定的线程。
使用线程程来处理请求。
当线程不够使用的时候会再启动一个新的子进程,然后在进程里面再启动线程处理请求,
由于其使用了线程处理请求,因此可以承受更高的并发。
优点:相比prefork 占用的内存较少,可以同时处理更多的请求
缺点:使用keepalive的长连接方式,某个线程会一直被占据,即使没有传输数据,也需要一直等待到超 时才会被释放。如果过多的线程,被这样占据,也会导致在高并发场景下的无服务线程可用(该问题在 prefork模式下,同样会发生)
1.2.1.3 Apache event模型
Apache中最新的模式,2012年发布的apache 2.4.X系列正式支持event 模型,属于事件驱动模型(epoll)。
每个进程响应多个请求,在现在版本里的已经是稳定可用的模式。
它和worker模式很像,最大的区别在于,它解决了keepalive场景下长期被占用的线程的资源浪费问题 (某些线程因为被keepalive,空挂在哪里等待,中间几乎没有请求过来,甚至等到超时)。event MPM中,会有一个专门的线程来管理这些keepalive类型的线程。
当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放。这样增强了高并发场 景下的请求处理能力。
优点:单线程响应多请求,占据更少的内存,高并发下表现更优秀,会有一个专门的线程来管理keep
alive类型的线程,当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放
缺点:没有线程安全控制
1.2.2 Nginx-高性能的 Web 服务端
Nginx是由1994年毕业于俄罗斯国立莫斯科鲍曼科技大学的同学 伊戈尔·赛索耶夫 为俄罗斯著名搜索网站 rambler.ru开发的,开发工作最早从2002年开始,第一次公开发布时间是2004104日,版本号是 0.1.0。
2019311F5 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.3 用户访问体验和性能
1.2.3.1 用户访问体验统计
互联网存在用户速度体验的1-3-10原则,即1秒最优,1-3秒较优,3~10秒比较慢,10秒以上用户无法接 受。用户放弃一个产品的代价很低,只是换一个URL而已。
全球最大搜索引擎 Google:慢500ms = 20% 将放弃访问。
全球最大的电商零售网站亚马逊:慢100ms = 1% 将放弃交易有很多研究都表明,性能对用户的行为有很大的影响:
79%的用户表示不太可能再次打开一个缓慢的网站
47%的用户期望网页能在2秒钟以内加载
40%的用户表示如果加载时间超过三秒钟,就会放弃这个网站
页面加载时间延迟一秒可能导致转换损失7%,页面浏览量减少11%
8秒定律:用户访问一个网站时,如果等待网页打开的时间超过8秒,会有超过30%的用户放弃等待
1.2.3.2 影响用户体验的因素
据说马云在刚开始创业在给客户演示时,打开一个网站花了不到四个小时。
影响用户体验的因素
1.客户端
      客户端硬件配置
      客户端网络速率
      客户端与服务端距离
2.服务器
      服务端网络速率
      服务端硬件配置
      服务端架构设计
      服务端应用程序工作模式
      服务端并发数量服务端响应文件大小及数量 buffer cache
      服务端I/O压力1.2.4 服务端 I/O 流程
1.2.4 服务端 I/O 流程
I/O在计算机中指Input/Output IOPS (Input/Output Per Second)即每秒的输入输出量(或读写次数),是衡量磁盘性能的主要指标之一。IOPS是指单位时间内系统能处理的I/O请求数量,一般以每秒处理的 I/O请求数量为单位,I/O请求通常为读或写数据操作请求。
一次完整的I/O是用户空间的进程数据与内核空间的内核数据的报文的完整交换,但是由于内核空间与用 户空间是严格隔离的,所以其数据交换过程中不能由用户空间的进程直接调用内核空间的内存数据,而 是需要经历一次从内核空间中的内存数据copy到用户空间的进程内存当中,所以简单说I/O就是把数据从 内核空间中的内存数据复制到用户空间中进程的内存当中。
服务器的I/O
       磁盘I/O
       网络I/O : 一切皆文件,本质为对socket文件的读写
1.2.4.1 磁盘 I/O
磁盘I/O是进程向内核发起系统调用,请求磁盘上的某个资源比如是html 文件或者图片,然后内核通过相 应的驱动程序将目标文件加载到内核的内存空间,加载完成之后把数据从内核内存再复制给进程内存, 如果是比较大的数据也需要等待时间。
机械磁盘的寻道时间、旋转延迟和数据传输时间:
寻道时间:是指磁头移动到正确的磁道上所花费的时间,寻道时间越短则I/O处理就越快,目前磁盘的寻道时 间一般在3-15毫秒左右。
旋转延迟:是指将磁盘片旋转到数据所在的扇区到磁头下面所花费的时间,旋转延迟取决于磁盘的转速,通常 使用磁盘旋转一周所需要时间的1/2之一表示,比如7200转的磁盘平均训传延迟大约为
60*1000/7200/2=4.17毫秒,公式的意思为 (每分钟60*1000毫秒每秒/7200转每分/2),如果是
15000转的则为60*1000/15000/2=2毫秒。
数据传输时间:指的是读取到数据后传输数据的时间,主要取决于传输速率,这个值等于数据大小除以传输速 率,目前的磁盘接口每秒的传输速度可以达到600MB,因此可以忽略不计。
常见的机械磁盘平均寻道时间值:
7200/分的磁盘平均物理寻道时间:9毫秒
10000/分的磁盘平均物理寻道时间:6毫秒
15000/分的磁盘平均物理寻道时间:4毫秒
常见磁盘的平均延迟时间:
7200转的机械盘平均延迟:60*1000/7200/2 = 4.17ms
10000转的机械盘平均延迟:60*1000/10000/2 = 3ms
15000转的机械盘平均延迟:60*1000/15000/2 = 2ms
每秒最大IOPS的计算方法:
7200转的磁盘IOPS计算方式:1000毫秒/(9毫秒的寻道时间+4.17毫秒的平均旋转延迟时
)=1000/13.13=75.9 IOPS
10000转的磁盘的IOPS计算方式:1000毫秒/(6毫秒的寻道时间+3毫秒的平均旋转延迟时
)=1000/9=111IOPS
15000转的磁盘的IOPS计算方式:15000毫秒/(4毫秒的寻道时间+2毫秒的平均旋转延迟时
)=1000/6=166.6 IOPS
1.2.4.2 网络 I/O
网络通信就是网络协议栈到用户空间进程的IO就是网络IO
网络I/O 处理过程
         获取请求数据,客户端与服务器建立连接发出请求,服务器接受请求(1-3
         构建响应,当服务器接收完请求,并在用户空间处理客户端的请求,直到构建响应完成(4
         返回数据,服务器将已构建好的响应再通过内核空间的网络 I/O 发还给客户端(5-7
不论磁盘和网络I/O
每次I/O,都要经由两个阶段:
         第一步:将数据从文件先加载至内核内存空间(缓冲区),等待数据准备完成,时间较长
         第二步:将数据从内核缓冲区复制到用户空间的进程的内存中,时间较短
1.3 I/O 模型
1.3.1 I/O 模型相关概念
同步/异步:关注的是消息通信机制,即调用者在等待一件事情的处理结果时,被调用者是否提供完成状态的通知。
        同步:synchronous,被调用者并不提供事件的处理结果相关的通知消息,需要调用者主动询问事 情是否处理完成。
       异步:asynchronous,被调用者通过状态、通知或回调机制主动通知调用者被调用者的运行状态。
阻塞/非阻塞:关注调用者在等待结果返回之前所处的状态
        阻塞:blocking,指IO操作需要彻底完成后才返回到用户空间,调用结果返回之前,调用者被挂起,干不了别的事情。
       非阻塞:nonblocking,指IO操作被调用后立即返回给用户一个状态值,而无需等到IO操作彻底完成,在最终的调用结果返回之前,调用者不会被挂起,可以去做别的事情。
1.3.2 网络 I/O 模型
阻塞型、非阻塞型、复用型、信号驱动型、异步
1.3.2.1 阻塞型 I/O 模型(blocking IO
阻塞IO模型是最简单的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.3.2.2 非阻塞型 I/O 模型 (nonblocking IO
用户线程发起IO请求时立即返回。但并未读取到任何数据,用户线程需要不断地发起IO请求,直到数据到达后,才真正读取到数据,继续执行。即 “轮询机制存在两个问题:如果有大量文件描述符都要等,那么就得一个一个的read。这会带来大量的Context Switchread是系统调用,每调用一次就得在用户态和核心态切换一次)。轮询的时间不好把握。这里是要猜多久之后数据才能到。等待时间设的太长,程序响应延迟就过大;设的太短,就会造成过于频繁的重试,干耗CPU而已,是比较浪费CPU的方式,一般很少直接使用这种模型,而是在其他IO模型中使用非阻塞IO这一特性。
非阻塞:程序向内核发送请I/O求后一直等待内核响应,如果内核处理请求的IO操作不能立即返回IO结果,进程将不再等待,而且继续处理其他请求,但是仍然需要进程隔一段时间就要查看内核I/O是否完成。
查看上图可知,在设置连接为非阻塞时,当应用进程系统调用 recvfrom 没有数据返回时,内核会立即返回一个 EWOULDBLOCK 错误,而不会一直阻塞到数据准备好。如上图在第四次调用时有一个数据报准备好了,所以这时数据会被复制到 应用进程缓冲区 ,于是 recvfrom 成功返回数据。
当一个应用进程这样循环调用 recvfrom 时,称之为轮询 polling 。这么做往往会耗费大量CPU时间,实际使用很少。
1.3.2.3 多路复用 I/O (I/O multiplexing)
上面的模型中,每一个文件描述符对应的IO是由一个线程监控和处理。
多路复用IO指一个线程可以同时(实际是交替实现,即并发完成)监控和处理多个文件描述符对应各自的IO,即复用同一个线程。
一个线程之所以能实现同时处理多个IO,是因为这个线程调用了内核中的SELECT,POLLEPOLL等系统调用,从而实现多路复用IO。
I/O multiplexing 主要包括:selectpollepoll三种系统调用,select/poll/epoll的好处就在于单个
process就可以同时处理多个网络连接的IO
它的基本原理就是select/poll/epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。
当用户进程调用了select,那么整个进程会被block,而同时,kernel监视所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。
Apache prefork是此模式的selectworkerpoll模式。
IO多路复用(IO Multiplexing) :是一种机制,程序注册一组socket文件描述符给操作系统,表示我要监视这些fd是否有IO事件发生,有了就告诉程序处理”IO多路复用一般和NIO一起使用的。NIOIO多路复用是相对独立的。NIO仅仅是指IO API总是能立刻返回,不会被Blocking;IO多路复用仅仅是操作系统提供的一种便利的通知机制。操作系统并不会强制这俩必须得一起用,可以只用IO多路复用 + BIO,这时还是当前线程被卡住。IO多路复用和NIO是要配合一起使用才有。
实际意义
IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,就通知该进程多个连接共用一个等待机制,本模型会阻塞进程,但是进程是阻塞在select或者poll这两个系统调用上,而不是阻塞在真正的IO操作上用户首先将需要进行IO操作添加到select中,同时等待select系统调用返回。当数据到达时,IO被激活,select函数返回。用户线程正式发起read请求,读取数据并继续执行从流程上来看,使用select函数进行IO请求和同步阻塞模型没有太大的区别,甚至还多了添加监视IO,以及调用select函数的额外操作,效率更差。并且阻塞了两次,但是第一次阻塞在select上时,select可以监控多个IO上是否已有IO操作准备就绪,即可达到在同一个线程内同时处理多个IO请求的目的。而不像阻塞IO那种,一次只能监控一个IO虽然上述方式允许单线程内处理多个IO请求,但是每个IO请求的过程还是阻塞的(在select函数上阻塞),平均时间甚至比同步阻塞IO模型还要长。如果用户线程只是注册自己需要的IO请求,然后去做自己的事情,等到数据到来时再进行处理,则可以提高CPU的利用率IO多路复用是最常使用的IO模型,但是其异步程度还不够“彻底,因它使用了会阻塞线程的select系统调用。因此IO多路复用只能称为异步阻塞IO模型,而非真正的异步IO。
优缺点
    优点:可以基于一个阻塞对象,同时在多个描述符上等待就绪,而不是使用多个线程(每个文件描述符一个线程),这样可以大大节省系统资源。
    缺点:当连接数较少时效率相比多线程+阻塞 I/O 模型效率较低,可能延迟更大,因为单个连接处理需要 2 次系统调用,占用时间会有增加。
IO多路复用适用如下场合:
    当客户端处理多个描述符时(一般是交互式输入和网络套接口),必须使用I/O复用
    当一个客户端同时处理多个套接字时,此情况可能的但很少出现
    当一个服务器既要处理监听套接字,又要处理已连接套接字,一般也要用到I/O复用
    当一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用
    当一个服务器要处理多个服务或多个协议,一般要使用I/O复用
1.3.2.4 信号驱动式 I/O 模型 (signal-driven IO)
信号驱动I/O的意思就是进程现在不用傻等着,也不用去轮询。而是让内核在数据就绪时,发送信号通知进程。
调用的步骤是,通过系统调用 sigaction ,并注册一个信号处理的回调函数,该调用会立即返回,然后主程序可以继续向下执行,当有I/O操作准备就绪,即内核数据就绪时,内核会为该进程产生一个 SIGIO信号,并回调注册的信号回调函数,这样就可以在信号回调函数中系统调用 recvfrom 获取数据,将用户进程所需要的数据从内核空间拷贝到用户空间。
此模型的优势在于等待数据报到达期间进程不被阻塞。用户主程序可以继续执行,只要等待来自信号处理函数的通知。
在信号驱动式 I/O 模型中,应用程序使用套接口进行信号驱动 I/O,并安装一个信号处理函数,进程继续运行并不阻塞。
在信号驱动式 I/O 模型中,应用程序使用套接口进行信号驱动 I/O,并安装一个信号处理函数,进程继续运行并不阻塞。
当数据准备好时,进程会收到一个 SIGIO 信号,可以在信号处理函数中调用 I/O 操作函数处理数据。
优点:线程并没有在等待数据时被阻塞,内核直接返回调用接收信号,不影响进程继续处理其他请求因此可以提高资源的利用率。
缺点:信号 I/O 在大量 IO 操作时可能会因为信号队列溢出导致没法通知
异步阻塞:程序进程向内核发送IO调用后,不用等待内核响应,可以继续接受其他请求,内核收到进程请求后 ,进行的IO如果不能立即返回,就由内核等待结果,直到IO完成后内核再通知进程。
1.3.2.5 异步 I/O 模型 (asynchronous IO)
异步I/O 与 信号驱动I/O最大区别在于,信号驱动是内核通知用户进程何时开始一个I/O操作,而异步I/O是由内核通知用户进程I/O操作何时完成,两者有本质区别,相当于不用去饭店场吃饭,直接点个外卖,把等待上菜的时间也给省了。
相对于同步I/O,异步I/O不是顺序执行。用户进程进行aio_read系统调用之后,无论内核数据是否准备好,都会直接返回给用户进程,然后用户态进程可以去做别的事情。等到socket数据准备好了,内核直接复制数据给进程,然后从内核向进程发送通知。IO两个阶段,进程都是非阻塞的。
信号驱动IO当内核通知触发信号处理程序时,信号处理程序还需要阻塞在从内核空间缓冲区拷贝数据到用户空间缓冲区这个阶段,而异步IO直接是在第二个阶段完成后,内核直接通知用户线程可以进行后续操作了。
优点:异步 I/O 能够充分利用 DMA 特性,让 I/O 操作与计算重叠
缺点:要实现真正的异步 I/O,操作系统需要做大量的工作。目前 Windows 下通过 IOCP 实现了真正的异步 I/O,在 Linux 系统下,Linux 2.6才引入,目前 AIO 并不完善,因此在 Linux 下实现高并发网络编程时以 IO 复用模型模式+多线程任务的架构基本可以满足需求。
Linux提供了AIO库函数实现异步,但是用的很少。目前有很多开源的异步IO库,例如libeventlibev、libuv。
异步非阻塞:程序进程向内核发送IO调用后,不用等待内核响应,可以继续接受其他请求,内核调用的IO如果不能立即返回,内核会继续处理其他事物,直到IO完成后将结果通知给内核,内核在将IO完成的结果返回给进程,期间进程可以接受新的请求,内核也可以处理新的事物,因此相互不影响,可以实现较大的同时并实现较高的IO复用,因此异步非阻塞使用最多的一种通信方式。
1.3.4.2 常用I/O模型比较
Select
POSIX所规定,目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理。
缺点
单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,可以通过修改宏定
FD_SETSIZE,再重新编译内核实现,但是这样也会造成效率的降低单个进程可监视的fd数量被限制,默认是1024,修改此值需要重新编译内核对socket是线性扫描,即采用轮询的方法,效率较低select 采取了内存拷贝方法来实现内核将 FD 消息通知给用户空间,这样一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大。
poll
本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态其没有最大连接数的限制,原因是它是基于链表来存储的大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义poll特点是水平触发,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd select是边缘触发即只通知一次。
epoll
Linux 2.6内核中提出的selectpoll的增强版本支持水平触发LT和边缘触发ET,最大的特点在于边缘触发,它只告诉进程哪些fd刚刚变为就需态,并且只会通知一次使用事件的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知。
优点:
没有最大并发连接的限制:能打开的FD的上限远大于1024(1G的内存能监听约10万个端口),具体查看 /proc/sys/fs/file-max,此值和系统内存大小相关。
效率提升:非轮询的方式,不会随着FD数目的增加而效率下降;只有活跃可用的FD才会调用callback函数,即epoll最大的优点就在于它只管理活跃的连接,而跟连接总数无关。
内存拷贝,利用mmap(Memory Mapping)加速与内核空间的消息传递;epoll使用mmap减少复制开销。
总结:
1epoll只是一组API,比起select这种扫描全部的文件描述符,epoll只读取就绪的文件描述符,再加入基于事件的就绪通知机制,所以性能比较好。
2、基于epoll的事件多路复用减少了进程间切换的次数,使得操作系统少做了相对于用户任务来说的无用功。
3epollselect等多路复用方式来说,减少了遍历循环及内存拷贝的工作量,因为活跃连接只占总并发连接的很小一部分。
实例:最大并发连接数和内存有直接关系
实例:
范例: select epoll 帮助
1.4 零拷贝
1.4.1 零拷贝介绍
1.4.1.1 传统 Linux I/O 的问题
传统的 Linux 系统的标准 I/O 接口(readwrite)是基于数据拷贝的,也就是数据都是 copy_to_user或者 copy_from_user,这样做的好处是,通过中间缓存的机制,减少磁盘 I/O 的操作,但是坏处也很明显,大量数据的拷贝,用户态和内核态的频繁切换,会消耗大量的 CPU 资源,严重影响数据传输的性能,统计表明,在Linux协议栈中,数据包在内核态和用户态之间的拷贝所用的时间甚至占到了数据包整个处理流程时间的57.1%
1.4.1.2 什么是零拷贝
零拷贝就是上述问题的一个解决方案,通过尽量避免拷贝操作来缓解 CPU 的压力。零拷贝并没有真正做 到“0”拷贝,它更多是一种思想,很多的零拷贝技术都是基于这个思想去做的优化。
1.4.2 零拷页相关技术
1.4.2.1 MMAP ( Memory Mapping )
mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进行访问。
mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。
实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。
内存映射减少数据在用户空间和内核空间之间的拷贝操作,适合大量数据传输。
上面左图为传统读写,右图为MMAP.两者相比mmap要比普通的read系统调用少了一次copy的过程。因为read调用,进程是无法直接访问kernel space的,所以在read系统调用返回前,内核需要将数据从内核复制到进程指定的buffer。但mmap之后,进程可以直接访问mmap的数据(page cache )
1.4.2.2 SENDFILE
14.2.3 DMA 辅助的 SENDFILE
.Nginx 架构和安装
2.1 Nginx 概述
2.1.1 Nginx 介绍
Nginxengine X 2002年开发,分为社区版和商业版(nginx plus )
2019311 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://openresty.org/cn/
2.1.2 Nginx 功能介绍
         静态的web资源服务器html,图片,jscsstxt等静态资源
         http/https协议的反向代理
         结合FastCGI/uWSGI/SCGI等协议反向代理动态资源请求
         tcp/udp协议的请求转发(反向代理)
         imap4/pop3协议的反向代理
2.2.3 基础特性
         模块化设计,较好的扩展性
         高可靠性
         支持热部署:不停机更新配置文件,升级版本,更换日志文件
         低内存消耗:10000keep-alive连接模式下的非活动连接,仅需2.5M内存
         event-driven,aio,mmapsendfile
2.2.4 Web 服务相关的功能
         虚拟主机(server
         支持 keep-alive 和管道连接(利用一个连接做多次请求)
         访问日志(支持基于日志缓冲提高其性能)url rewirte
         路径别名
         基于IP及用户的访问控制
         支持速率限制及并发数限制
         重新配置和在线升级而无须中断客户的工作进程
2.2 Nginx 架构和进程
2.2.2 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.3 Nginx 进程间通信
工作进程是由主进程生成的,主进程使用fork()函数,在Nginx服务器启动过程中主进程根据配置文件决定启动工作进程的数量,然后建立一张全局的工作表用于存放当前未退出的所有的工作进程,主进程生成工作进程后会将新生成的工作进程加入到工作进程表中,并建立一个单向的管道并将其传递给工作进程,该管道与普通的管道不同,它是由主进程指向工作进程的单向通道,包含了主进程向工作进程发出的指令、工作进程ID、工作进程在工作进程表中的索引和必要的文件描述符等信息。
主进程与外界通过信号机制进行通信,当接收到需要处理的信号时,它通过管道向相关的工作进程发送正确的指令,每个工作进程都有能力捕获管道中的可读事件,当管道中有可读事件的时候,工作进程就会从管道中读取并解析指令,然后采取相应的执行动作,这样就完成了主进程与工作进程的交互。
worker进程之间的通信原理基本上和主进程与worker进程之间的通信是一样的,只要worker进程之间能够取得彼此的信息,建立管道即可通信,但是由于worker进程之间是完全隔离的,因此一个进程想要知道另外一个进程的状态信息,就只能通过主进程来实现。
为了实现worker进程之间的交互,master进程在生成worker进程之后,在worker进程表中进行遍历,将该新进程的PID以及针对该进程建立的管道句柄传递给worker进程中的其他进程,为worker进程之间的通信做准备,当worker进程1worker进程2发送指令的时候,首先在master进程给它的其他worker进程工作信息中找到2的进程PID,然后将正确的指令写入指向进程2的管道,worker进程2捕获到管道中的事件后,解析指令并进行相关操作,这样就完成了worker进程之间的通信。
worker进程可以通过共享内存来通讯的,比如upstream中的zone,或者limit_reqlimit_conn中的zone等。操作系统提供了共享内存机制。
Nginx 启动时,Master 进程,加载配置文件
Master 进程,初始化监听的 socket
Master 进程,fork 出多个 Worker 进程
Worker 进程,竞争新的连接,获胜方通过三次握手,建立 Socket 连接,并处理请求
2.2.5 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 版本支持动态装载和卸载
模块分类:
核心模块:core module
标准模块:
HTTP 模块: ngx_http_*
HTTP Core modules #默认功能
HTTP Optional modules #需编译时指定
Mail 模块: ngx_mail_*
Stream 模块 ngx_stream_*
第三方模块
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++,Fortranpascalobjective C,java以及Ada等其他语言,此外还需要Automake工具,以完成自动创建Makefile的工作,Nginx的一些模块需要依赖第三方库,比如: pcre(支持rewrite),zlib(支持gzip模块)和openssl(支持ssl模块) 等。
2.4.2.1 编译安装 Nginx
官方源码包下载地址:
https://nginx.org/en/download.html

编译安装示例:

#!/bin/bash# 安装依赖
dnf install gcc pcre-devel zlib-devel openssl-devel -y# 创建 Nginx 用户
useradd -s /sbin/nologin -M nginx# 解压 Nginx 源码包
tar zxf nginx-1.24.0.tar.gz
cd 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 \
--with-stream_realip_module# 编译并安装
make && make install# 创建软链接使命令全局可用
ln -s /usr/local/nginx/sbin/nginx /usr/sbin/nginx# 验证安装
nginx -v
nginx完成安装以后,有四个主要的目录
[root@Nginx nginx-1.24.0]# ls /usr/local/nginx/
conf html logs sbin
conf:保存nginx所有的配置文件,其中nginx.confnginx服务器的最核心最主要的配置文件,其他的.conf则是用来配置nginx相关的功能的,例如fastcgi功能使用的是fastcgi.conffastcgi_params两个文件,配置文件一般都有一个样板配置文件,是以.default为后缀,使用时可将其复制并将default后缀去掉即可。
html目录中保存了nginx服务器的web文件,但是可以更改为其他目录保存web文件,另外还有一个50xweb文件是默认的错误页面提示页面。
logs:用来保存nginx服务器的访问日志错误日志等日志,logs目录可以放在其他路径,比 如/var/logs/nginx里面。
sbin:保存nginx二进制启动脚本,可以接受不同的参数以实现不同的功能。
2.4.2.2 配置nginx的启动文件

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

将旧Nginx二进制文件换成新Nginx程序文件(注意先备份)
master进程发送USR2信号
master进程修改pid文件名加上后缀.oldbin,成为nginx.pid.oldbin
master进程用新Nginx文件启动新master进程成为旧master的子进程,系统中将有新旧两个Nginx
进程共同提供Web服务,当前新的请求仍然由旧Nginxworker进程进行处理,将新生成的master
程的PID存放至新生成的pid文件nginx.pid
向旧的Nginx服务进程发送WINCH信号,使旧的Nginx worker进程平滑停止
向旧master进程发送QUIT信号,关闭老master,并删除Nginx.pid.oldbin文件
如果发现升级有问题,可以回滚∶向老master发送HUP,向新master发送QUIT
2.6.2 平滑升级和回滚案例
[root@Nginx nginx]# tar zxf nginx-1.26.1.tar.gz
[root@Nginx nginx]# cd nginx-1.26.1/# 编译新版本
[root@Nginx nginx-1.26.1]# ./configure --with-http_ssl_module --with-http_v2_module \
--with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module \
--with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module# 仅执行make,无需make install
[root@Nginx nginx-1.26.1]# make# 对比新旧版本
[root@Nginx nginx-1.26.1]# ll objs/nginx /usr/local/nginx/sbin/nginx
-rwxr-xr-x 1 root root 1239416 Jul 18 15:08 objs/nginx
-rwxr-xr-x 1 root root 5671488 Jul 18 11:41 /usr/local/nginx/sbin/nginx# 备份旧版nginx
[root@Nginx ~]# cd /usr/local/nginx/sbin/
[root@Nginx sbin]# cp nginx nginx.24# 替换为新版本
[root@Nginx sbin]# \cp -f /root/nginx/nginx-1.26.1/objs/nginx /usr/local/nginx/sbin# 配置检测
[root@Nginx sbin]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful# 平滑升级
[root@Nginx sbin]# kill -USR2 48732  # nginx worker ID# 查看进程状态
[root@Nginx sbin]# ps aux | grep nginx
root      48732  0.0  0.1  9868 2436 ?        Ss   14:17   0:00 nginx: master process /usr/local/nginx/sbin/nginx
nobody    48733  0.0  0.2 14200 4868 ?        S    14:17   0:00 nginx: worker process
root      52075  0.0  0.3  9876 6528 ?        S    15:41   0:00 nginx: master process /usr/local/nginx/sbin/nginx
nobody    52076  0.0  0.2 14208 4868 ?        S    15:41   0:00 nginx: worker process# 验证版本
[root@Nginx sbin]# curl -I localhost
HTTP/1.1 200 OK
Server: nginx/1.24.0  # 旧版本仍在运行
...# 回收旧版本
[root@Nginx sbin]# kill -WINCH 48732# 再次验证
[root@Nginx sbin]# curl -I localhost
HTTP/1.1 200 OK
Server: nginx/1.26.1  # 新版本已生效
...# 版本回滚操作
[root@Nginx sbin]# cp nginx nginx.26
[root@Nginx sbin]# mv nginx.24 nginx
[root@Nginx sbin]# kill -HUP 48732
[root@Nginx sbin]# kill -WINCH 52075# 最终验证
[root@Nginx sbin]# curl -I localhost
HTTP/1.1 200 OK
Server: nginx/1.24.0  # 回滚完成
...
Nginx 核心配置详解
3.1 配置文件说明
nginx 官方帮助文档:http://nginx.org/en/docs/
Nginx的配置文件的组成部分:
         主配置文件:nginx.conf
         子配置文件: include conf.d/*.conf
          fastcgi uwsgiscgi 等协议相关的配置文件
          mime.types:支持的mime类型,MIME(Multipurpose Internet Mail Extensions)多用途互联网邮
          件扩展类型,MIME消息能包含文本、图像、音频、视频以及其他应用程序专用的数据,是设定某
          种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动
          使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
nginx 配置文件格式说明   
         配置文件由指令与指令块构成
         每条指令以;分号结尾,指令与值之间以空格符号分隔
         可以将多条指令放在同一行,用分号分隔即可,但可读性差,不推荐
         指令块以{ }大括号将多条指令组织在一起,且可以嵌套指令块
         include语句允许组合多个配置文件以提升可维护性
         使用#符号添加注释,提高可读性
         使用$符号使用变量
         部分指令的参数支持正则表达式
Nginx 主配置文件的配置指令方式:
directive value [value2 ...];
注意
(1) 指令必须以分号结尾
(2) 支持使用配置变量
内建变量:由Nginx模块引入,可直接引用
自定义变量:由用户使用set命令定义,格式: set variable_name value;
引用变量:$variable_name

     

主配置文件结构:四部分
main block:主配置段,即全局配置段,对http,mail都有效
#事件驱动相关的配置
event {
...
}
#http/https 协议相关配置段
http {
...
}
#默认配置文件不包括下面两个块
#mail 协议相关配置段
mail {
...
}
#stream 服务器相关配置段
stream {
...
}
默认的nginx.conf 配置文件格式说明

3.2 全局配置
示例: 实现 nginx 的高并发配置
​​​​​​​
安装压力测试软件:

测试:

-n:请求总量

-c:并发量

4.建立nginx站点:

5.root 与 alias

root:指定web的家目录,在定义location的时候,文件的绝对路径等于 root+location

alias:定义路径别名,会把访问的路径重新定义到其指定的路径,文档映射的另一种机制;仅能用于 location上下文,此指令使用较少

6.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前,表示包含正则表达式并且转义字符。可以将 . * ?等转义为普通符号
#匹配优先级从高到低:
=, ^~, ~/~*, 不带符号

nginx -s reload
测试:

测试:

7.Nginx 账户认证功能

由 ngx_http_auth_basic_module 模块提供此功能

测试:

8.自定义错误页面

自定义错误页,同时也可以用指定的响应状态码进行响应, 可用位置:http, server, location, if in location

测试:

9.自定义错误日志

测试:

10.检测文件是否存在
try_files会按顺序检查文件是否存在,返回第一个找到的文件或文件夹(结尾加斜线表示为文件夹),如 果所有文件或文件夹都找不到,会进行一个内部重定向到最后一个参数。只有最后一个参数可以引起一个内部重定向,之前的参数只设置内部URI的指向。最后一个参数是回退URI且必须存在,否则会出现内部500错误。

11.长连接配置

安装测试软件:

测试:

12.作为下载服务器配置

建立共享资源存放目录:

测试:

四、Nginx 高级配置
1.Nginx 状态页

基于nginx 模块 ngx_http_stub_status_module 实现, 在编译安装nginx的时候需要添加编译参数 --with-http_stub_status_module 否则配置完成之后监测会是提示法错误

状态页显示的是整个服务器的状态,而非虚拟主机的状态

测试:

2.Nginx 压缩功能
Nginx支持对指定类型的文件进行压缩然后再传输给客户端,而且压缩还可以设置压缩比例,压缩后的文件大小将比源文件显著变小,样有助于降低出口带宽的利用率,降低企业的IT支出,不过会占用相 应的CPU资源。 Nginx对文件的压缩功能是依赖于模块 ngx_http_gzip_module,默认是内置模块

建立实验素材:

编辑主配置文件:

测试:

3.Nginx的版本隐藏

用户在访问nginx的时候,我们可以从报文中获得nginx的版本,相对于裸漏版本号的nginx,我们把其隐藏起来更安全(编译之前设置

4.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$host;
# 请求的主机名limit_rate 10240;
echo $limit_rate;
# 显示网络速率限制值(未设置则显示0)$remote_port;
# 客户端连接Nginx时使用的随机端口号$remote_user;
# 通过Auth Basic Module认证的用户名$request_body_file;
# 反向代理时发送给后端服务器的本地资源文件名$request_method;
# 请求方法(GET/PUT/DELETE等)$request_filename;
# 当前请求资源文件的完整磁盘路径
# 示例: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>;
# 获取指定cookie键值(将name替换为实际cookie名)$http_<name>;
# 获取请求头字段值(name需小写,横线转下划线)

先备份原本的主和子配置文件

systemctl stop nginx

编译中添加插件:

make & make install 重新编译安装

将原来的主和子配置文件覆盖新的主和子配置文件

systemctl restart nginx

编辑配置文件:

测试:

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

1.ngx_http_rewrite_module 模块指令
if 指令
用于条件匹配判断,并根据条件判断结果选择不同的Nginx配置,可以配置在server或location块中进行配置,Nginx的if语法仅能使用if做单次判断,不支持使用if else或者if elif这样的多重判断

使用正则表达式对变量进行匹配,匹配成功时if指令认为条件为true,否则认为false,变量与表达式之间使用以下符号链接:

= #比较变量和字符串是否相等,相等时if指令认为该条件为true,反之为false
!= #比较变量和字符串是否不相等,不相等时if指令认为条件为true,反之为false
~ #区分大小写字符,可以通过正则表达式匹配,满足匹配条件为真,不满足匹配条件为假
!~ #区分大小写字符,判断是否匹配,不满足匹配条件为真,满足匹配条件为假
~* #不区分大小写字符,可以通过正则表达式匹配,满足匹配条件为真,不满足匹配条件为假
!~* #不区分大小字符,判断是否匹配,满足匹配条件为假,不满足匹配条件为真
-f 和 !-f #判断请求的文件是否存在和是否不存在
-d 和 !-d #判断请求的目录是否存在和是否不存在
-x 和 !-x #判断文件是否可执行和是否不可执行
-e 和 !-e #判断请求的文件或目录是否存在和是否不存在(包括文件,目录,软链接)
#注意:
#如果$变量的值为空字符串或0,则if指令认为该条件为false,其他条件为true。
#nginx 1.0.1之前$变量的值如果以0开头的任意字符串会返回false

测试:

set 指令

指定key并给其定义一个变量,变量可以调用Nginx内置变量赋值给key另外set定义格式为set $key value,value可以是text, variables和两者的组合。

测试:

break 指令
用于中断当前相同作用域(location)中的其他Nginx配置 与该指令处于同一作用域的Nginx配置中,位于它前面的配置生效位于后面的 ngx_http_rewrite_module 模块中指令就不再执行Nginx服务器在根据配置处理请求的过程中遇到该指令的时候,回到上一层作用域继续向下读取配置, 该指令可以在server块和locationif块中使用

测试:

return 指令
return用于完成对请求的处理,并直接向客户端返回响应状态码,比如:可以指定重定向URL(对于特殊重 定向状态码,301/302等) 或者是指定提示文本内容(对于特殊状态码403/500等),处于此指令后的所有配置都将不被执行,return可以在server、if 和 location块进行配置

测试:

2.rewrite 指令

通过正则表达式的匹配来改变URI,可以同时存在一个或多个指令,按照顺序依次对URI进行匹配, rewrite主要是针对用户请求的URL或者是URI做具体处理

rewrite将用户请求的URI基于regex所描述的模式进行检查,匹配到时将其替换为表达式指定的新的URI

注意:如果在同一级配置块中存在多个rewrite规则,那么会自下而下逐个检查;被某条件规则替换完成后,会重新一轮的替换检查,隐含有循环机制,但不超过10次;如果超过,提示500响应码,[flag]所表示的标志位用于控制此循环机制

如果替换后的URL是以http://或https://开头,则替换结果会直接以重定向返回给客户端, 即永久重定向 301

正则表达式格式

. #匹配除换行符以外的任意字符
\w #匹配字母或数字或下划线或汉字
\s #匹配任意的空白符
\d #匹配数字
\b #匹配单词的开始或结束
^ #匹配字付串的开始
$ #匹配字符串的结束
* #匹配重复零次或更多次
+ #匹配重复一次或更多次
? #匹配重复零次或一次
(n) #匹配重复n次
{n,} #匹配重复n次或更多次
{n,m} #匹配重复n到m次
*? #匹配重复任意次,但尽可能少重复
+? #匹配重复1次或更多次,但尽可能少重复
?? #匹配重复0次或1次,但尽可能少重复
{n,m}? #匹配重复n到m次,但尽可能少重复
{n,}? #匹配重复n次以上,但尽可能少重复
\W #匹配任意不是字母,数字,下划线,汉字的字符
\S #匹配任意不是空白符的字符
\D #匹配任意非数字的字符
\B #匹配不是单词开头或结束的位置
[^x] #匹配除了x以外的任意字符
[^lee] #匹配除了lee 这几个字母以外的任意字符

rewrite flag 使用介绍
利用nginx的rewrite的指令,可以实现url的重新跳转,rewrite有四种不同的flag,分别是redirect(临时 重定向302)、permanent(永久重定向301)、break和last。其中前两种是跳转型的flag,后两种是代理型

跳转型指由客户端浏览器重新对新地址进行请求
代理型是在WEB服务器内部实现跳转

flag 说明:

redirect;
#临时重定向,重写完成后以临时重定向方式直接返回重写后生成的新URL给客户端
#由客户端重新发起请求;使用相对路径,或者http://或https://开头,状态码:302
permanent;
#重写完成后以永久重定向方式直接返回重写后生成的新URL给客户端
#由客户端重新发起请求,状态码:301
break;
#重写完成后,停止对当前URL在当前location中后续的其它重写操作
#而后直接跳转至重写规则配置块之后的其它配置,结束循环,建议在location中使用
#适用于一个URL一次重写
last;
#重写完成后,停止对当前URI在当前location中后续的其它重写操作,
#而后对新的URL启动新一轮重写检查,不建议在location中使用
#适用于一个URL多次重写,要注意避免出现超过十次以及URL重写后返回错误的给用户

rewrite案例: 域名永久与临时重定向
域名的临时的调整,后期可能会变,之前的域名或者URL可能还用、或者跳转的目的域名和URL还会跳 转,这种情况浏览器不会缓存跳转,临时重定向不会缓存域名解析记录(A记录),但是永久重定向会缓存

永久重定向301:

域名永久型调整,即域名永远跳转至另外一个新的域名,之前的域名再也不使用,跳转记录可以缓存到 客户端浏览器 永久重定向会缓存DNS解析记录, 浏览器中有 from disk cache 信息,即使nginx服务器无法访问,浏览器也 会利用缓存进行重定向

临时重定向302:

域名临时重定向,告诉浏览器域名不是固定重定向到当前目标域名,后期可能随时会更改,因此浏览器 不会缓存当前域名的解析记录,而浏览器会缓存永久重定向的DNS解析记录,这也是临时重定向与永久 重定向最大的本质区别。

即当nginx服务器无法访问时,浏览器不能利用缓存,而导致重定向失败

rewrite 案例: break 与 last

测试:

break:终止当前rewrite规则,不再匹配后续规则或location

last:完成当前rewrite规则后,重新匹配location

默认行为为last,可根据需求选择合适的指令。

rewrite案例: 自动跳转 https

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

制作证书:

测试:

rewrite 案例: 判断网页存在与否

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

测试:

3.Nginx 防盗链
防盗链基于客户端携带的referer实现,referer是记录打开一个页面之前记录是从哪个页面跳转过来的标 记信息,如果别人只链接了自己网站图片或某个单独的资源,而不是打开了网站的整个页面,这就是盗 链,referer就是之前的那个网站域名,正常的referer信息有以下几种:

正常通过搜索引擎搜索web 网站并访问该网站的referer信息如下:

日志

实现盗链

在一个web 站点盗链另一个站点的资源信息,比如:图片、视频等

实现防盗链

基于访问安全考虑,nginx支持通过ngx_http_referer_module模块,检查访问请求的referer信息是否有效 实现防盗链功能

六、Nginx 反向代理功能

反向代理:reverse proxy,指的是代理外网用户的请求到内部的指定的服务器,并将数据返回给用户的 一种方式,这是用的比较多的一种方式。
Nginx 除了可以在企业提供高性能的web服务之外,另外还可以将 nginx 本身不具备的请求通过某种预 定义的协议转发至其它服务器处理,不同的协议就是Nginx服务器与其他服务器进行通信的一种规范,主 要在不同的场景使用以下模块实现不同的功能。

同构代理:用户不需要其他程序的参与,直接通过http协议或者tcp协议访问后端服务器

异构代理:用户访问的资源时需要经过处理后才能返回的,比如php,python,等等,这种访问资源需要经过处理才能被访问

1.实战案例: 反向代理针对特定的资源实现代理(动静分离)

要求:将用户对域 www.zk.org 的请求转发给后端服务器处理

RS1和RS2安装httpd并启动,关闭火墙和selinux

RS2安装php,并在默认发布目录写info.php

2.反向代理示例: 缓存功能

编辑主配置文件:

编辑子配置文件:

访问并验证缓存文件:

验证缓存目录结构及文件大小:

3.http 反向代理负载均衡

注意: 本节实验过程中先关闭缓存

配置:

测试:

4.基于Cookie 实现会话绑定

测试:

5.实现 Nginx 四层负载均衡
Nginx在1.9.0版本开始支持tcp模式的负载均衡,在1.9.13版本开始支持udp协议的负载,udp主要用于 DNS的域名解析,其配置方式和指令和http 代理类似,其基于ngx_stream_proxy_module模块实现tcp 负载,另外基于模块ngx_stream_upstream_module实现后端服务器分组转发、权重分配、状态监测、 调度算法等高级功能。 如果编译安装,需要指定 --with-stream 选项才能支持ngx_stream_proxy_module模块

tcp负载均衡配置参数

注意:tcp的负载均衡要位于http语句块之外

负载均衡实例: MySQL
nginx配置
udp 负载均衡实例: DNS

两RS配置DNS:

在http外指定新的子配置文件目录:

建立目录和子配置文件:

如果要53端口同时开udp和tcp的话就要多复制出条server块然后把第二个server块的udp去掉

访问测试:

从前端主机成功轮询访问到100和200server

6.实现 FastCGI

1.FastCGI配置指令

Nginx基于模块ngx_http_fastcgi_module实现通过fastcgi协议将指定的客户端请求转发至php-fpm处 理,其配置指令如下:

2.FastCGI实战案例 : Nginx与php-fpm在同一服务器
编译安装

编译安装更方便自定义参数或选项,所以推荐大家使用源码编译

解决php依赖:

如果oniguruma-devel没有则:

解压源码并安装

等待编译安装

php相关配置优化

生成主配置文件:

生成启动文件:

准备php测试页面

Nginx配置转发

Nginx安装完成之后默认生成了与fastcgi的相关配置文件,一般保存在nginx的安装路径的conf目录当 中,比如/apps/nginx/conf/fastcgi.conf、/apps/nginx/conf/fastcgi_params

DNS解析:

添加php环境变量:

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

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

安装memcache模块

复制测试文件到nginx发布目录中

修改状态页面的登陆密码和memcache的访问接口

配置php加载memcache模块

部署memcached

性能对比:

4.php高速缓存

部署方法

在我们安装的nginx中默认不支持memc和srcache功能,需要借助第三方模块来让nginx支持此功能,所以nginx需要重新编译

备份配置文件:

编译:

./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module --add-module=/mnt/memc-nginx-module-0.20 --add-module=/mnt/srcache-nginx-module-0.33

编译安装:

恢复备份配置文件:

编辑配置文件:

测试压测:

七、nginx 二次开发版本

openresty
Nginx 是俄罗斯人发明的, Lua 是巴西几个教授发明的,中国人章亦春把 LuaJIT VM 嵌入到 Nginx中, 实现了OpenResty 这个高性能服务端解决方案

OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态Web 应用、Web 服 务和动态网关。

OpenResty® 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。

OpenResty 由于有功能强大且方便的的API,可扩展性更强,如果需要实现定制功能,OpenResty是个不错的选择

官网: http://openresty.org/cn/

编译安装 openresty:

因为openresty与nginx冲突,所以编译安装 openresty前要把nginx卸载:

./configure --prefix=/usr/local/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

启动:

http://www.xdnf.cn/news/1271269.html

相关文章:

  • BroadcastChannel:轻松实现前端跨页面通信
  • 使用 Ansys Discovery 进行动态设计和分析
  • ​​​​​​​【Datawhale AI夏令营】多模态RAG财报问答挑战赛:学习笔记与上分思考
  • Java基础-完成局域网内沟通软件的开发
  • B.10.01.5-电商系统的设计模式应用实战
  • Day 8: 深度学习综合实战与进阶技术 - 从优化到部署的完整流程
  • 【Datawhale AI夏令营】从Baseline到SOTA:深度剖析金融问答RAG管道优化之路
  • Mybatis进阶
  • 机器学习第七课之支持向量机SVM
  • 本地进行语音文字互转
  • P1890 gcd区间
  • C++11中的移动语义
  • 【无标题】AI 赋能日常效率:实用案例与操作心得分享
  • B.10.01.6-DDD领域驱动设计:从理论到落地的完整指南
  • 数据挖掘2.6 Perceptron Modeling 感知器建模
  • Qdrant Filtering:must / should / must_not 全解析(含 Python 实操)
  • 心灵笔记:正念冥想
  • 解决python错误:playwright._impl._errors.TimeoutError: Timeout 30000ms exceeded.
  • 3.5.2_1 随机访问介质访问控制
  • Python中的Lambda函数详解
  • 【排序算法】④堆排序
  • NTP /Chrony 网络时间协议
  • Leetcode-19. 删除链表的倒数第 N 个结点
  • 比较useCallback、useMemo 和 React.memo
  • 机器学习 K-Means聚类 无监督学习
  • 第4章 程序段的反复执行for语句P115练习题(题及答案)
  • 元宇宙技术如何改变社交方式?
  • 哈希与安全
  • pgAdmin 仪表盘的system部分不能显示,报SYSTEM_STATS扩展没有安装
  • C++ 中的智能指针