性能影响 互联网存在用户速度体验的1-3-10原则,即1秒最优,3-10秒比较慢,10秒以上用户无法接受。用户放弃一个产品的代价很低,只是换一个URL而已。
影响用户体验的几个因素
客户端硬件配置
客户端网络速率
客户端与服务端距离
服务端网络速率
服务端硬件配置
服务端架构设计
服务端应用程序工作模式
服务端并发数量
服务端响应文件大小及数量
服务端I/0压力
服务端I/O I/O在计算机中指Input/Output,IOPS (Input/Output Per Second)即每秒的输入输出量(或读写次数),是衡量磁盘性能的主要指标之一。IOPS是指的是在单位时间内系统能处理的I/O请求数量,一般以每秒处理的I/O请求数量为单位,I/0请求通常为读或写数据操作请求。
一次完整的I/O是用户空间的进程数据与内核空间的内核数据的报文的完整交换过程,但是由于内核空间与用户空间是严格隔离的,所以其数据交换过程中不能由用户空间的进程直接调用内核空间的内存数据,而是需要经历一次从内核空间中的内存数据copy到用户空间的进程内存当中,所以简单说一次I/O就是把数据从内核空间中的内存数据复制到用户空间中进程的内存当中的整个过程。 而网络通信就是从网络协议栈到用户空间进程的I/O,也就是网络I/O。
磁盘I/O是进程向内核发起系统调用,请求磁盘上的某个资源比如是文件或者是图片,然后内核通过相应的驱动程序将目标图片加载到内核的内存空间,加载完成之后把数据从内核内存再复制给进程内存,如果是比较大的数据也需要等待时间。
每次I/O,都要经由两个阶段: 第一步:将数据从磁盘文件先加载至内核内存空间(缓冲区), 此步骤需要等待数据准备完成,时间较长 第二步:将数据从内核缓冲区复制到用户空间的进程的内存中,时间较短
I/O模型 系统I/O 同步/异步 关注的是事件处理的消息通信机制,即在等待一件事情的处理结果时,被调用者是否提供完成通知。
同步: synchronous, 调用者等待被调用者返回消息后才能继续执行,如果被调用者不提供消息返回则为同步,同步需要调用者主动询问事情是否处理完成。
进程发出请求调用后,内核不提供通知机制,即文件I/O处理完成后不通知进程,需要进程自己去问内核是否处理完成。
异步: asynchronous, 被调用者通过状态、通知或回调机制主动通知调用者,即异步会主动返回被调用者的状态给调用者。
进程发出请求调用后,内核会在调用处理完成后返回调用结果给进程,Nginx是异步的。
阻塞/非阻塞 关注调用者在等待结果返回之前所处的状态
阻塞: blocking,指I/O操作需要彻底完成后才返回到用户空间,调用结果返回之前,调用者被挂起,干不了别的事情。
非阻塞: nonblocking, 指I/O操作被调用后立即返回给用户一个状态值,无需等到I/O操作彻底完成,最终的调用结果返回之前,调用者不会被挂起,可以去做别的事情。
系统IO模型组合 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 以我去吃饭为例:我点了10个包子 同步与异步: 我点包子之后厨师是否告诉我: 同步:厨师做好包子后会放到指定位置,但是做好包子之前需要自己一次次去看包子做好没有,厨师不会在包子做好之后通知我。 异步:厨师做好包子后告诉我包子做好放哪了。 阻塞与非阻塞: 我点包子后的状态: 阻塞:在厨师做包子期间一直在包子盘子前面等着,不能干别的事情。 非阻塞:点完包子就可以去干别的事情,比如去逛逛街或者买买买。 IO模型组合: 同步阻塞:我点完包子后不能去做别的事情,而且不知道包子有没有做好,需要自己一直等着并一次次的问厨师做好没有。 同步非阻塞:点完包子后可以去做别的事情,但是不能长时间做别的事情,因为我还是不知道包子有没有做好,也要自己一直等着并一次次的问厨师做好没有,只能抽空做点别的。 异步阻塞:我点完包子后不能去做别的事情,但是厨师在做好包子后会告诉我,也就是我不用再一次次问厨师包子有没有做好了。 异步非阻塞:我点完包子后可以做别的事情,而且可以一直在做别的去事情,因为厨师在做好包子后会告诉我。
网络I/O 阻塞型、非阻塞型、复用型、信号驱动型、异步
同步阻塞型I/O(blocking IO) 阻塞I/O模型是最简单的I/O模型,用户线程在内核进行I/O操作时被阻塞
1 2 用户请求到达系统服务进程,然后进程通过系统调用read( )向内核发起IO读操作,即将用户请求由用户空间转到内核空间,内核接收到I/O请求后开始从磁盘读取文件到内核内存,即在等用户请求的文件从磁盘到达内核内存后,然后将接收的数据拷贝到用户空间,然后完成read操作。 用户请求需要等待内核将数据读取到进程内存后,处理用户的进程才可以继续处理该请求,整个I/O请求的过程中,请求进程是被阻塞的,这导致进程在发起I/O请求时,不能做任何事情,而且对CPU的资源利用率不够。
优点:程序简单,在阻塞等待数据期间进程挂起,基本不会占用CPU资源 缺点:每个连接需要独立的进程单独处理,当并发请求量大时为了维护程序,内存、进程切换开销较大,apache的prefork使用的是这种模式。
1 同步阻塞:程序向内核发送I/O请求后一直等待内核响应,如果内核处理请求的I/O操作不能立即返回,则进程将一直等待并不再接受新的请求,并由进程轮询查看I/O是否完成,完成后进程将I/O结果返回给Client,在IO没有返回期间进程不能接受其他客户的请求,而且是有进程自己去查看I/O是否完成,这种方式简单,但是比较慢,用的比较少。
同步非阻塞型I/O(nonblocking IO) 用户请求进程向内核发起I/O请求时立即返回,但并未读取到任何数据,进程需要不断地发起I/O请求,直到数据到达进程空间的内存后,才真正读取到数据并继续执行,即前期需要一次次 “轮询”去查看请求是否数据是否准备报,但是此机制存在两个问题: 1.如果有大量文件描述符都要等,那么就得一个一个的read,这会带来大量的ContexSwitch (read是系统调用, 每调用一次就得在用户态和核心态切换一次) , 2.轮询的时间不好把握,这里是要猜多久之后数据才能到,等待时间设的太长,程序响应延迟就过大,但是设的太短,就会造成过于频繁的重试,干耗CPU而已,所以是比较浪费CPU的方式,因此一般很少直接使用这种模型,而是在其他IO模型中使用非阻塞I/O这一特性。
I/O多路复用型(IO multiplexing) I/O multiplexing就是我们说的select, poll, epoll, 有些地方也称这种I/O方式为event driven I/O(事件驱动I/O), select/poll/epoll的好处就在于单个process就可以同时处理多个网络连接的I/O。它的基本原理就是select, poll,epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。 当用户进程调用了select,那么整个进程会被block,而同时,kernel会”监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回, 这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。
1 Apache prefork是此模式的主进程+多进程/单线程+select, work是主进程+多进程/多线程+poll模式
信号驱动式IO(signal-driven IO) 用户进程可以通过sigaction系统调用注册一个信号处理程序,然后进程可以继续向下执行,当有IO操作准备就绪时,由内核通知触发一个SIGIO信号处理程序执行,然后将用户进程所需要的数据从内核空间拷贝到用户空间,此模型的优势在于等待数据报到达期间进程不被阻塞,进程可以继续执行,只要等待来自信号处理函数的通知。
优点:进程没有在等待数据时被阻塞,内核直接返回调用接收信号,不影响进程继续处理其他请求因此可以提高资源的利用率
缺点:信号IO在大量IO操作时可能会因为信号队列溢出导致没法通知
1 异步阻塞进程向内核发送IO调用后,不用等待内核响应,可以继续接受其他请求,内核收到进程请求后进行的IO如果不能立即返回,就由内核等待结果,直到IO完成后内核再通知进程,apache event模型就是主进程+多进程/多线程+信号驱动
异步非阻塞IO(asynchronous) 相对于同步IO,异步IO不是顺序执行,用户进程进行aio_read系统调用之后,无论内核数据是否准备好,都会直接返回给用户进程,然后用户态进程可以去做别的事情,等到socket数据准备好了,内核直接复制数据给进程,然后从内核向进程发送通知,异步非阻塞IO的两个阶段,进程都是非阻塞的。 Linux提供了AIO库函数实现异步,但是用的很少,目前有很多开源的异步IO库,例如libevent、 libev、 libuv等, 异步过程如下图所示:
1 异步非阻塞:程序进程向内核发送IO调用后,不用等待内核响应,可以继续接受其他请求,内核调用的IO如果不能立即返回,内核会继续处理其他事物,直到IO完成后将结果通知给内核,内核再将IO完成的结果返回给进程,期间进程可以接受新的请求,内核也可以处理新的事物,因此相互不影响,可以实现较大的同时并实现较高的IO复用,因此异步非阻塞使用最多的一种通信方式,nginx就是是异步非阻塞模型。
IO对比 这五种网络I/O模型中,越往后,阻塞越少,理论上效率也是最优前四种属于同步I/O,因为其中真正的I/O操作 (recvfrom)将阻塞进程/线程,只有异步I/O模型才与POSIX定义的异步I/O相匹配。
实现方式 Nginx支持在多种不同的操作系统实现不同的事件驱动模型,但是其在不同的操作系统甚至是不同的系统版本上面的实现方式不尽相同,主要有以下实现方式:
1、select: select库是在linux和windows平台都基本支持的事件驱动模型库,并且在接口的定义也基本相同,只是部分参数的含义略有差异,最大井发限制1024,是最早期的事件驱动模型。 2、poll: 在Linux的基本驱动模型,windows不支持此驱动模型,是select的升级版,取消了最大的并发限制,在编译nginx的时候可以使用–with-poll_ module和–without-poll_module这两个指定是否编译select库。 3、epoll: epoll库是Nginx服务器支持的最高性能的事件驱动库之一, 是公认的非常优秀的事件驱动模型,它和select和poll有很大的区别,epoll是poll的升级版, 但是与poll的效率有很大的区别. epoll的处理方式是创建一个待处理的事件列表,然后把这个列表发给内核,返回的时候在去轮询检查这个表,以判断事件是否发生,epoll支持一个进程打开的最大事件描述符的上限是系统可以打开的文件的最大数,同时epoll库的IO效率不随描述符数目增加而线性下降,因为它只会对内核上报的“活跃”的描述符进行操作。 4、rtsig: 不是一个常用事件驱动,最大队列1024,不是很常用 5、kqueue: 用于支持BSD系列平台的高效事件驱动模型,主要用在FreeBSD 4. 1及以上版本、openBSD 2。0级以上版本,NetBSD级以上版本及Mac os x平台上,该模型也是poll库的变种,因此和epoll没有本质上的区别,都是通过避免轮训操作提供效率。 6、/dev/poll: 用于支持unix衍生平台的高效事件驱动模型,主要在Solaris平台、HP/UX, 该模型是sun公司在开发Solaris系列平台的时候提出的用于完成事件驱动机制的方案,它使用了虚拟的/dev/pol1设备,开发人员将要见识的文件描述符加入这个设备,然后通过ioctl( )调用来获取事件通知,因此运行在以上系列平台的时候请使用/ dev/poll事件驱动机制 7、eventport: 该方案也是sun公司在开发Solaris的时候提出的事件驱动库,只是Solaris 10以上的版本,该驱动库看防止内核崩溃等情况的发生。 8、Iocp: Windows系统上的实现方式,对应第5种(异步I/0) 模型。
常用模型汇总
\
select
poll
epoll
操作方式
遍历
遍历
回调
底层实现
数组
链表
哈希表
IO效率
每次调用都进行线性遍历,时间复杂度为O(n)
每次调用都进行线性遍历,时间复杂度为O(n)
事件通知方式,每当fd就绪,系统注册的回调函数就会被调用,将就绪fd放到rdllist里面,时间复杂度为O(1)
最大连接数
1024(x86)或2048(x64)
无上限
无上限
fd拷贝
每次调用select,都需要把fd集合从用户态拷贝到内核态
每次调用poll,都需要把fd集合从用户态拷贝到内核态
调用epoll_ctl时拷贝进内核并保存,之后每次epoll_wait不拷贝
常用模型通知对比
水平触发–多次通知,需要关心数据是否取完,即数据取走之后即不再通知进程,以避免重复多次无效通知,通知效率较低。
边缘触发–一次通知,需要关心数据是否取走,即只通知一次怎么保证数据被进程成功取走了,以避免数据丢失,通知效率较高。
1 2 3 4 5 6 7 8 select: POSIX所规定,目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理 缺点 单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,可以通过修改宏定义FD_ SETSIZE, 再重新编译内核实现,但是这样也会造成效率的降低。 单个进程可监视的fd数量被限制,默认是1024, 修改此值需要重新编译内核。 对socket是线性扫描,即采用轮询的方法,效率较低。 select采取了内存拷贝方法来实现内核将FD消息通知给用户空间,这样一个用来存放大量fd的数据结构, 这样会 使得用户空间和内核空间在传递该结构时复制开销大。
1 2 3 4 5 poll: 本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态。 其没有最大连接数的限制,原因是它是基于链表来存储的。 大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。 poll特点是"水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd。
1 2 3 4 5 6 7 8 epoll: 在Linux 2.6内核中提出的select和poll的增强版本。 支持水平触发LT和边缘触发ET,最大的特点在于边缘触发,它只告诉进程哪些fd刚刚变为就绪态,并且只会通知一次 使用“事件"的就绪通知方式,通过epoll_ctl注册fd, 一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fd, epoll_wait便可以收到通知。 优点: 没有最大并发连接的限制:能打开的FD的上限远大于1024(1G的内存能监听约10万个端口),具体查看/proc/sys/fs/file-max,此值和系统内存大小相关 效率提升:非轮询的方式,不会随着FD数目的增加而效率下降;只有活跃可用的FD才会调用callback函数,即epoll最大的优点就在于它只管理“活跃"的连接,而跟连接总数无关 内存拷贝,利用mmap(Memory Mapping)加速与内核空间的消息传递;即epoll使用mmap减少复制开销
MMAP介绍 mmap(memory mapping)系统调用使得进程之间通过映射同一个普通文件实现共享内存,普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问。
传统方式拷贝数据
mmap方式
Nginx基础 Nginx: engineX, 2002年开始开发,2004年开源,2019年3月11日, Nginx公司被E5 Networks以6.7亿美元收 购,Nginx官网: http://nginx.org , Nginx商业版为Nginx Plus: https://www.nginx.com/products/nginx/ Nginx则是免费的、开源的、高性能的HTTP和反向代理服务器、邮件代理服务器、以及TCP/UDP代理 服务器 解决C10K问题(10K Connections) , http://www.ideawu.net/blog/archives/740.html Nginx的其它的二次发行版:
Tengine:由淘宝网发起的Web服务器项目。它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性,Tengine的性能和稳定性已经在大型的网站如淘宝网,天猫商城等得到了很好的检验,它的最终目标是打造一个高效、稳定、安全、易用的Web平台,从2011年12月开始,Tengine成为一个开源项目,官网http://tengine.taobao.org/
OpenResty:基于Nginx与Lua语言的高性能Web平台,章亦春团队开发,官网: http://openresty.org/cn/
Nginx功能介绍
静态的web资源服务器html,图片, js, css, txt等静态资源
结合FastCGI/uWSGI/SCGI等协议反向代理动态资源请求
http/https协议的反向代理
imap4/pop3协议的反向代理
tcp/udp协议的请求转发(反向代理)
基础特性
特性:
模块化设计,较好的扩展性
高可靠性
支持热部署:不停机更新配置文件,升级版本,更换日志文件
低内存消耗: 10000个keep- alive连接模式下的非活动连接,仅需2. 5M内存
event - driven, aio, mmap, sendfile
基本功能:
静态资源的web服务器
http协议反向代理服务器
pop3/ imap4协议反向代理服务器
FastCGI(LNMP), UWSGI (python)等协议
模块化(非DSO) ,如zip, SSL模块
和web相关的功能
虚拟主机(server)
支持keep-alive和管道连接(利用一个连接做多次请求)
访问日志(支持基于日志缓冲提高其性能)
url rewirte
路径别名
基于IP及用户的访问控制
支持速率限制及并发数限制
重新配置和在线升级而无须中断客户的工作进程
Nginx组织结构 web请求处理机制:
多进程方式: 服务器每接收到一个客户端请求就有服务器的主进程生成一个子进程响应客户端,直到用户关闭连接,这样的优势是处理速度快,各子进程之间相互独立,但是如果访问过大会导致服务器资源耗尽而无法提供请求。
多线程方式: 与多进程方式类似,但是每收到一个客户端请求会有服务进程派生出一个线程来个客户方进行交互,一个线程的开销远远小于一个进程,因此多线程方式在很大程度减轻了web服务器对系统资源的要求,但是多线程也有自己的缺点,即当多个线程位于同一个进程内工作的时候,可以相互访问同样的内存地址空间,所以他们相互影响,另外一旦主进程挂掉则所有子线程都不能工作了,IIS服务器使用了多线程的方式,需要间隔一段时间就重启一次才能稳定。
组织模型 Nginx是多进程组织模型,而且是一个由Master主进程和Worker工作进程组成。
主进程(master process)的功能
读取Nginx配置文件并验证其有效性和正确性
建立、绑定和关闭socket连接
按照配置生成、管理和结束工作进程
接受外界指令,比如重启、升级及退出服务器等指令
不中断服务,实现平滑升级,重启服务并应用新的配置
开启日志文件,获取文件描述符
不中断服务,实现平滑升级,升级失败进行回滚处理
编译和处理perl脚本
工作进程(work process)的功能
接受处理客户的请求
将请求以此送入各个功能模块进行处理
IO调用,获取相应数据
与后端服务器通信,接收后端服务器的处理结果
缓存数据,访问缓存索引,查询和调用缓存数据
发送请求结果,响应客户的请求
接收主程序指令,比如重启、升级和退出等
进程间通信 工作进程是有主进程生成的,主进程使用fork()函数,在Nginx服务器启动过程中主进程根据配置文件决定启动工作进程的数量,然后建立一张全局的工作表用于存放当前未退出的所有的工作进程,主进程生成工作进程后会将新生成的工作进程加入到工作进程表中,并建立一个单向的管道并将其传递给工作进程,该管道与普通的管道不同,它是由主进程指向工作进程的单向通道,包含了主进程向工作进程发出的指令、工作进程ID、工作进程在工作进程表中的索引和必要的文件描述符等信息。
主进程与外界通过信号机制进行通信,当接收到需要处理的信号时,它通过管道向相关的工作进程发送正确的指令,每个工作进程都有能力捕获管道中的可读事件,当管道中有可读事件的时候,工作进程就会从管道中读取并解析指令,然后采取相应的执行动作,这样就完成了主进程与工作进程的交互。
工作进程之间的通信原理基本上和主进程与工作进程之间的通信是一样的,只要工作进程之间能够取得彼此的信息,建立管道即可通信,但是由于工作进程之间是完全隔离的,因此一个进程想要知道另外一个进程的状态信息就只能通过主进程来设置了。为了实现工作进程之间的交互,主进程在生成工作进程之后,在工作进程表中进行遍历,将该新进程的ID以及针对该进程建立的管道句柄传递给工作进程中的其他进程,为工作进程之间的通信做准备,当工作进程1向工作进程2发送指令的时候,首先在主进程给它的其他工作进程工作信息中找到2的进程ID,然后将正确的指令写入指向进程2的管道,工作进程2捕获到管道中的事件后,解析指令并进行相关操作,这样就完成了工作进程之间的通信。
Nginx模块介绍
核心模块:是Nginx服务器正常运行必不可少的模块,提供错误日志记录、配置文件解析、事件驱动机制、 进程管理等核心功能
标准HTTP模块:提供HTTP协议解析相关的功能,比如:端口配置、网页编码设置、HTTP响应头设置等等
可选HTTP模块:主要用于扩展标准的HTTP功能,让Nginx能处理一些特殊的服务, 比如: Flash 多媒体传输、解析GeolP请求、网络传输压缩、安全协议SSL支持等
邮件服务模块:主要用于支持Nginx的邮件服务,包括对POP3协议、IMAP 协议和SMTP协议的支持
第三方模块:是为了扩展Nginx服务器应用,完成开发者自定义功能,比如: Json 支持、Lua 支持等
nginx高度模块化,但其模块早期不支持DSO机制; 1.9.11版本支持动态装载和卸载
Nginx安装 Nginx的安装版本分为Mainline version(主要开发放本,其实就是还处于开发版)。Stable version(当前最新稳定版)和Legacy versions(旧的稳定版),Nginx安装可以使用yum或源码安装,但是推荐使用源码,一是yum的版本比较旧,二是编译安装可以更方便自定义相关路径,三是使用源码编译可以自定义相关功能,更方便业务的上的使用。源码安装需要提前准备标准的编译器,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模块) 和openssI (支持ssl模块)等。
Nginx yum安装 Install the prerequisites:
To set up the yum repository, create the file named /etc/yum.repos.d/nginx.repo
with the following contents:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 [nginx-stable] name=nginx stable repo baseurl=http://nginx.org/packages/centos/$releasever /$basearch / gpgcheck=1 enabled=1 gpgkey=https://nginx.org/keys/nginx_signing.key module_hotfixes=true [nginx-mainline] name=nginx mainline repo baseurl=http://nginx.org/packages/mainline/centos/$releasever /$basearch / gpgcheck=1 enabled=0 gpgkey=https://nginx.org/keys/nginx_signing.key module_hotfixes=true
By default, the repository for stable nginx packages is used. If you would like to use mainline nginx packages, run the following command:
1 yum-config-manager --enable nginx-mainline
To install nginx, run the following command:
When prompted to accept the GPG key, verify that the fingerprint matches 573B FD6B 3D8F BC64 1079 A6AB ABF5 BD82 7BD9 BF62
, and if so, accept it.
Nginx编译安装 下载源码包http://nginx.org/en/download.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 [root@s2 -] [root@s2 src] [root@s2 src] [root@s2 src] 编译是为了检查系统环境是否符合编译安装的要求,比如是否有gcc编译工具,是否支持编译参数当中的模块,并根据 开启的参数等生成Makefile文件为下一一步做准备: [root@s2 nginx-1.18.1] --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@s2 nginx-1.18.1] [root@s2 nginx-1.18.1] [root@s2 nginx-1.18.1] [root@s2 nginx-1.18.1]
备注: nginx完成安装以后,有四个主要的目录:
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二进制启动脚本,可以接受不同的参数以实现不同的功能。
验证版本及编译参数
1 2 3 4 5 6 7 8 [root@s2 nginx-1.16.1] nginx version: nginx/1.16.1 built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) built with openSSL 1.0.2k-fips 26 Jan 2017 TLS SNI support enabled configure arguments: --prefix=/apps/nginx --user=nginx --group=nginx --with- http_ssl_module --with-http_v2_module --with-http_realip_module --with- http_stub_status module --with-http_gzip_static_module --with-pcre --with-streamwith-stream_ssl_module --with-stream_realip_module
创建Nginx自启动脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 [root@s1 ~] [Unit] Description=The nginx HTTP and reverse proxy server After=network.target remote-fs.target nss-lookup.target [Service] Type=forking PIDFile=/run/nginx.pid ExecstartPre=/usr/bin/rm -f /run/nginx. pid ExecStartPre=/apps/nginx/sbin/nginx -t ExecStart=/apps/nginx/sbin/nginx ExecReload=/bin/kill -S HUP $MAINPID Killsignal=SIGQUIT TimeoutStopSec=5 KillMode=process PrivateTmp=true [Install] WantedBy=multi-user.target
Nginx核心配置详解 默认配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 [root@s2 -] user nginx nginx; worker_processes 1; events { worker_connections 1024; http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_ timeout 65; server { listen 80; server_name localhost; location / { root html; index index.html index.htm; } error_ page 500 502 503 504 /50x.html;
全局配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 user nginx nginx; worker_processes [number| auto]; worker_cpu_affinity [0000001 0000010 0000100 00001000 | auto ]; [root@s2 ~]#ps axo pid, cmd, psr,user | grep nginx 4106 nginx: master process / apps 1 root 4181 nginx: worker process θ nginx 4182 nginx: worker process 1 nginx 4184 grep --color-auto nginx θ root error_log /apps/nginx/logs/error.log error ;pid /apps/nginx/logs/nginx.pid; worker_priority 0 ; worker_rlimit_nofile 65536 ; [root@s2 ~]# watch -n1 'ps -axo pid, cmd,nice I grep nginx' #验证进程优先级 daemon off ; master_process off |on ; events { worker_connections 65536 ; use epoll ; accept_mutex on ; multi_accept on ;
http详细配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 http { include mime .types; default_type application/octet-stream; sendfile on ; keepalive_timeout 65 ; server { listen 80 ; server_name localhost; location / { root html; index index.html index.htm; location ~ /passwd.html { deny all; } }
核心配置示例 root和alias root:指定web的家目录,在定义location的时候,文件的绝对路径等于root+location,如:
1 2 3 4 5 6 7 8 9 10 11 12 13 server { listen 80 ; server_name www.kinmfer.com location / { root /data/nginx/html/pc ; } location /about { root /data/nginx/html/pc; index index.html; } [root@s2 ~]# mkdir /data/nginx/html/pc/about [root@s2 ~]# echo about > /data/nginx/html/pc/about/index.html 重启Nginx并访问测试
alias:定义路径别名,会把访问的路径重新定义到其指定的路径,如:
1 2 3 4 5 6 7 8 9 server { listen 80 ; server_name www.kinmfer.com; location /about { alias /data/nginx/html/pc; index index .html; } 重启Nginx并访问测试 http://www.kinmfer.com/about/index.html #访问指定文件资源
location的详细使用 在没有使用正则表达式的时候,nginx会先在server中的多个location选取匹配度最高的一个uri, uri是用户请求的字符串,即域名后面的web文件路径,然后使用该location模块中的正则uri和字符串,如果匹配成功就结束搜索,并使用此location处理此请求。
1 2 3 4 5 6 7 8 9 10 11 语法规则: location [=|~|~*|^~] /uri/ { ... } = ~ !~ ~* !~* ^~ $ \ *
location优先级: (location =) > (location ^~ 路径) > (location ,* 正则顺序) > (location 部分起始路径) > (/)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 直接匹配网站根会加速Nginx访问处理: location = / { ..... : } location / { ......: } 静态资源配置: location ^~ /static/ { .... } location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ { ..... } 多应用配置 location ~* /app1 { ...... } location ~* /app2 { ...... }
Nginx四层访问控制 访问控制基于模块ngx_http_access_module实现,可以通过匹配客户端源IP地址进行限制。
1 2 3 4 5 6 7 8 9 location /about { alias /data/nginx/html/pc; index index.html; deny 192.168.1.1 ; allow 192.168.1.0 /24 ; allow 10.1.1.0 /16 ; allow 2001 :0db8::/32 ; deny all; }
Nginx账户认证功能 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [root@s2 ~] [root@s2 ~] [root@s2 ~] Adding password for user user1 [root@s2 -] Adding password for user user2 [root@s2 ~] user1:$apr $SRjm0u2Kr $VHvkAIc50Yg .3ZoaGwaGq/ user2:$apr1 $nIqnxoJBSLR9W1DTJT .viDJhXa6wHV. [root@s2 ~] location = /login/ { root /data/nginx/html/pc; index index.html; auth_basic "login password" ; auth_basic_user_file /apps/nginx/conf/.htpasswd; }
自定义错误页面 1 2 3 4 5 6 7 listen 80 ;server_name www.kinmfer.com;error_page 500 502 503 504 404 /error.html;location = /error.html { root html; } 重启nginx并访问不存在的页面进行测试
自定义访问日志 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [root@s2 -]# mkdir /data/nginx/logs listen 80 ; server_name www.kinmfer.com;error_page 500 502 503 504 404 /error.html; access_log /data/nginx/logs/www-kinmfer-com-access.log;error_log /data/nginx/logs/www-kinmfer-com-error .log;location = /error.html { root html; } 也可以单独放在location中 location = /error.html { root html; access_log /data/nginx/logs/www-kinmfer-com-access.log; error_log /data/nginx/logs/www-kinmfer-com-error .log; } 重启nginx并访问不存在的页面进行测试并验证是在指定目录生成新的日志文件
检测文件是否存在 try_files会按顺序检查文件是否存在,返回第一个找到的文件或文件夹 (结尾加斜线表示为文件夹),如果所有文件或文件夹都找不到,会进行一个内部重定向到最后一个参数。只有最后一个参数可以引起一个内部重定向,之前的参数只设置内部URI的指向。最后一个参数是回退URI且必须存在,否则会出现内部500错误。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 location /about { root /data/nginx/html/pc ; index index.html; try_files $uri $uri /index.html $uri .html =489; } [root@s2 ~] 重启nginx并测试,当访问到http://www.kinmfer.com/about/xx.html等不存在的uri会显示default,如果是自定义的状态码则会显示在返回数据的状态码中,如: [root@s2 about] HTTP/1.1 489 Server: nginx Date: Thu, 21 Feb 2019 00:11:40 GMT Content-Length: θ Connection: keep-alive Keep-Alive: timeout=65
长连接配置 keepalive_timeout number; #设定保持连接超时时长,0表示禁止长连接,默认为75s, 通常配置在http字段作 为站点全局配置
keepalive_requests number; #在一次长连接上所允许请求的资源的最大数量,默认为100次
keepalive_disable none | browser …;#对哪种浏览器禁用长连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 keepalive_requests 200; keepalive_timeout 65 60; 开启长连接后,返回客户端的会话保持时间为60s,单次长连接累计请求达到指定次数请求或65秒就会被断开,后面的 60为发送给客户端应答报文头部中显示的超时时间设置为60s:如不设置客户端将不显示超时时间。 Keep-Alive: timeout=60 如果设置为0表示关闭会话保持功能,将如下显示: Connection:close 使用命令测试: [root@s3 apps] Trying 172.18.200.102... Connected to www.kinmfer.com. Escape character is '^]' . GET / HTTP/1.1 HOST: www.kinmfer.com HTTP/1.1 200 OK Server: nginx/1.14.2 Date: Thu, 14 Mar 2019 17:23:46 GMT Content-Type: text/html Content-Length: 7 Last-Modified: Thu, 14 Mar 2020 14:54:50 GMT Connection: keep- alive Keep-Alive: timeout=60 ETag: "5c8a6b3a-7" Accept-Ranges: bytes pc web
作为下载服务器 1 2 3 4 5 6 7 8 9 10 11 [root@s2 about] [root@s2 about] location /download { root /data/nginx/html/pc; autoindex on; autoindex_exact_size on; autoindex_localtime on; [root@s2 pc] 重启Nginx并访问测试下载页面
作为上传服务器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 client_max_body_size 1m ; client_body_buffer_size size;client_body_temp_path path [level1 [level2 [1evel3]]];[root@s3 ~]# md5sum /data/nginx/html/pc/index.html 95f6f65f498c74938064851b1bb963d4 /data/nginx/html/pc/index.html 1级目录占1位16进制,即2^4=16个目录0-f 2级目录占2位16进制,即2^8=256个目录00-ff 3级目录占2位16进制,即28=256个目录00-ff 配置示例: client_max_body_size 10m ;client_body_buffer_size 16k ;client_body_temp_path /apps/nginx/temp 1 2 2 ;
其他配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 limit_except method ... { ... },仅用于location 限制客户端使用除了指定的请求方法之外的其它方法 method:GET, HEAD, POST, PUT, DELETE, MKCOL, COPY, MOVE, OPTIONS, PROPFIND,PROPPATCH,LOCK,UNLOCK,PATCH limit_except GET { allow 192.168.0.0 /24 ; allow 192.168.7.101 ; deny all; } [root@s2 about]# mkdir /data/nginx/html/pc/upload [root@s2 about]# echo "upload" > /data/nginx/html/pc/upload/index.html [root@s2 about]# vim /apps/nginx/conf/conf.d/pc.conf location /upload { root /data/kinmfer/pc; index index.html; limit_except GET { allow 172.18.200.101 ; deny all; } }
1 2 3 4 5 6 7 8 aio on | off linux 2 .6 以上内核提供以下几个系统调用来支持aio: 1 、SYS_io_setup:建立aio的context2 、SYS_io_submit: 提交I/O操作请求3 、SYS_i0_getevents:获取已完成的I/O事件4 、SYS_i0_cancel:取消I/O操作请求5 、SYS_i0_destroy: 毁销aio的context
1 2 3 4 5 6 7 8 9 open_file_cache off ; open_file_cache max=N [inactive=time];nginx可以缓存以下三种信息: (1)文件元数据:文件的描述符、文件大小和最近一次的修改时间 (2)打开的目录结构 (3)没有找到的或者没有权限访问的文件的相关信息 max=N:可缓存的缓存项上限数量;达到上限后会使用LRU(Least recently used, 最近最少使用)算法实现 管理 inactive=time:缓存项的非活动时长,在此处指定的时长内未被命中的或命中的次数少于open_file_cache_min_uses指令所指定的次数的缓存项即为非活动项,将被删除
1 2 3 open_file_cache_errors on | off ;是否缓存查找时发生错误的文件一类的信息 默认值为off
1 open_file_cache_min_uses number ;指令的inactive参数指定的时长内,至少被命中此处指定的次数方可被归类为活动项默认值为1
1 2 3 4 5 6 open_file_cache_valid time;缓存项有效性的检查验证频率,默认值为60s open_file_cache max=10000 inactive=60s ; open_file_cache_valid 60s ; open_file_cache_min_uses 5 ; open_file_cache_errors on ;
Nginx高级配置 Nginx状态页 在编译安装nginx的时候需要添加编译参数–with-http-stub-status-module,否则配置完成之后监测会是提示语法错误。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 配置示例: location /nginx_status { stub_status; access_log off ; allow 192.168.0.0 /16 ; allow 127.0.0.1 ; deny all; 状态页用于输出nginx的基本状态信息: 输出信息示例: Active connections: 291 server accepts handled requests 16630948 16630948 31070465 上面三个数字分别对应accepts, handled, requests三个值 Reading: 6 Writing: 179 waiting: 106 Active connections: 当前处于活动状态的客户端连接数, 包括连接等待空闲连接数。 accepts:统计总值,Nginx自启动后已经接受的客户端请求的总数。 handled:统计总值,Nginx自启动后已经处理完成的客户端请求的总数,通常等于accepts,除非有因 worker_connections限制等被拒绝的连接。 requests:统计总值,Nginx自启动后客户端发来的总的请求数。 Reading:当前状态,正在读取客户端请求报文首部的连接的连接数。 Writing:当前状态,正在向客户端发送响应报文过程中的连接数。 Waiting:当前状态,正在等待客户端发出请求的空闲连接数,开启keep-alive的情况下, 这个值等于active- (reading+writing),
Nginx第三方模块
第三模块是对nginx的功能扩展,第三方模块需要在编译安装Nginx的时候使用参数–add-module=PATH指定路径添加,有的模块是由公司的开发人员针对业务需求定制开发的,有的模块是开源爱好者开发好之后上传到github进行开源的模块,nginx支持第三方模块需要从源码重新编译支持,比如开源的echo模块https://github.com/openresty/echo-nginx-module :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 [root@s2 pc]# systemctl stop nginx [root@s2 pc]# vim /apps/nginx/conf/conf.d/pc.conf location /main { index index. html; default_type text/html; echo "hello world, main-->" ; echo_reset_timer ; echo_location /sub1; echo_location /sub2; echo "took $echo_timer_elapsed sec for total." ; } location /sub1 { echo_sleep 1 ; echo sub1; } location /sub2 { echo_sleep 1 ; echo sub2; } [root@s2 pc]# /apps/nginx/sbin/nginx -t nginx: [emerg] unknown directive "echo_reset_timer" in /apps/nginx/conf/conf.d/pc.conf:86 nginx: configuration file /apps/nginx/conf/nginx.conf test failed [root@s2 src]# yum install git -y [root@s2 src]# git clone https://github.com/openresty/echo-nginx-module.git [root@s2 src]# cd nginx-1.12.2/ [root@s2 src]# ./configure \ --prefix=/apps/nginx \ --user-nginx --group=nginx \ --with-http_ss1_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 \ --with-http_perl_module \ --add-module=/usr/local/src/echo-nginx-module [root@s2 src]# make && make install [root@s2 pc]# /apps/nginx/sbin/nginx -t nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok nginx: configuration file /apps/nginx/conf/nginx.conf test is successful [root@s2 pc]# systemctl restart nginx [root@s2 pc]# curl http://www.kinmfer.com/main hello world, main-->sub1 sub2 took 2 .010 sec for total.
Nginx变量使用 Nginx的变量可以在配置文件中引用,作为功能判断或者日志等场景使用,变量可以分为内置变量和自定义变量,内置变量是由nginx模块自带,通过变量可以获取到众多的与客户端访问相关的值。
内置变量
1 2 3 $document_uri ;http://www.kinmfer.com/main/index.do?id=20190221&partner-search会被定为/main/index.do
1 2 3 limit_rate 10240; echo $limit_rate ;
自定义变量 假如需要自定义变量名称和值,使用指令set $variable value;,则方法如下: Syntax: set $variable value; Default: - Context: server, location, if
1 2 3 4 5 set $name kinmfer;echo $name ; set $my_port $server_port ;echo $my_port ;echo "$server_name :$server_port " ;
Nginx自定义访问日志 访问日志是记录客户端即用户的具体请求内容信息,全局配置模块中的error_log是记录nginx服务器运行时的日志保存路径和记录日志的level, 因此有着本质的区别,而且Nginx的错误日志一般只有一个,但是访问日志可以在不同server中定义多个,定义一个日志需要使用access_log指定日志的保存路径,使用log_format指定日志的格式,格式中定义要保存的具体日志内容。
自定义默认格式 如果是要保留日志的源格式,只是添加相应的日志内容,则配置如下:
1 2 3 4 5 6 7 8 9 10 log_format nginx_format1 '$remote_addr - $remote_user [$time_local ] "$request " ' '$status $body_bytes_sent "$http_referer " ' "$http_user_agent " "$http_x_forwarded_for " ' ' $server_name :$server_port '; access_log logs/access.log nginx_format1; #重启nginx并访问测试日志格式 ==> /apps/nginx/logs/access.log <== 192.168.0.1.。[22/Feb/2019:08:44:14 +0800] "GET /favicon.ico HTTP/1.1”404 162 "。” "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rV:65.0) Gecko/2 0100101 Firefox/78.0" ". "www.kinmfer.com:80
自定义json格式日志 Nginx的默认访问日志记录内容相对比较单一, 默认的格式也不方便后期做日志统计分析,生产环境中通常将 nginx日志转换为json日志,然后配合使用ELK做日志收集-统计-分析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 log_format access_json '{"@timestamp " :"$time iso8601", ' '"host":"$server_addr ", ' '"clientip":"$remote_addr ", ' '"size":$body_bytes_sent , ' "responsetime" :$request_time , ' ' "upstreamtime" :"$upstream_response_time " , ' ' "upstreamhost" : "$upstream_addr " , ' ' "http_host" : "$host " , ' ' "uri" :"$uri " ,' domain": "$host ", ' '"xff":"$http_x_forwarded_for ", ' '"referer": "$http_referer ", ' "tcp_xff" : "$proxy_protocol_addr " , ' ' "http_user_agent" : "$http_user_agent " , ' ' "status" :"$status " }'; access_log /apps/nginx/1ogs/access_json.log access_json; #重启Nginx并访问测试日志格式 {"@timestamp " :"2019-02-22T08:55:32+08:00", "host":"192.168.7.102", "clientip":"192.168.0.1", "size" :162, "responsetime" :0.000, "upstreamtime":" -", "upstreamhost" :"-", "http_host" : "www.kinmfer.com" , "uri":"/favicon.ico" , "domain": "www.kinmfer.com" , "xff":"-", "referer":"-","tcp_xff":"", "http_user_agent" :"Mozilla/5.0 (Windows NT 6.1; Win64;x64; rv:65.0) Gecko/20100101 Firefox/65", "status":"404"}
json格式的日志访问统计 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 status_200= [] status_404= [] with open ("access_ json.log" ) as f: for line in f.readlines(): line = eval (line) if line.get("status" ) == "200" : status_200.append(line.get) elif line.get("status" ) == "404" : status_404.append(line.get) else : print("状态码ERROR" ) print ("状态码200的有--:" , len (status_200))print ("状态码404的有--:" , len (status_404))[root@s2 -] 状态码200 的有--: 1910 状态码404 的有--: 13
Nginx压缩功能 Nginx支持对指定类型的文件进行压缩然后再传输给客户端,而且压缩还可以设置压缩比例,压缩后的文件大小将比源文件显著变小,这样有助于降低出口带宽的利用率,降低企业的IT支出,不过会占用相应的CPU资源。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 gzip on | off ;gzip_comp_level level;gzip_disable "MSIE [1-6]\." ;gzip_min_length 1k ;gzip_http_version 1 .0 | 1 .1 ;gzip_buffers number size;gzip_types mime-type ...:gzip_vary on | off ; [root@s2 pc]# cp /apps/nginx/logs/access.log /data/nginx/html/pc/test.html [root@s2 pc]# echo "test1" > /data/nginx/html/pc/test1.html #小于1k的文件测试是否会压缩 [root@s2 pc]# vim /apps/nginx/conf/nginx.conf gzip on ; gzip_comp_level 3 ;gzip_min_length 1k ;gzip_types text/plain application/javascript application/x-javascript text/cssapplication/xml text/javascript application/x-httpd-php image/jpeg image/gifimage/png; gzip_vary on ;重启Nginx并访问测试: [root@s2 pc]# curl --head --compressed http://www.kinmfer.com HTTP/1.1 200 OK Server: nginx Date: Thu, 21 Feb 2019 13:06:18 GMT Content-Type: text/html Content-Length: 7 Last-Modified: Tue, 19 Feb 2019 04:09:32 GMT Connection: keep- alive Keep-Alive: timeout=65 ETag: "5c6b817c-7" Accept-Ranges: bytes [root@s2 -]# curl --head - -compressed http://www.kinmfer.com/test.html HTTP/1.1 200 OK Server: nginx Date: Fri, 22 Feb 2019 01:52:23 GMT Content-Type: text/html Last-Modified: Thu, 21 Feb 2019 10:31:18 GMT Connection: keep-alive Keep-Alive: timeout=65 Vary: Accept-Encoding ETag: W/"5c6e7df6-171109" Content-Encoding: gzip #压缩传输
Https功能 Web网站的登录页面都是使用https加密传输的,加密数据以保障数据的安全,HTTPS能够加密信息,以免敏感 信息被第三方获取,所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTPS协议,HTTPS其实是有两部分组成: HTTP+SSL/TLS, 也就是在HTTP上又加了一层处理加密信息的模块。服务端和客户端的信息传 输都会通过TLS进行加密,所以传输的数据都是加密后的数据。
ssl配置参数 nginx的https功能基于模块ngx_https_ssl_module实现,因此如果是编译安装的nginx要使用参数ngx_https_ssl_module开启ssI功能,但是作为nginx的核心功能,yum安装的nginx默认就是开启的,编译安装的nginx需要指定编译参数–with-https_ssl_module开启。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ssl on | off ;ssl_certificate /path/to/file;ssl_certificate_key /path/to/file;ssl_protocols [SSLv2] [SSLv3] [TLSV1] [TLSV1.1 ] [TLSV1.2 ];ssl_session_cache off | none | [builtin[:size]] [shared:name:size]; off:关闭缓存 none:通知客户端支持ssl session cache, 但实际不支持 builtin[:size]:使用openSSL内建缓存,为每worker进程私有 [shared:name:size]:在各worker之间使用一个共享的缓存,需要定义一个缓存名称和缓存空间大小,一兆可以存储4000个会话信息,多个虚拟主机可以使用相同的缓存名称。 ssl_session_timeout time;
签署证书请看此篇博客:
https://kinmfer.github.io/2020/05/05/Linux%E5%9F%BA%E7%A1%80-14-%E5%8A%A0%E5%AF%86%E5%92%8C%E5%AE%89%E5%85%A8/#CA和申请证书
1 2 3 4 5 6 7 8 listen 80 ;listen 443 ssl;ssl_certificate /apps/nginx/certs/www.kinmfer.com.crt; ssl_certificate_key /apps/nginx/certs/www.kinmfer.com.key;ssl_session_cache shared:sslcache:20m ;ssl_session_timeout 10m ;
实现多域名https Nginx支持基于单个IP实现多域名的功能,并且还支持单IP多域名的基础之上实现HTTPS,其实是基于Nginx的SNI (Server Name Indication)功能实现,SNI是为了解决个Nginx服务器内使用一个IP绑定多个域名和证书的功能,其具体功能是客户端在连接到服务器建立SSL链接之前先发送要访问站点的域名(Hostname) , 这样服务器再根据这个域名返回给客户端一个合适的证书。
步骤与以上类似
关于favicon.ico favicon.ico文件是浏览器收藏网址时显示的图标,当客户端使用浏览器问页面时,浏览器会自己主动发起请求获取页面的favicon.ico文件,但是当浏览器请求的favicon.ico文件不存在时,服务器会记录404日志,而且浏览器也会显示404报错。
解决办法
1 2 3 4 5 6 7 8 9 10 11 location = /favicon.ico { root /data/nginx/html/pc/images; expires 90d ; }
安全选项 自定义Nginx版本号 更改Nginx源码信息并重新编译Nginx
1 2 49 static u_char ngx_http_server_string[] = "Server: kinmfer666" CRLF;
升级OpenSSL版本 心脏出血(英语: Heartbleed),也简称为心血漏洞,是一个出现在加密程序库OpenSSL的安全漏洞,该程序库广泛用于实现互联网的传输层安全(TLS) 协议。它于2012年被引入了软件中,2014年4月首次向公众披露。只要使用的是存在缺陷的OpenSSL实例,无论是服务器还是客户端,都可能因此而受到攻击。此问题的原因是在实现TLS的心跳扩展时没有对输入进行适当验证(缺少边界检查),因此漏洞的名称来源于”心跳”(heartbeat) 。该程序错误属于缓冲区过读,即可以读取的数据比应该允许读取的还多。
1 2 3 4 5 6 7 8 9 10 11 12 13 准备OpenSSL源码包: /usr/1ocal/src 编译安装Nginx并制定新版本OpenSSL路径: 验证并启动Nginx: nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
rewrite 功能 通过正则表达式的匹配来改变URI,可以同时存在一个或多个指令,按照顺序依次对URI进行匹配,rewrite主要是针对用户请求的URL或者是URI做具体处理。
用法:rewrite regex replacement [flag];
(1) rewrite flag
利用nginx的rewrite的指令,可以实现url的重新跳转,rewrtie有四种不同的flag,分别是redirect(临时重定向)、permanent(永久重定向)、break和last。其中前两种是跳转型的flag,后两种是代理型,跳转型是指由客户端浏览器重新对新地址进行请求,代理型是在WEB服务器内部实现跳转的。
1 2 3 4 redirect; #临时重定向,重写完成后以临时重定向方式直接返回重写后生成的新URL给客户端,由客户端重新发起请求;使用相对路径,或者http://或https://开头,状态码:302 permanent; #重写完成后以永久重定向方式直接返回重写后生成的新URL给客户端,由客户端重新发起请求,状态码:301 last; #重写完成后停止对当前URI在当前location中后续的其它重写操作,而后对新的URL启动新一轮重写检查,不建议在location中使用 break; #重写完成后停止对当前URL在当前location中后续的其它重写操作,而后直接跳转至重写规则配置块之后的其它配置;结束循环,建议在location中使用
(2) 临时重定向与永久重定向
1 2 3 4 5 6 location / { root /usr/local/nginx/html/pc; index index.html; rewrite / http://www.aaa.com permanent ; }
(3) last与break
1 2 3 4 5 6 7 8 9 10 11 12 13 location /break { rewrite ^/break/(.*) /test$1 break ; return 666 "break" ; } location /last { rewrite ^/last/(.*) /test$1 last ; return 888 "last" ; } location /test { return 999 "test" ; }
(4) 自动跳转https
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 server { listen 80 ; listen 443 ssl; ssl_certificate /usr/local/nginx/certs/www.aaa.com.crt; ssl_certificate_key /usr/local/nginx/certs/www.aaa.com.key; ssl_session_cache shared:sslcache:20m ; ssl_session_timeout 10m ; server_name www.aaa.com; location / { root html/aaa.com; index index.html index.htm; if ($scheme = http){ rewrite / https://www.aaa.com permanent ; } } } server { listen 80 default_server; server_name www.aaa.com; rewrite ^(.*)$ https://$server_name $1 permanent ; }
(5) 判断文件是否存在
1 2 3 4 5 6 7 8 9 例:当用户访问到公司网站的时输入了一个错误的URL,可以将用户重定向至官网首页 location / { root /usr/local/nginx/html/pc; index index.html; if (!-f $request_filename ) { rewrite (.*) http://www.aaa.net/index.html; } }
(6) 防盗链
防盗链基于客户端携带的referer实现,referer是记录打开一个页面之前记录是从哪个页面跳转过来的标记信息,如果别人只链接了自己网站图片或某个单独的资源,而不是打开了网站的整个页面,这就是盗链,referer就是之前的那个网站域名,正常的referer信息有以下几种:
1 2 3 4 5 none: #请求报文首部没有referer首部,比如用户直接在浏览器输入域名访问web网站,就没有referer信息。 blocked: #请求报文有referer首部,但无有效值,比如为空。 server_names: #referer首部中包含本主机名及即nginx 监听的server_name。 arbitrary_string: #自定义指定字符串,可使用*作通配符。 regular expression: #被指定的正则表达式模式匹配到的字符串,要使用~开头,例如:~.*\.aaa\.com
1 2 3 4 5 6 7 8 location ^~ /images { root /usr/local/nginx/pc; index index.html; valid_referers none blocked server_names *.aaa.com www.aaa.* api.online.test/v1/hostlist ~\.google\. ~\.baidu\.; if ($invalid_referer ) { return 403 ; } }
代理功能 Nginx除了可以在企业提供高性能的web服务之外,另外还可以将本身不具备的请求通过某种预定义的协议转发至其它服务器处理,不同的协议就是Nginx服务器与其他服务器进行通信的一种规范,主要在不同的场景使用以下模块实现不同的功能:
ngx_http_proxy_module: 将客户端的请求以http协议转发至指定服务器进行处理。 ngx_stream_proxy_module: 将客户端的请求以tcp协议转发至指定服务器处理。 ngx_http_fastcgi_module: 将客户端对php的请求以fastcgi协议转发至指定服务器助理。 ngx_http_uwsgi_module: 将客户端对Python的请求以uwsgi协议转发至指定服务器处理。
配置参数: proxy_pass; #用来设置将客户端请求转发给的后端服务器的主机,可以是主机名、IP地址:端口的方式,也可以代理到预先设置的主机群组;
1 2 3 4 5 6 location /web { index index.html; proxy_pass http://192.168.7.103:80; proxy_pass http://192.168.7.103:80/; }
(1) 正向代理配置
1 2 3 4 5 6 7 8 9 10 11 12 13 http { resolver 8.8.8.8 ; server { listen 8088 ; location / { proxy_pass http://$http_host $request_uri ; } } } export "http_proxy=http://[user]:[pass]@host :port/" 如:export http_proxy=http://192.168.145.27:8088
(2) 反向代理配置
1 2 3 4 5 6 7 8 9 10 11 server { listen 80 ; server_name www.xxx.net; location / { proxy_pass http://192.168.145.7:80/; } } location /web { proxy_pass http://192.168.7.103:80/; }
(3) 代理缓存功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 proxy_cache zone | off ; proxy_cache_key string; proxy_cache_valid [code ...] time; proxy_cache_valid 200 302 10m ;proxy_cache_valid 404 1m ;proxy_cache_path; #定义可用于proxy功能的缓存;Context:http proxy_cache_path path [levels=levels] [use_temp_path=on |off ]keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on |off ] [purger_files=number] [purger_sleep=time] [purger_threshold=time]; 例:在http配置定义缓存信息 proxy_cache_path /var/cache/nginx/proxy_cache levels=1 :2 :2 keys_zone=proxycache:20m inactive=120s max_size=1g ; proxy_cache proxycache;proxy_cache_key $request_uri ;proxy_cache_valid 200 302 301 1h ;proxy_cache_valid any 1m ;proxy_cache_use_stale; #在被代理的后端服务器出现哪种情况下,可直接使用过期的缓存响应客户端 proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | off ; proxy_cache_methods GET | HEAD | POST ...;proxy_set_header field value;Context: http, server, location proxy_set_header X-Real-IP $remote_addr ;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ;请求报文的标准格式如下: X-Forwarded-For: client1, proxy1, proxy2 [root@www ~]# vim /usr/local/nginx/conf/nginx.conf proxy_cache_path /usr/local/nginx/proxycache levels=1 :1 :1 keys_zone=proxycache:20m inactive=120s max_size=1g ; [root@www ~]# vim /usr/local/nginx/conf/conf.d/pc.conf location /web { proxy_pass http://192.168.27.7:80/; proxy_set_header clientip $remote_addr ; proxy_cache proxycache; proxy_cache_key $request_uri ; proxy_cache_valid 200 302 301 1h ; proxy_cache_valid any 1m ; }
(4) 添加头部报文信息
Syntax: add_header name value [always]; Default: — Context: http, server, location, if in location
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 add_header name value [always];add_header X-Via $server_addr ;add_header X-Cache $upstream_cache_status ;add_header X-Accel $server_name ;add_trailer name value [always];location /web { proxy_pass http://192.168.27.7:80/; proxy_set_header clientip $remote_addr ; proxy_cache proxycache; proxy_cache_key $request_uri ; proxy_cache_valid 200 302 301 1h ; proxy_cache_valid any 1m ; add_header X-Via $server_addr ; add_header X-Cache $upstream_cache_status ; add_header X-Accel $server_name ; }
负载均衡 (1) http的负载均衡-upstream
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 配置参数: upstream name { server address [parameters]; } weight=number #设置权重,默认为1 max_conns=number #给当前server设置最大活动链接数,默认为0表示没有限制 max_fails=number #对后端服务器连续监测失败多少次就标记为不可用 fail_timeout=time #对后端服务器的单次监测超时时间,默认为10秒 backup down resolve hash KEY consistent; hash $request_uri consistent; ip_hash; #源地址hash调度方法,基于的客户端的remote_addr(源地址)做hash计算,以实现会话保持
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 调度算法: rr: 轮询,默认的调度方式,将所有请求都按照时间顺序分配到不同的服务上; weight: 权重,指定每个服务的权重比例,weight和访问比率成正比; ip_hash: 指定负载均衡器按照基于客户端IP的分配方式,这个方法确保了相同的客户端的请求一直发送到相同的服务器,以保证session会话。这样每个访客都固定访问一个后端服务器,可以解决session不能跨服务器的问题; least_conn: 把请求转发给连接数较少的后端服务器。轮询算法是把请求平均的转发给各个后端,使它们的负载大致相同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高。这种情况下,least_conn这种方式就可以达到更好的负载均衡效果 fair: 按照服务器端的响应时间来分配请求,响应时间短的优先分配; url_hash: 按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,要配合缓存命中来使用。同一个资源多次请求,可能会到达不同的服务器上,导致不必要的多次下载,缓存命中率不高,以及一些资源时间的浪费;而使用url_hash,可以使得同一个url(也就是同一个资源请求)会到达同一台服务器,一旦缓存住了资源,再此收到请求,就可以从缓存中读取; 例: upstream webserver { server 192.168.27.7:80 weight=1 fail_timeout=5s max_fails=3 ; server 192.168.27.17:80 weight=1 fail_timeout=5s max_fails=3 backup; } server { listen 80 ; server_name www.aaa.net; location / { index index.html index.php; root /usr/local/nginx/html/pc; } location /web { index index.html; proxy_pass http://webserver/; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; } }
(2) tcp的负载均衡
Nginx在1.9.0版本开始支持tcp模式的负载均衡,在1.9.13版本开始支持udp协议的负载,udp主要用于DNS的域名解析,其配置方式和指令和http代理类似,其基于ngx_stream_proxy_module模块实现tcp负载,另外基于模块ngx_stream_upstream_module实现后端。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 配置参数: stream { upstream backend { hash $remote_addr consistent; server backend1.example.com:12345 weight=5 ; server 127.0.0.1:12345 max_fails=3 fail_timeout=30s ; server unix:/tmp/backend3; } upstream dns { server 192.168.0.1:53535 ; server dns.example.com:53 ; } server { listen 12345 ; 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; } } 实例1:Redis负载均衡 stream { upstream redis_server { server 192.168.145.27:6379 max_fails=3 fail_timeout=30s ; } server { listen 192.168.145.7:6379 ; proxy_connect_timeout 3s ; proxy_timeout 3s ; proxy_pass redis_server; } } 实例2:mysql负载均衡 stream { upstream mysql_server { least_conn; server 192.168.145.27:3306 max_fails=3 fail_timeout=30s ; } server { listen 192.168.145.7:3306 ; proxy_connect_timeout 6s ; proxy_timeout 15s ; proxy_pass mysql_server; } }
FastCGI配置 Nginx基于模块ngx_http_fastcgi_module实现通过fastcgi协议将指定的客户端请求转发至php-fpm处理,其配置参数如下:
1 2 3 4 5 6 7 8 fastcgi_pass address; fastcgi_index name; fastcgi_param parameter value [if_not_empty]; fastcgi_param REMOTE_ADDR $remote_addr ; fastcgi_param REMOTE_PORT $remote_port ; fastcgi_param SERVER_ADDR $server_addr ; fastcgi_param SERVER_PORT $server_port ; fastcgi_param SERVER_NAME $server_name ;
1 2 3 4 5 6 7 8 9 Nginx默认配置示例: location ~ \.php$ { root html; fastcgi_pass 127.0.0.1:9000 ; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name ; include fastcgi_params; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 fastcgi缓存定义: fastcgi_cache_path path [levels=levels] [use_temp_path=on |off ] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on |off ] [purger_files=number] [purger_sleep=time] [purger_threshold=time];path max_size=size levels=levels: keys_zone=name:size inactive=time fastcgi缓存调用: fastcgi_cache zone | off ; fastcgi_cache_key string; fastcgi_cache_methods GET | HEAD | POST ...; fastcgi_cache_min_uses number; fastcgi_keep_conn on | off ; fastcgi_cache_valid [code ...] time; fastcgi_hide_header field; fastcgi_pass_header field;
Nginx与php-fpm实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 (1) 安装php-fpm [root@www ~]# yum install php-fpm php-mysql -y [root@www ~]# systemctl start php-fpm (2) 准备php测试页 [root@www ~]# vim /usr/local/nginx/html/aaa.com/index.php <?php phpinfo(); ?> (3) nginx配置转发 [root@www ~]# vim /usr/local/nginx/conf/conf.d/aaa.conf server { listen 80 ; server_name www.aaa.com; location / { root html/aaa.com; index index.html index.htm; } location ~ \.php$ { root html/aaa.com; fastcgi_pass 127.0.0.1:9000 ; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root $fastcgi_script_name ; include fastcgi_params; } } (3) 重启nginx并使用浏览器测试 [root@www ~]# nginx -s reload php相关配置优化: [root@www ~]# grep "^[a-Z]" /etc/php-fpm.conf include=/etc/php-fpm.d/*.conf pid = /run/php-fpm/php-fpm.piderror_log = /var/log/php-fpm/error.log daemonize = yes [root@www ~] listen = 127.0.0.1:9000 listen.allowed_clients = 127.0.0.1 user = nginx group = nginx pm = dynamic pm.max_children = 500 pm.start_servers = 100 pm.min_spare_servers = 100 pm.max_spare_servers = 200 pm.max_requests = 500000 pm.status_path = /pm_status ping.path = /ping ping.response = ping-pong slowlog = /var/log/php-fpm/www-slow.log php_admin_value[error_log] = /var/log/php-fpm/www-error .log php_admin_flag[log_errors] = on php_value[session.save_handler] = files php_value[session.save_path] = /var/lib/php/session
系统参数优化 默认的Linux内核参数考虑的是最通用场景,不符合用于支持高并发访问的Web服务器的定义,根据业务特点来进行调整,当Nginx作为静态web内容服务器、反向代理或者提供压缩服务器的服务器时,内核参数的调整都是不同的,此处针对最通用的、使Nginx支持更多并发请求的TCP网络参数做简单的配置,修改/etc/sysctl.conf来更改内核参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 fs.file-max = 1000000 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_keepalive_time = 600 net.ipv4.tcp_fin_timeout = 30 net.ipv4.tcp_max_tw_buckets = 5000 net.ipv4.ip_local_port_range = 1024 65000 net.ipv4.tcp_rmem = 10240 87380 12582912 net.ipv4.tcp_wmem = 10240 87380 12582912 net.core.netdev_max_backlog = 8096 net.core.rmem_default = 6291456 net.core.wmem_default = 6291456 net.core.rmem_max = 12582912 net.core.wmem_max = 12582912 注意:以上的四个参数,需要根据业务逻辑和实际的硬件成本来综合考虑 net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_max_syn_backlog = 8192 net.ipv4.tcp_tw_recycle = 1 net.core.somaxconn=262114 net.ipv4.tcp_max_orphans=262114