Nginx面试题(史上最全 + 持续更新)

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

尼恩面试宝典专题39Nginx面试题史上最全、持续更新

本文版本说明V27

《尼恩面试宝典》升级规划为

后续基本上每一个月都会发布一次最新版本可以联系构师尼恩获取 发送 “领取电子书” 获取。

Nginx的并发能力在同类型网页服务器中的表现相对而言是比较好的因此受到了很多企业的青睐我国使用Nginx网站的知名用户包括腾讯、淘宝、百度、京东、新浪、网易等等。

Nginx是系统架构师、开发人员、网页服务器运维人员必备技能之一下面的面试题为大家提供系统化、体系化的学习资料 比一般的专业书籍更有价值

最新版本可以联系构师尼恩获取 发送 “领取电子书” 获取。

聊聊什么是Nginx?

Nginx是一个web服务器和反向代理服务器用于HTTP、HTTPS、SMTP、POP3和IMAP协议。

Nginx—Ngine X是一款免费的、自由的、开源的、高性能HTTP服务器和反向代理服务器

也是一个IMAP、POP3、SMTP代理服务器

Nginx以其高性能、稳定性、丰富的功能、简单的配置和低资源消耗而闻名。

也就是说Nginx本身就可以托管网站类似于Tomcat一样进行Http服务处理也可以作为反向代理服务器 、负载均衡器和HTTP缓存。

Nginx 解决了服务器的C10K就是在一秒之内连接客户端的数目为10k即1万问题。

它的设计不像传统的服务器那样使用线程处理请求而是一个更加高级的机制—事件驱动机制是一种异步事件驱动结构。

聊聊Nginx的一些特性。

Nginx服务器的特性包括

  • 反向代理/L7负载均衡器
  • 嵌入式Perl解释器
  • 动态二进制升级
  • 可用于重新编写URL具有非常好的PCRE支持

聊聊Nginx的优缺点

核心优点

  • 占内存小可实现高并发连接处理响应快
  • 可实现http服务器、虚拟主机、方向代理、负载均衡
  • Nginx配置简单
  • 可以不暴露正式的服务器IP地址

核心缺点

  • 动态处理差

nginx处理静态文件好,耗费内存少但是处理动态页面则很鸡肋

现在一般前端用nginx作为反向代理抗住压力。

聊聊Nginx应用场景

  • http服务器。

Nginx是一个http服务可以独立提供http服务。可以做网页静态服务器。

  • 虚拟主机。

可以实现在一台服务器虚拟出多个网站例如个人网站使用的虚拟机。

  • 反向代理负载均衡。

当网站的访问量达到一定程度后单台服务器不能满足用户的请求时需要用多台服务器集群可以使用nginx做反向代理。

并且多台服务器可以平均分担负载不会应为某台服务器负载高宕机而某台服务器闲置的情况。

nginz 中也可以配置安全管理、比如可以使用Nginx搭建API接口网关,对每个接口服务进行拦截。

聊聊使用“反向代理服务器”的优点是什么?

反向代理服务器可以隐藏源服务器的存在和特征。

它充当互联网云和web服务器之间的中间层。

这对于安全方面来说是很好的特别是当您使用web托管服务时。

聊聊什么是正向代理和反向代理

首先代理服务器一般指局域网内部的机器通过代理服务器发送请求到互联网上的服务器代理服务器一般作用在客户端。例如GoAgent翻墙软件。

我们的客户端在进行翻墙操作的时候我们使用的正是正向代理通过正向代理的方式在我们的客户端运行一个软件将我们的HTTP请求转发到其他不同的服务器端实现请求的分发。

反向代理服务器作用在服务器端它在服务器端接收客户端的请求然后将请求分发给具体的服务器进行处理然后再将服务器的相应结果反馈给客户端。Nginx就是一个反向代理服务器软件。

从上图可以看出客户端必须设置正向代理服务器当然前提是要知道正向代理服务器的IP地址还有代理程序的端口。

反向代理正好与正向代理相反对于客户端而言代理服务器就像是原始服务器并且客户端不需要进行任何特别的设置。客户端向反向代理的命名空间name-space中的内容发送普通请求接着反向代理将判断向何处原始服务器转交请求并将获得的内容返回给客户端。

聊聊反向代理好处

  1. 保护了真实的 web 服务器web 服务器对外不可见外网只能看到反向代理服务器而反向代理服务器上并没有真实数据因此保证了 web 服务器的资源安全。
  2. 反向代理为基础产生了动静资源分离以及负载均衡的方式减轻 web 服务器的负担加速了对网站访问速度。
  3. 节约了有限的 IP 地址资源企业内所有的网站共享一个在 internet 中注册的IP地址这些服务器分配私有地址采用虚拟主机的方式对外提供服务。

聊聊什么是Nginx? 它的优势和功能?

Nginx是一个web服务器和方向代理服务器用于HTTP、HTTPS、SMTP、POP3和IMAP协议。因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。
优点

1更快

这表现在两个方面一方面在正常情况下单次请求会得到更快的响应另一方面在高峰期如有数以万计的并发请求Nginx可以比其他Web服务器更快地响应请求。

2高扩展性跨平台

Nginx的设计极具扩展性它完全是由多个不同功能、不同层次、不同类型且耦合度极低的模块组成。因此当对某一个模块修复Bug或进行升级时可以专注于模块自身无须在意其他。而且在HTTP模块中还设计了HTTP过滤器模块一个正常的HTTP模块在处理完请求后会有一串HTTP过滤器模块对请求的结果进行再处理。这样当我们开发一个新的HTTP模块时不但可以使用诸如HTTP核心模块、events模块、log模块等不同层次或者不同类型的模块还可以原封不动地复用大量已有的HTTP过滤器模块。这种低耦合度的优秀设计造就了Nginx庞大的第三方模块当然公开的第三方模块也如官方发布的模块一样容易使用。
Nginx的模块都是嵌入到二进制文件中执行的无论官方发布的模块还是第三方模块都是如此。这使得第三方模块一样具备极其优秀的性能充分利用Nginx的高并发特性因此许多高流量的网站都倾向于开发符合自己业务特性的定制模块。

3高可靠性用于反向代理宕机的概率微乎其微

高可靠性是我们选择Nginx的最基本条件因为Nginx的可靠性是大家有目共睹的很多家高流量网站都在核心服务器上大规模使用Nginx。Nginx的高可靠性来自于其核心框架代码的优秀设计、模块设计的简单性另外官方提供的常用模块都非常稳定每个worker进程相对独立master进程在1个worker进程出错时可以快速“拉起”新的worker子进程提供服务。

4低内存消耗

一般情况下10 000个非活跃的HTTP Keep-Alive连接在Nginx中仅消耗2.5MB的内存这是Nginx支持高并发连接的基础。

5单机支持10万以上的并发连接

这是一个非常重要的特性

随着互联网的迅猛发展和互联网用户数量的成倍增长各大公司、网站都需要应付海量并发请求一个能够在峰值期顶住10万以上并发请求的Server无疑会得到大家的青睐。

理论上Nginx支持的并发连接上限取决于内存10万远未封顶。当然能够及时地处理更多的并发请求是与业务特点紧密相关的。

6热部署

master管理进程与worker工作进程的分离设计使得Nginx能够提供热部署功能即可以在7×24小时不间断服务的前提下升级Nginx的可执行文件。

当然它也支持不停止服务就更新配置项、更换日志文件等功能。

7最自由的BSD许可协议

这是Nginx可以快速发展的强大动力。

BSD许可协议不只是允许用户免费使用Nginx它还允许用户在自己的项目中直接使用或修改Nginx源码然后发布。这吸引了无数开发者继续为Nginx贡献自己的智慧。

以上7个特点当然不是Nginx的全部拥有无数个官方功能模块、第三方功能模块使得Nginx能够满足绝大部分应用场景这些功能模块间可以叠加以实现更加强大、复杂的功能有些模块还支持Nginx与Perl、Lua等脚本语言集成工作大大提高了开发效率。这些特点促使用户在寻找一个Web服务器时更多考虑Nginx。

选择Nginx的核心理由还是它能在支持高并发请求的同时保持高效的服务

聊聊为什么要用Nginx

  • 跨平台、配置简单、方向代理、高并发连接处理2-3万并发连接数官方监测能支持5万并发内存消耗小开启10个nginx才占150M内存 nginx处理静态文件好耗费内存少

  • 而且Nginx内置的健康检查功能如果有一个服务器宕机会做一个健康检查再发送的请求就不会发送到宕机的服务器了。重新将请求提交到其他的节点上。

  • 使用Nginx的话还能

    1. 节省宽带支持GZIP压缩可以添加浏览器本地缓存
    2. 稳定性高宕机的概率非常小
    3. 接收用户请求是异步的

聊聊请解释什么是C10K问题?

C10K问题是指无法同时处理大量客户端(10,000)的网络套接字。

聊聊C10K问题的本质和解决方案

什么是C10K问题

所谓 c10k 问题指的是服务器如何支持 10k 个并发连接也就是 concurrent 10000 connection这也是 c10k 这个名字的由来。

由于硬件成本的大幅度降低和硬件技术的进步如果一台服务器能够同时服务更多的客户端那么也就意味着服务每一个客户端的成本大幅度降低。从这个角度来看c10k 问题显得非常有意义。

C10K问题由来

互联网的基础是网络通信早期的互联网可以说是一个小群体的集合。互联网还不够普及用户也不多一台服务器同时在线 100 个用户在当时已经算是大型应用了所以并不存在 C10K 的难题。互联网的爆发期是在 www 网站、浏览器出现后。最早的互联网称之为 Web1.0大部分的使用场景是下载一个 HTML 页面用户在浏览器中查看网页上的信息这个时期也不存在 C10K 问题。

Web2.0 时代到来后就不同了。一方面是互联网普及率大大提高了用户群体几何倍增长。另一方面是互联网不再是单纯地浏览 www 网页逐渐开始进行交互而且应用程序的逻辑也变得更复杂。从简单的表单提交到即时通信和在线实时互动C10K 的问题才体现出来了。因为每一个用户都必须与服务器保持连接才能进行实时数据交互。诸如 Facebook 这样的网站同一时间的并发 TCP 连接很可能已经过亿。

早期的腾讯QQ也同样面临C10K问题只不过他们是用了UDP这种原始的包交换协议来实现的绕开了这个难题当然过程肯定是痛苦的。如果当时有 epoll 技术他们肯定会用 TCP。众所周之后来的手机 QQ、微信都采用 TCP 协议。
实际上当时也有异步模式如select/poll 模型。这些技术都有一定的缺点selelct 最大不能超过 1024poll 没有限制但每次收到数据时需要遍历每一个连接查看哪个连接有数据请求。

这时候问题就来了最初的服务器都是基于进程/线程模型的新到来一个 TCP 连接就需要分配 1 个进程或者线程。进程又是操作系统最昂贵的资源一台机器无法创建很多进程。如果是 C10K就要创建 1 万个进程那么就单机而言操作系统是无法承受的往往出现效率低下、甚至完全瘫痪。如果是采用分布式系统维持 1 亿用户在线需要 10 万台服务器成本巨大也只有 Facebook、Google、Apple 等巨头才有财力购买如此多的服务器。

基于上述考虑如何突破单机性能局限是高性能网络编程所必须要直面的问题。这些局限和问题最早被 Dan Kegel 进行了归纳和总结并首次系统地分析和提出了解决方案。后来这种普遍的网络现象和技术局限都被大家称为 C10K 问题。

C10K问题的本质

C10K 问题本质上是操作系统的问题。对于 Web1.0/2.0 时代的操作系统而言传统的同步阻塞 I/O 模型都是一样的处理的方式都是 requests per second并发 10K 和 100 的区别关键在于 CPU。

创建的进程、线程多了数据拷贝频繁缓存 I/O、内核将数据拷贝到用户进程空间、阻塞 进程/线程上下文切换消耗大 导致操作系统崩溃这就是 C10K 问题的本质

可见解决 C10K 问题的关键就是尽可能减少 CPU 等核心资源消耗从而榨干单台服务器的性能突破 C10K 问题所描述的瓶颈。

C10K问题的解决方案探讨

从网络编程技术的角度来说主要思路为

  1. 为每个连接分配一个独立的线程/进程。
  2. 同一个线程/进程同时处理多个连接IO 多路复用。

为每个连接分配一个独立的线程/进程

这一思路最为直接。但是由于申请进程/线程会占用相当可观的系统资源同时对于多进程/线程的管理会对系统造成压力因此这种方案不具备良好的可扩展性。

这一思路在服务器资源还没有富裕到足够程度的时候是不可行的。即便资源足够富裕效率也不够高。

总之此思路技术实现会使得资源占用过多可扩展性差在实际应用中已被抛弃。

同一个线程/进程同时处理多个连接IO多路复用

IO 多路复用从技术实现上又分很多种。我们逐一来看看下述各种实现方式的优劣。

实现方式1循环逐个处理各个连接每个连接对应一个 socket

循环逐个处理各个连接每个连接对应一个 socket。当所有 socket 都有数据的时候这种方法是可行的。但是当应用读取某个 socket 的文件数据不 ready 的时候整个应用会阻塞在这里等待该文件句柄 ready即使别的文件句柄 ready也无法往下处理。

实现小结直接循环处理多个连接。

问题归纳任一文件句柄的不成功会阻塞住整个应用。

实现方式2使用 select 方法

使用 select 方法解决上面阻塞的问题思路比较简单。在读取文件句柄之前先查下它的状态如果 ready 了就进行处理如果不 ready 就不进行处理这不就解决了这个问题了嘛于是有了 select 方案。用一个 fd_set 结构体来告诉内核同时监控多个文件句柄当其中有文件句柄的状态发生指定变化例如某句柄由不可用变为可用或超时则调用返回。

之后应用可以使用 FD_ISSET 来逐个查看确定哪个文件句柄的状态发生了变化。这样做小规模的连接问题不大但当连接数很多文件句柄个数很多的时候逐个检查状态就很慢了。因此select 往往存在管理的句柄上限FD_SETSIZE。同时在使用上因为只有一个字段记录关注和发生事件所以每次调用之前要重新初始化 fd_set 结构体。

intselect(intnfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,structtimeval *timeout);

实现小结有连接请求抵达了再检查处理。

问题归纳句柄上限+重复初始化+逐个排查所有文件句柄状态效率不高。

实现方式3使用 poll 方法

poll 主要解决 select 的前两个问题

  1. 通过一个 pollfd 数组向内核传递需要关注的事件以消除文件句柄上限。
  2. 使用不同字段分别标注 “关注事件和发生事件”来避免重复初始化。

实现小结设计新的数据结构提高使用效率。

问题归纳逐个排查所有文件句柄状态效率不高。

实现方式4使用 epoll 方法

既然 “poll 逐个排查所有文件句柄状态” 效率不高很自然的在调用返回的时候如果只给应用提供发生了状态变化很可能是数据 ready的文件句柄进行排查的效率就高很多。epoll 采用了这种设计适用于大规模的应用场景。实验表明当文件句柄数目超过10之后epoll 性能将优于 select 和 poll当文件句柄数目达到 10K 的时候epoll 已经超过 select 和 poll 两个数量级。

实现小结只返回状态变化的文件句柄。

问题归纳依赖特定平台Linux。

因为 Linux 是互联网企业中使用率最高的操作系统所以 Epoll 就成为 “C10K killer、高并发、高性能、异步非阻塞” 这些技术的代名词了。FreeBSD 推出了 kqueueLinux 推出了 epollWindows 推出了 IOCPSolaris 推出了 /dev/poll。这些操作系统提供的功能就是为了解决 C10K 问题。epoll 技术的编程模型就是异步非阻塞回调也可以叫做 Reactor、事件驱动、事件轮循EventLoop。Nginx、libevent、node.js 这些就是 Epoll 时代的产物。

实现方式5使用 libevent 库

由于 epoll,、kqueue、IOCP 每个接口都有自己的特点程序移植非常困难所以需要对这些接口进行封装以让它们易于使用和移植其中 libevent 库就是其中之一。跨平台封装底层平台的调用提供统一的 API但底层在不同平台上自动选择合适的调用。

按照 libevent 的官方网站libevent 库提供了以下功能当一个文件描述符的特定事件如可读可写或出错发生了或一个定时事件发生了libevent 就会自动执行用户指定的回调函数来处理事件。目前libevent 已支持以下接口 /dev/poll、kqueue、event ports、select、poll 和 epoll。Libevent 的内部事件机制完全是基于所使用的接口的。因此libevent 非常容易移植也使它的扩展性非常容易。目前libevent 已在以下操作系统中编译通过Linux、BSD、Mac OS X、Solaris 和 Windows。使用 libevent 库进行开发非常简单也很容易在各种 unix 平台上移植。

聊聊Nginx如何实现超高并发

面试官心理分析

主要是看应聘人员的对NGINX的基本原理是否熟悉因为大多数人多多少少都懂点NGINX但是真正其明白原理的可能少之又少。

明白其原理才能做优化否则只能照样搬样出了问题也无从下手。

懂皮毛的人一般会做个 Web Server搭建一个 Web 站点

初级运维可能搞个 HTTPS 、配置一个反向代理; 中级运维定义个 upstream、写个正则判断

老鸟做个性能优化、写个ACL还有可能改改源码。

面试题剖析

异步非阻塞使用了epoll 和大量的底层代码优化。

如果一个server采用一个进程负责一个request的方式那么进程数就是并发数。正常情况下会有很多进程一直在等待中。

而nginx采用一个master进程多个woker进程的模式。

  • master进程主要负责收集、分发请求。每当一个请求过来时master就拉起一个worker进程负责处理这个请求。
  • 同时master进程也负责监控woker的状态保证高可靠性
  • woker进程一般设置为跟cpu核心数一致。nginx的woker进程在同一时间可以处理的请求数只受内存限制可以处理多个请求。
  • Nginx 的异步非阻塞工作方式正把当中的等待时间利用起来了。在需要等待的时候这些进程就空闲出来待命了因此表现为少数几个进程就解决了大量的并发问题。

每进来一个request会有一个worker进程去处理。但不是全程的处理处理到什么程度呢处理到可能发生阻塞的地方比如向上游后端服务器转发request并等待请求返回。那么这个处理的worker很聪明他会在发送完请求后注册一个事件“如果upstream返回了告诉我一声我再接着干”。于是他就休息去了。

此时如果再有request 进来他就可以很快再按这种方式处理。而一旦上游服务器返回了就会触发这个事件worker才会来接手这个request才会接着往下走。

聊聊Nginx如何实现超高并发

Nginx 是一个高性能的 Web 服务器能够同时处理大量的并发请求。

它结合多进程机制和异步机制 异步机制使用的是异步非阻塞方式

接下来就给大家介绍一下 Nginx 的多线程机制和异步非阻塞机制。

1、多进程机制

服务器每当收到一个客户端时就有 服务器主进程 master process 生成一个 子进程 worker process 出来和客户端建立连接进行交互直到连接断开该子进程就结束了。

使用进程的好处是各个进程之间相互独立不需要加锁减少了使用锁对性能造成影响同时降低编程的复杂度降低开发成本。其次采用独立的进程可以让进程互相之间不会影响 如果一个进程发生异常退出时其它进程正常工作 master 进程则很快启动新的 worker 进程确保服务不会中断从而将风险降到最低。

缺点是操作系统生成一个子进程需要进行 内存复制等操作在资源和时间上会产生一定的开销。当有大量请求时会导致系统性能下降 。

2、异步非阻塞机制

每个工作进程 使用 异步非阻塞方式 可以处理 多个客户端请求 。

当某个 工作进程 接收到客户端的请求以后调用 IO 进行处理如果不能立即得到结果就去 处理其他请求 即为 非阻塞 而 客户端 在此期间也 无需等待响应 可以去处理其他事情即为 异步 。

当 IO 返回时就会通知此 工作进程 该进程得到通知暂时 挂起 当前处理的事务去 响应客户端请求 。

聊聊请解释Nginx服务器上的Master和Worker进程分别是什么?

  • 主程序 Master process 启动后通过一个 for 循环来 接收 和 处理外部信号
  • 主进程通过 fork() 函数产生 worker 子进程 每个子进程执行一个 for循环来实现Nginx服务器对事件的接收和处理 。

一般推荐 worker 进程数与CPU内核数一致这样一来不存在大量的子进程生成和管理任务避免了进程之间竞争CPU 资源和进程切换的开销。而且 Nginx 为了更好的利用 多核特性 提供了 CPU 亲缘性的绑定选项我们可以将某一个进程绑定在某一个核上这样就不会因为进程的切换带来 Cache 的失效。

对于每个请求有且只有一个工作进程 对其处理。首先每个 worker 进程都是从 master进程 fork 过来。在 master 进程里面先建立好需要 listen 的 socketlistenfd 之后然后再 fork 出多个 worker 进程。

所有 worker 进程的 listenfd 会在新连接到来时变得可读 为保证只有一个进程处理该连接所有 worker 进程在注册 listenfd 读事件前抢占 accept_mutex 抢到互斥锁的那个进程注册 listenfd 读事件 在读事件里调用 accept 接受该连接。

当一个 worker 进程在 accept 这个连接之后就开始读取请求、解析请求、处理请求产生数据后再返回给客户端 最后才断开连接。这样一个完整的请求就是这样的了。我们可以看到一个请求完全由 worker 进程来处理而且只在一个 worker 进程中处理。

在 Nginx 服务器的运行过程中 主进程和工作进程 需要进程交互。交互依赖于 Socket 实现的管道来实现。

聊聊请列举Nginx服务器的最佳用途。

Nginx服务器的最佳用法是在网络上部署动态HTTP内容使用SCGI、WSGI应用程序服务器、用于脚本的FastCGI处理程序。

它还可以作为负载均衡器。

聊聊Nginx负载均衡实现过程

首先在http模块中配置使用upstream模块定义后台的webserver的池子并且给池子命名 比如命名为proxy-web

在池子中我们可以添加多台后台webserver其中状态检查、调度算法都是在池子中配置

然后在server模块中定义虚拟 location 地址但是这个虚拟location 地址 不指定自己的web目录站点

它将使用location 匹配url然后转发到上面定义好的web池子中

后台的webserver的池子最后根据调度策略再转发到后台web server上。

聊聊Nginx负载均衡配置

Upstream proxy_nginx {
	server 192.168.0.254 weight=1max_fails=2 fail_timeout=10s ; 
	server 192.168.0.253 weight=2 max_fails=2fail_timeout=10s;
	server192.168.0.252 backup; server192.168.0.251 down; 
}

server{
	listen 80;
	server_name xiaoka.com;
}

location / {
	proxy_pass http:// proxy_nginx;
	proxy_set_header Host
	proxy_set_header X-Real-IP
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

聊聊nginx的常用的负载均衡算法

1、round-robin

round-robin的意思是循环轮询。

Nginx最简单的负载均衡配置如下

http {
upstream app1 {
    server 10.10.10.1;
    server 10.10.10.2;
}
server {
    listen 80;
    location / {
        proxy_pass http://app1;
    }
}

upstream app1用来指定一个服务器组该组的名字是app1包含两台服务器。在指定服务器组里面包含的服务器时以形式“server ip/domainport”的形式指定其中80端口可以忽略。然后在接收到请求时通过“proxy_pass http://app1”把对应的请求转发到组app1上。Nginx默认的负载均衡算法就是循环轮询如上配置我们采用的就是循环轮询其会把接收到的请求循环的分发给其包含的当前可用的服务器。使用如上配置时Nginx会把第1个请求给10.10.10.1把第2个请求给10.10.10.2第3个请求给10.10.10.1以此类推。

2、least-connected

least-connected算法的中文翻译是最少连接即每次都找连接数最少的服务器来转发请求。例如Nginx负载中有两台服务器A和B当Nginx接收到一个请求时A正在处理的请求数是10B正在处理的请求数是20则Nginx会把当前请求交给A来处理。要启用最少连接负载算法只需要在定义服务器组时加上“least_conn”如

upstream app1 {
    least_conn;
    server 10.10.10.1;
    server 10.10.10.2;
}

3、ip-hash

ip-hash算法会根据请求的客户端IP地址来决定当前请求应该交给谁。使用ip-hash算法时Nginx会确保来自同一客户端的请求都分发到同一服务器。要使用ip-hash算法时只需要在定义服务器组时加上“ip-hash ”指令如

upstream app1 {
    ip_hash;
    server 10.10.10.1;
    server 10.10.10.2;
}

4、weighted

weighted算法也就是权重算法会根据每个服务的权重来分发请求权重大的请求相对会多分发一点权重小的会少分发一点。这通常应用于多个服务器的性能不一致时。需要使用权重算法时只需要在定义服务器组时在服务器后面指定参数weight如

upstream app1 {
    server 10.10.10.1 weight=3;
    server 10.10.10.2;
}

聊聊Nginx 有哪些负载均衡策略

Nginx 默认提供的负载均衡策略

1、轮询默认round_robin

每个请求按时间顺序逐一分配到不同的后端服务器如果后端服务器 down 掉能自动剔除。

2、IP 哈希 ip_hash

每个请求按访问 ip 的 hash 结果分配这样每个访客固定访问一个后端服务器可以解决 session 共享的问题。

当然实际场景下一般不考虑使用 ip_hash 解决 session 共享。

3、最少连接 least_conn

下一个请求将被分派到活动连接数量最少的服务器

4、权重 weight

weight的值越大分配到的访问概率越高主要用于后端每台服务器性能不均衡的情况下达到合理的资源利用率。 还可以通过插件支持其他策略。

聊聊ngx_http_upstream_module的作用是什么?

ngx_http_upstream_module用于定义可通过fastcgi传递、proxy传递、uwsgi传递、memcached传递和scgi传递指令来引用的服务器组。

聊聊Nginx配置高可用性怎么配置

  • 当上游服务器(真实访问服务器)一旦出现故障或者是没有及时相应的话应该直接轮训到下一台服务器保证服务器的高可用
  • Nginx配置代码
server {
    listen       80;
    server_name  www.lijie.com;
    location / {
        ### 指定上游服务器负载均衡服务器
        proxy_pass http://backServer;
        ###nginx与上游服务器(真实访问的服务器)超时时间 后端服务器连接的超时时间_发起握手等候响应超时时间
        proxy_connect_timeout 1s;
        ###nginx发送给上游服务器(真实访问的服务器)超时时间
        proxy_send_timeout 1s;
        ### nginx接受上游服务器(真实访问的服务器)超时时间
        proxy_read_timeout 1s;
        index  index.html index.htm;
    }
}

聊聊Nginx为什么不使用多线程

apache:

创建多个进程或线程而每个进程或线程都会为其分配cpu和内存线程要比进程小的多所以worker支持比perfork高的并发并发过大会榨干服务器资源。

Nginx:

采用单线程来异步非阻塞处理请求管理员可以配置Nginx主进程的工作进程的数量(epoll)不会为每个请求分配cpu和内存资源节省了大量资源同时也减少了大量的CPU的上下文切换。

所以才使得Nginx支持更高的并发。

聊聊Nginx为什么不使用多线程

Nginx:

采用单线程来异步非阻塞处理请求管理员可以配置Nginx主进程的工作进程的数量

不会为每个请求分配cpu和内存资源节省了大量资源同时也减少了大量的CPU的上下文切换所以才使得Nginx支持更高的并发。

聊聊Nginx主要特性

  1. 支持SSL 和TLSSNI.
    Nginx它支持内核Poll模型能经受高负载的考验,有报告表明能支持高达50,000个并发连接数。
  2. Nginx具有很高的稳定性。
    例如当前 apache一旦上到200个以上进程web响应速度就明显非常缓慢了。而Nginx采取了分阶段资源分配技术使得它的CPU与内存占用率非常低。nginx官方表示保持10,000个没有活动的连接它只占2.5M内存所以类似DOS这样的攻击对nginx来说基本上是毫无用处的。
  3. Nginx支持热部署。
    它的启动特别容易并且几乎可以做到7*24不间断运行即使运行数个月也不需要重新启动。对软件版本进行进行热升级。
  4. Nginx采用master-slave模型,能够充分利用SMP的优势且能够减少工作进程在磁盘IO的阻塞延迟。
    当采用select()/poll()调用时还可以限制每个进程的连接数。
  5. Nginx采用master-slave模型,能够充分利用SMP的优势且能够减少工作进程在磁盘IO的阻塞延迟。
    当采用select()/poll()调用时还可以限制每个进程的连接数。
  6. Nginx采用了一些os提供的最新特性如对sendfile (Linux2.2+) accept-filter
    (FreeBSD4.1+)TCP_DEFER_ACCEPT (Linux 2.4+)的支持,从而大大提高了性能。
  7. 免费开源可以做高并发负载均衡。

聊聊Nginx常用命令

1、启动

nginx

2、停止

nginx -s stop 
或
nginx -s quit

3、重载配置

./sbin/nginx -s reload(平滑重启 )service nginx reload

4、重载指定配置文件

.nginx -c /usr/local/nginx/conf/nginx.conf

5、查看版本

nginx -v

6、检查配置文件是否正确

nginx -t

7、显示帮助命令

nginx -h

聊聊Nginx IO事件模型以及连接数上限

events {
    use epoll; #epoll 是多路复⽤ IO(I/O Multiplexing)中的⼀种⽅式,但是仅⽤于 linux2.6 
    #以上内核,可以⼤⼤提⾼ nginx 的性能
    worker_connections 1024;#单个后台 worker process 进程的最⼤并发链接数
    # multi_accept on; 
}

聊聊动态资源、静态资源分离的原因

动态资源、静态资源分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来

动静资源做好了拆分以后我们就可以根据静态资源的特点将其做缓存操作这就是网站静态化处理的核心思路

动态资源、静态资源分离简单的概括是动态文件与静态文件的分离

二者分离的原因
在我们的软件开发中

  • 有些请求是需要后台处理的如.jsp,.do等等
  • 有些请求是不需要经过后台处理的如css、html、jpg、js等等文件

这些不需要经过后台处理的文件称为静态文件否则动态文件。

因此我们后台处理忽略静态文件。这会有人又说那我后台忽略静态文件不就完了吗

当然这是可以的但是这样后台的请求次数就明显增多了。

在我们对资源的响应速度有要求的时候我们应该使用这种动静分离的策略去解决

动、静分离将网站静态资源HTMLJavaScriptCSSimg等文件与后台应用分开部署提高用户访问静态代码的速度降低对后台应用访问

这里我们将静态资源放到nginx中动态资源转发到tomcat服务器中

聊聊Nginx怎么做的动静分离

只需要指定路径对应的目录。

location/可以使用正则表达式匹配。并指定对应的硬盘中的目录。如下

location /image/ {
    root /usr/local/static/;
    autoindex on;
}

创建目录

mkdir /usr/local/static/image

进入目录

cd /usr/local/static/image

放一张照片上去

1.jpg

重启 nginx

sudo nginx -s reload

打开浏览器 输入 server_name/image/1.jpg 就可以访问该静态图片了

聊聊什么是动静分离

动静分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来动静资源做好了拆分以后我们就可以根据静态资源的特点将其做缓存操作这就是网站静态化处理的核心思路实际上何谓动何谓静呢拿我们 Java 来说 jsp、servlet 等就是动因为他们离开我们的 web 服务器的支持就会无法正常工作。而 js、css 等文件就是静了。因为离开 web 服务器他一样能正常的工作。

动静分离简单的概括是动态文件与静态文件的分离。

Nginx动静分离

聊聊Nginx动静态资源分离做过吗为什么要这样做

动态资源、静态资源分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来。

比如说 js、css、hrml从A服务器返回。图片从B服务器返回其他请求从Tomcat服务器C返回。

后台应用分开部署提高用户访问静态代码的速度。而且现在还有CDN服务不需要限制于服务器的带宽。

聊聊Nginx如何做动静分离

Nginx 根据客户端请求的 url 来判断请求的是否是静态资源如果请求的 url 包含 jpg、png则由 Nginx 处理。如果请求的 url 是 .php 或者 .jsp 等等这个时候这个请求是动态的将转发给 tomcat 处理。

总结来说Nginx 是通过 url 来区分请求的类型并转发给不同的服务端。

聊聊Nginx动静分离的好处

  • api 接口服务化动静分离之后后端应用更为服务化只需要通过提供 api 接口即可可以为多个功能模块甚至是多个平台的功能使用可以有效的节省后端人力更便于功能维护。
  • 前后端开发并行前后端只需要关心接口协议即可各自的开发相互不干扰并行开发并行自测可以有效的提高开发时间也可以有些的减少联调时间
  • 减轻后端服务器压力提高静态资源访问速度后端不用再将模板渲染为 html 返回给用户端且静态服务器可以采用更为专业的技术提高静态资源的访问速度。

聊聊Nginx 和 Apache、Tomcat 之间的不同点

Tomcat 和Nginx/Apache区别

1、Nginx/Apache 是Web Server,而Apache Tomact是一个servlet container

2、tomcat可以对jsp进行解析nginx和apache只是web服务器可以简单理解为只能提供html静态文件服务。

Nginx和Apache区别

1Nginx轻量级同样起web 服务比apache占用更少的内存及资源 。

2Nginx 抗并发nginx 处理请求是异步非阻塞的而apache 则是阻塞型的在高并发下nginx 能保持低资源低消耗高性能 。

3Nginx提供负载均衡可以做做反向代理前端服务器

4Nginx多进程单线程异步非阻塞Apache多进程同步阻塞。

聊聊Nginx和Apache 之间的不同点

nginxapache
1.nginx 是一个基于web服务器1.Apache 是一个基于流程的服务器
2.所有请求都由一个线程来处理2.单线程处理单个请求
3.nginx避免子进程的概念3.apache是基于子进程的
4.nginx类似于速度4.apache类似于功率
5.nginx在内存消耗和连接方面比较好5.apache在内存消耗和连接方面并没有提高
6.nginx在负载均衡方面表现较好6.apache当流量达到进程的极限时apache将拒绝新的连接
7.对于PHP来说nginx更可取因为他支持PHP7.apache支持的php python Perl和其他语言使用插件当应用程序基于python和ruby时它非常有用
8.nginx 不支持像ibmi 和 openvms 一样的os8.apache支持更多的os
9.nginx 只具有核心功能9.apache 提供了比Nginx更多的功能
10.nginx 性能和可伸缩性不依赖于硬件10.apache 依赖于CPU和内存等硬件组件

聊聊Nginx与Apache对比

优点

  1. 轻量级采用 C 语言 进行编写同样的 web 服务会占用更少的内存及资源。
  2. 抗并发nginx 以 epoll and kqueue 作为开发模型处理请求是异步非阻塞的多个连接对应一个进程负载能力比 apache 高很多而 apache 则是同步多进程模型只能一个连接对应一个进程当压力过大时它是会被阻塞型的。
    在高并发下 nginx 能保持低资源低消耗高性能 而 apache 在 PHP 处理慢或者前端压力很大的情况下很容易出现进程数飙升从而拒绝服务的现象。
  3. 设计高度模块化编写模块相对简单。
  4. 配置简洁正则配置让很多事情变得简单而且改完配置能使用 -t 测试配置有没有问题apache 配置复杂 重启的时候发现配置出错了会很崩溃。
  5. 一般用于处理静态文件静态处理性能比 apache 高三倍以上。
  6. 作为负载均衡服务器支持 7 层负载均衡。
  7. 本身就是一个反向代理服务器而且可以作为非常优秀的邮件代理服务器。
  8. nginx 启动特别容易, 并且几乎可以做到 7*24 不间断运行即使运行数个月也不需要重新启动支持热部署比如实现不间断服务的情况下进行软件版本的升级与版本的回退。
  9. 社区活跃各种高性能模块出品迅速。

缺点

  1. apache 的 rewrite 比 nginx 强大在 rewrite 频繁的情况下用 apache。
  2. apache 发展到现在模块超多基本想到的都可以找到。
  3. apache 更为成熟少 bug nginx 的 bug 相对较多。
  4. apache 超稳定Nginx 一个进程死掉时会影响到多个用户的使用稳定性差。
  5. apache 对 PHP 支持比较简单nginx 需要配合其他后端用。
  6. apache 在处理动态请求有优势nginx 在这方面是鸡肋一般动态请求要 apache 去做nginx 适合静态和反向。
  7. apache 仍然是目前的主流拥有丰富的特性成熟的技术和开发社区。

聊聊Nginx与Apache选择

Apache

● apache 的 rewrite 比 nginx 强大在 rewrite 频繁的情况下用 apache

● apache 发展到现在模块超多基本想到的都可以找到

● apache 更为成熟少 bug nginx 的 bug 相对较多

● apache 超稳定

● apache 对 PHP 支持比较简单nginx 需要配合其他后端用

● apache 在处理动态请求有优势nginx 在这方面是鸡肋一般动态请求要 apache 去做nginx 适合静态和反向。

● apache 仍然是目前的主流拥有丰富的特性成熟的技术和开发社区

Nginx

● 轻量级采用 C 语言 进行编写同样的 web 服务会占用更少的内存及资源

● 抗并发nginx 以 epoll and kqueue 作为开发模型处理请求是异步非阻塞的负载能力比 apache 高很多而 apache 则是阻塞型的。在高并发下 nginx 能保持低资源低消耗高性能 而 apache 在 PHP 处理慢或者前端压力很大的情况下很容易出现进程数飙升从而拒绝服务的现象。

● nginx 处理静态文件好静态处理性能比 apache 高三倍以上

● nginx 的设计高度模块化编写模块相对简单

● nginx 配置简洁正则配置让很多事情变得简单而且改完配置能使用 -t 测试配置有没有问题apache 配置复杂 重启的时候发现配置出错了会很崩溃

● nginx 作为负载均衡服务器支持 7 层负载均衡

● nginx 本身就是一个反向代理服务器而且可以作为非常优秀的邮件代理服务器

● 启动特别容易, 并且几乎可以做到 7*24 不间断运行即使运行数个月也不需要重新启动还能够不间断服务的情况下进行软件版本的升级

● 社区活跃各种高性能模块出品迅速

聊聊Nginx如何处理HTTP请求。

Nginx使用反应器模式。

主事件循环等待操作系统发出准备事件的信号这样数据就可以从套接字读取在该实例中读取到缓冲区并进行处理。

单个线程可以提供数万个并发连接。

聊聊Nginx是如何处理一个请求的呢

首先nginx在启动时会解析配置文件得到需要监听的端口与ip地址

然后在nginx的master进程里面先初始化好这个监控的socket再进行listen

然后再fork出多个子进程出来, 子进程会竞争accept新的连接。

此时客户端就可以向nginx发起连接了。

当客户端与nginx进行三次握手与nginx建立好一个连接后

此时某一个子进程会accept成功然后创建nginx对连接的封装即ngx_connection_t结构体

接着根据事件调用相应的事件处理模块如http模块与客户端进行数据的交换

最后nginx或客户端来主动关掉连接到此一个连接就寿终正寝了

聊聊Nginx处理HTTP请求过程的 11 个阶段

Nginx 处理 HTTP 请求的过程大概可以分为 11 个阶段如下

  1. Read Request Headers解析请求头。
  2. Identify Configuration Block识别由哪一个 location 进行处理匹配 URL。
  3. Apply Rate Limits判断是否限速。例如可能这个请求并发的连接数太多超过了限制或者 QPS 太高。
  4. Perform Authentication连接控制验证请求。例如可能根据 Referrer 头部做一些防盗链的设置或者验证用户的权限。
  5. Generate Content生成返回给用户的响应。为了生成这个响应做反向代理的时候可能会和上游服务Upstream Services进行通信然后这个过程中还可能会有些子请求或者重定向那么还会走一下这个过程Internal redirects and subrequests。
  6. Response Filters过滤返回给用户的响应。比如压缩响应或者对图片进行处理。
  7. Log记录日志。

以上这七个步骤从整体上介绍了一下处理流程下面还会再说一下实际的处理过程。

聊聊Nginx处理HTTP请求的11个阶段

下面介绍一下详细的 11 个阶段每个阶段都可能对应着一个甚至多个 HTTP 模块通过这样一个模块对比我们也能够很好的理解这些模块具体是怎么样发挥作用的。

Nginx处理HTTP请求过程.png

  1. POST_READ在 read 完请求的头部之后在没有对头部做任何处理之前想要获取到一些原始的值就应该在这个阶段进行处理。这里面会涉及到一个 realip 模块。
  2. SERVER_REWRITE和下面的 REWRITE 阶段一样都只有一个模块叫 rewrite 模块一般没有第三方模块会处理这个阶段。
  3. FIND_CONFIG做 location 的匹配暂时没有模块会用到。
  4. REWRITE对 URL 做一些处理。
  5. POST_WRITE处于 REWRITE 之后也是暂时没有模块会在这个阶段出现。

接下来是确认用户访问权限的三个模块

  1. PREACCESS是在 ACCESS 之前要做一些工作例如并发连接和 QPS 需要进行限制涉及到两个模块limt_conn 和 limit_req
  2. ACCESS核心要解决的是用户能不能访问的问题例如 auth_basic 是用户名和密码access 是用户访问 IPauth_request 根据第三方服务返回是否可以去访问。
  3. POST_ACCESS是在 ACCESS 之后会做一些事情同样暂时没有模块会用到。

最后的三个阶段处理响应和日志

  1. PRECONTENT在处理 CONTENT 之前会做一些事情例如会把子请求发送给第三方的服务去处理try_files 模块也是在这个阶段中。
  2. CONTENT这个阶段涉及到的模块就非常多了例如 index, autoindex, concat 等都是在这个阶段生效的。
  3. LOG记录日志 access_log 模块。

以上的这些阶段都是严格按照顺序进行处理的当然每个阶段中各个 HTTP 模块的处理顺序也很重要如果某个模块不把请求向下传递后面的模块是接收不到请求的。

而且每个阶段中的模块也不一定所有都要执行一遍下面就接着讲一下各个阶段模块之间的请求顺序。

聊聊Nginx处理HTTP请求的11个阶段的顺序处理

如下图所示每一个模块处理之间是有序的那么这个顺序怎么才能得到呢其实非常简单在源码 ngx_module.c 中有一个数组 ngx_module_name其中包含了在编译 Nginx 的时候的 with 指令所包含的所有模块它们之间的顺序非常关键在数组中顺序是相反的。

char *ngx_module_names[] = {
    … …
    "ngx_http_static_module",
    "ngx_http_autoindex_module",
    "ngx_http_index_module",
    "ngx_http_random_index_module",
    "ngx_http_mirror_module",
    "ngx_http_try_files_module",
    "ngx_http_auth_request_module",
    "ngx_http_auth_basic_module",
    "ngx_http_access_module",
    "ngx_http_limit_conn_module",
    "ngx_http_limit_req_module",
    "ngx_http_realip_module",
    "ngx_http_referer_module",
    "ngx_http_rewrite_module",
    "ngx_http_concat_module",
    … …
}

灰色部分的模块是 Nginx 的框架部分去执行处理的第三方模块没有机会在这里得到处理。

在依次向下执行的过程中也可能不按照这样的顺序。例如在 access 阶段中有一个指令叫 satisfy它可以指示当有一个满足的时候就直接跳到下一个阶段进行处理例如当 access 满足了就直接跳到 try_files 模块进行处理而不会再执行 auth_basic、auth_request 模块。

在 content 阶段中当 index 模块执行了就不会再执行 auto_index 模块而是直接跳到 log 模块。整个 11 个阶段所涉及到的模块和先后顺序如下图所示

Nginx处理HTTP请求过程.png

聊聊Nginx配置文件nginx.conf有哪些属性模块?

worker_processes  1                					# worker进程的数量
events {                              					# 事件区块开始
    worker_connections  1024            				# 每个worker进程支持的最大连接数
}                                    					# 事件区块结束
http {                               					# HTTP区块开始
    include       mime.types            				# Nginx支持的媒体类型库文件
    default_type  application/octet-stream     		# 默认的媒体类型
    sendfile        on       							# 开启高效传输模式
    keepalive_timeout  65       						# 连接超时
    server {            								# 第一个Server区块开始表示一个独立的虚拟主机站点
        listen       80      							# 提供服务的端口默认80
        server_name  localhost       					# 提供服务的域名主机名
        location / {            						# 第一个location区块开始
            root   html       						# 站点的根目录相当于Nginx的安装目录
            index  index.html index.htm      			# 默认的首页文件多个用空格分开
        }          										# 第一个location区块结果
        error_page   500502503504  /50x.html     		# 出现对应的http状态码时使用50x.html回应客户
        location = /50x.html {          				# location区块开始访问50x.html
            root   html      							# 指定对应的站点目录为html
        }
    }  
    ......

聊聊在Nginx中如何使用未定义的服务器名称来阻止处理请求?

只需将请求删除的服务器, 可以定义为

Server {
    listen 80;
    server_name “ “ ;
    return 444;
}

这里服务器名被保留为一个空字符串它将在没有“主机”头字段的情况下匹配请求而一个特殊的Nginx的非标准代码444被返回从而终止连接。

聊聊Nginx的进程模型

  1. master-worker模式
    在master-worker模式下有一个master进程和至少一个的worker进程。
  2. 单进程模式。
    单进程模式只有一个进程。

聊聊Nginx服务器上的Master和Worker进程分别是什么?

Master进程读取及评估配置和维持

Worker进程处理请求

聊聊Nginx惊群

惊群效应thundering herd是指多进程多线程在同时阻塞等待同一个事件的时候休眠状态

如果等待的这个事件发生那么他就会唤醒等待的所有进程或者线程但是最终却只能有一个进程线程获得这个时间的 “控制权”对该事件进行处理

而其他进程线程获取 “控制权” 失败只能重新进入休眠状态这种现象和性能浪费就叫做惊群效应。

聊聊惊群效应消耗了什么

Linux 内核对用户进程线程频繁地做无效的调度、上下文切换等使系统性能大打折扣。上下文切换context switch过高会导致 CPU 像个搬运工频繁地在寄存器和运行队列之间奔波更多的时间花在了进程线程切换而不是在真正工作的进程线程上面。

直接的消耗包括 CPU 寄存器要保存和加载例如程序计数器、系统调度器的代码需要执行。间接的消耗在于多核 cache 之间的共享数据。为了确保只有一个进程线程得到资源需要对资源操作进行加锁保护加大了系统的开销。目前一些常见的服务器软件有的是通过锁机制解决的比如 Nginx它的锁机制是默认开启的可以关闭还有些认为惊群对系统性能影响不大没有去处理比如 Lighttpd。

聊聊Nginx惊群效应? 以及解决方案

对于 Nginx 的惊群问题我们首先需要理解的是在 Nginx 启动过程中master 进程会监听配置文件中指定的各个端口然后 master 进程就会调用 fork() 方法创建各个子进程根据进程的工作原理子进程是会继承父进程的全部内存数据以及监听的端口的也就是说 worker 进程在启动之后也是会监听各个端口的。

关于惊群指的就是当客户端有新建连接的请求到来时就会触发各个 worker 进程的连接建立事件但是只有一个 worker 进程能够正常处理该事件而其他的 worker 进程会发现事件已经失效从而重新循环进入等待状态。这种由于一个事件而 “惊” 起了所有 worker 进程的现象就是惊群问题。很明显如果所有的 worker 进程都被触发了那么这将消耗大量的资源。

解决方案

在 Nginx 中每个 worker 进程被创建的时候都会调用 ngx_worker_process_init() 方法初始化当前 worker 进程这个过程中有一个非常重要的步骤即每个 worker 进程都会调用 epoll_create() 方法为自己创建一个独有的 epoll 句柄。

对于每一个需要监听的端口都有一个文件描述符与之对应而 worker 进程只有将该文件描述符通过 epoll_ctl() 方法添加到当前进程的 epoll 句柄中并且监听 accept 事件此时才会被客户端的连接建立事件触发从而处理该事件。从这里也可以看出worker 进程如果没有将所需要监听的端口对应的文件描述符添加到该进程的 epoll 句柄中那么其是无法被触发对应的事件的。

基于这个原理nginx 就使用了一个共享锁来控制当前进程是否有权限将需要监听的端口添加到当前进程的 epoll 句柄中也就是说只有获取锁的进程才会监听目标端口。通过这种方式就保证了每次事件发生时只有一个 worker 进程会被触发。如下图所示为 worker 进程工作循环的一个示意图

Nginx惊群

这里关于图中的流程需要说明的一点是每个 worker 进程在进入循环之后就会尝试获取共享锁如果没有获取到就会将所监听的端口的文件描述符从当前进程的 epoll 句柄中移除即使并不存在也会移除这么做的主要目的是防止丢失客户端连接事件即使这可能造成少量的惊群问题但是并不严重。

试想一下如果按照理论在当前进程释放锁的时候就将监听的端口的文件描述符从 epoll 句柄中移除那么在下一个 worker 进程获取锁之前这段时间各个端口对应的文件描述符是没有任何 epoll 句柄进行监听的此时就会造成事件的丢失。如果反过来按照图中的在获取锁失败的时候才移除监听的文件描述符由于获取锁失败则说明当前一定有一个进程已经监听了这些文件描述符因而此时移除是安全的。

但是这样会造成的一个问题是按照上图当前进程在一个循环执行完毕的时候会释放锁然后处理其他的事件注意这个过程中其是没有释放所监听的文件描述符的。此时如果另一个进程获取到了锁并且监听了文件描述符那么这个时候就有两个进程监听了文件描述符因而此时如果客户端发生连接建立事件那么就会触发两个 worker 进程。这个问题是可以容忍的主要原因有两点

  • 这个时候发生的惊群现象只触发了更少的 worker 进程比起每次都惊起所有的 worker 进程要好很多
  • 会发生这种惊群问题的主要原因是当前进程释放了锁但是没有释放所监听的文件描述符但是 worker 进程在释放锁之后主要是处理客户端连接的读写事件和检查标志位这个过程是非常短的在处理完之后其就会尝试获取锁这个时候就会释放所监听的文件描述符了而相较而言获取锁的 worker 进程在等待处理客户端的连接建立事件的事件就更长了因而会发生惊群问题的概率还是比较小的。

源码讲解

worker 进程初始事件的方法主要是在 ngx_process_events_and_timers() 方法中进行的下面我们就来看看该方法是如何处理整个流程的如下是该方法的源码

void ngx_process_events_and_timers(ngx_cycle_t *cycle) {
  ngx_uint_t flags;
  ngx_msec_t timer, delta;
  if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
    return;
  }
  // 这里开始处理事件对于kqueue模型其指向的是ngx_kqueue_process_events()方法
  // 而对于epoll模型其指向的是ngx_epoll_process_events()方法
  // 这个方法的主要作用是在对应的事件模型中获取事件列表然后将事件添加到ngx_posted_accept_events
  // 队列或者ngx_posted_events队列中
  (void) ngx_process_events(cycle, timer, flags);
  // 这里开始处理accept事件将其交由ngx_event_accept.c的ngx_event_accept()方法处理
  ngx_event_process_posted(cycle, &ngx_posted_accept_events);
  // 开始释放锁
  if (ngx_accept_mutex_held) {
    ngx_shmtx_unlock(&ngx_accept_mutex);
  }
  // 如果不需要在事件队列中进行处理则直接处理该事件
  // 对于事件的处理如果是accept事件则将其交由ngx_event_accept.c的ngx_event_accept()方法处理
  // 如果是读事件则将其交由ngx_http_request.c的ngx_http_wait_request_handler()方法处理
  // 对于处理完成的事件最后会交由ngx_http_request.c的ngx_http_keepalive_handler()方法处理。
  // 这里开始处理除accept事件外的其他事件
  ngx_event_process_posted(cycle, &ngx_posted_events);
}	

上面的代码中我们省略了大部分的检查工作只留下了骨架代码。首先worker 进程会调用 ngx_trylock_accept_mutex() 方法获取锁这其中如果获取到了锁就会监听各个端口对应的文件描述符。然后会调用 ngx_process_events() 方法处理 epoll 句柄中监听到的事件。接着会释放共享锁最后就是处理已建立连接的客户端的读写事件。下面我们来看一下 ngx_trylock_accept_mutex() 方法是如何获取共享锁的

ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle) {
  // 尝试使用CAS算法获取共享锁
  if (ngx_shmtx_trylock(&ngx_accept_mutex)) {
    // ngx_accept_mutex_held为1表示当前进程已经获取到了锁
    if (ngx_accept_mutex_held && ngx_accept_events == 0) {
      return NGX_OK;
    }
    // 这里主要是将当前连接的文件描述符注册到对应事件的队列中比如kqueue模型的change_list数组
    // nginx在启用各个worker进程的时候默认情况下worker进程是会继承master进程所监听的socket句柄的
    // 这就导致一个问题就是当某个端口有客户端事件时就会把监听该端口的进程都给唤醒
    // 但是只有一个worker进程能够成功处理该事件而其他的进程被唤醒之后发现事件已经过期
    // 因而会继续进入等待状态这种现象称为"惊群"现象。
    // nginx解决惊群现象的方式一方面是通过这里的共享锁的方式即只有获取到锁的worker进程才能处理
    // 客户端事件但实际上worker进程是通过在获取锁的过程中为当前worker进程重新添加各个端口的监听事件
    // 而其他worker进程则不会监听。也就是说同一时间只有一个worker进程会监听各个端口
    // 这样就避免了"惊群"问题。
    // 这里的ngx_enable_accept_events()方法就是为当前进程重新添加各个端口的监听事件的。
    if (ngx_enable_accept_events(cycle) == NGX_ERROR) {
      ngx_shmtx_unlock(&ngx_accept_mutex);
      return NGX_ERROR;
    }
    // 标志当前已经成功获取到了锁
    ngx_accept_events = 0;
    ngx_accept_mutex_held = 1;
    return NGX_OK;
  }
  // 前面获取锁失败了因而这里需要重置ngx_accept_mutex_held的状态并且将当前连接的事件给清除掉
  if (ngx_accept_mutex_held) {
    // 如果当前进程的ngx_accept_mutex_held为1则将其重置为0并且将当前进程在各个端口上的监听
    // 事件给删除掉
    if (ngx_disable_accept_events(cycle, 0) == NGX_ERROR) {
      return NGX_ERROR;
    }
    ngx_accept_mutex_held = 0;
  }
  return NGX_OK;
}

上面的代码中本质上主要做了三件事

  1. 通过 ngx_shmtx_trylock() 方法尝试使用CAS方法获取共享锁
  2. 获取锁之后则调用 ngx_enable_accept_events() 方法监听目标端口对应的文件描述符
  3. 如果没有获取到锁则调用 ngx_disable_accept_events() 方法释放所监听的文件描述符

总结

惊群现象指所有的工作进程都在等待一个 socket当 socket 客户端连接时所有工作线程都被唤醒但最终有且仅有一个工作线程去处理该连接其他进程又要进入睡眠状态。

Nginx 通过控制争抢处理 socket 的进程数量和抢占 ngx_accept_mutex 锁解决惊群现象。只有一个 ngx_accept_mutex 锁谁拿到锁谁处理该 socket 的请求。

聊聊Nginx IO模型

Nginx 支持多种并发模型并发模型的具体实现根据系统平台而有所不同。

在支持多种并发模型的平台上Nginx 自动选择最高效的模型。

但我们也可以使用 use 指令在配置文件中显式地定义某个并发模型。

聊聊Nginx IO模型

Nginx 支持多种并发模型并发模型的具体实现根据系统平台而有所不同。在支持多种并发模型的平台上Nginx 自动选择最高效的模型。但我们也可以使用 use 指令在配置文件中显式地定义某个并发模型。

Nginx中支持的并发模型

select

IO 多路复用、标准并发模型。在编译 Nginx 时如果所使用的系统平台没有更高效的并发模型select 模块将被自动编译。configure 脚本的选项–with-select_module 和 --without-select_module 可被用来强制性地开启或禁止 select 模块的编译。

poll

IO 多路复用、标准并发模型。与 select 类似在编译 Nginx 时如果所使用的系统平台没有更高效的并发模型poll 模块将被自动编译。configure 脚本的选项–with-poll_module 和 --without-poll_module 可用于强制性地开启或禁止 poll 模块的编译。

epoll

IO 多路复用、高效并发模型可在 Linux 2.6+ 及以上内核可以使用。

kqueue

IO 多路复用、高效并发模型可在 FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0, and Mac OS X 平台中使用。

/dev/poll

高效并发模型可在 Solaris 7 11/99+, HP/UX 11.22+ (eventport), IRIX 6.5.15+, and Tru64 UNIX 5.1A+ 平台使用。

eventport

高效并发模型可用于 Solaris 10 平台PS由于一些已知的问题建议使用/dev/poll替代。

聊聊为什么 epoll 快比较一下 Apache 常用的 select 和 Nginx 常用的 epoll

select

  1. 最大并发数限制因为一个进程所打开的 FD 文件描述符是有限制的由 FD_SETSIZE 设置默认值是 1024/2048因此 Select 模型的最大并发数就被相应限制了。自己改改这个 FD_SETSIZE 想法虽好可是先看看下面吧。

  2. 效率问题select 每次调用都会线性扫描全部的 FD 集合这样效率就会呈现线性下降把 FD_SETSIZE 改大的后果就是大家都慢慢来什么都超时了。

  3. 内核/用户空间内存拷贝问题如何让内核把 FD 消息通知给用户空间呢在这个问题上 select 采取了内存拷贝方法在 FD 非常多的时候非常的耗费时间。

总结为

  1. 连接数受限
  2. 查找配对速度慢
  3. 数据由内核拷贝到用户态消耗时间。

epoll

  1. Epoll 没有最大并发连接的限制上限是最大可以打开文件的数目这个数字一般远大于 2048, 一般来说这个数目和系统内存关系很大 具体数目可以 cat /proc/sys/fs/file-max 查看。

  2. 效率提升Epoll 最大的优点就在于它只管你 “活跃” 的连接 而跟连接总数无关因此在实际的网络环境中Epoll 的效率就会远远高于 select 和 poll。

  3. 内存共享Epoll 在这点上使用了 “共享内存”这个内存拷贝也省略了。

聊聊你如何通过不同于80的端口开启Nginx?

为了通过一个不同的端口开启Nginx你必须进入/etc/Nginx/sites-enabled/如果这是默认文件那么你必须打开名为“default”的文件。

编辑文件并放置在你想要的端口

server {
  listen 81; 
}

聊聊location的作用是什么

location指令的作用是根据用户请求的URI来执行不同的应用也就是根据用户请求的网站URL进行匹配匹配成功即进行相关的操作。

聊聊location的语法能说出来吗

location主要用于URI的匹配。

什么是 uri
URIUniform Resource Identifier统一资源标识符如下图的data.html;
URNUniform Resource Name统一资源名称如下图的ste.org/img.png比URI多个域名;
URLUniform Resource Locator统一资源定位符如下面URL包含了http协议、端口、域名、文件名。

URI的匹配 示例如下:

#优先级1,精确匹配根路径
location =/ {
    return 400;
}

#优先级2,以某个字符串开头,以av开头的优先匹配这里区分大小写
location ^~ /av {
    root /data/av/;
}

#优先级3区分大小写的正则匹配匹配/media*****路径
location ~ /media {
    alias /data/static/;
}

#优先级4 不区分大小写的正则匹配所有的****.jpg|gif|png 都走这里
location ~* .*\.(jpg|gif|png|js|css)$ {
    root  /data/av/;
}

#优先7通用匹配
location / {
    return 403;
}

聊聊Nginx如何定义错误提示页面

#error_page 500 502 503 504 /50x.html;
location = /50x.html {
    root /root; 
}

聊聊是否有可能将Nginx的错误替换为502错误、503?

502 =错误网关

503 =服务器超载

有可能但是您可以确保fastcgi_intercept_errors被设置为ON并使用错误页面指令。

Location / {
    fastcgi_pass 127.0.01:9001;
    fastcgi_intercept_errors on;
    error_page 502 =503/error_page.html;

聊聊nginx中500、502、503、504 有什么区别

500

Internal Server Error 内部服务错误比如脚本错误编程语言语法错误。

502

Bad Gateway错误网关错误。比如服务器当前连接太多响应太慢页面素材太多、带宽慢。

503

Service Temporarily Unavailable服务不可用web服务器不能处理HTTP请求可能是临时超载或者是服务器进行停机维护。

504

Gateway timeout 网关超时程序执行时间过长导致响应超时例如程序需要执行20秒而nginx最大响应等待时间为10秒这样就会出现超时。

聊聊Nginx如何精准匹配路径

location = /get { 
   #规则 A 
}

聊聊Nginx路径匹配优先级

多个location 配置的情况下匹配顺序为

  1. 首先匹配 =

  2. 其次匹配 ^~

  3. 再其次是按文件中顺序的正则匹配

  4. 最后是交给 / 通用匹配。

当有匹配成功时候停止匹配按当前匹配规则处理请求。

聊聊如何将请求转发给后端应用服务器

location = / {
	proxy_pass http://tomcat:8080/index
}

聊聊如何根据文件类型设置过期时间

location ~* \.(js|css|jpg|jpeg|gif|png|swf)$ {
	if (-f $request_filename) {
		expires 1h;
		break; 
	}
}

聊聊如何禁止访问某个目录

location ^~/path/ {
    deny all;
}

聊聊在Nginx中解释如何在URL中保留双斜线?

要在URL中保留双斜线就必须使用merge_slashes_off;

语法:merge_slashes [on/off]

默认值: merge_slashes on

环境: httpserver

聊聊Nginx rewrite全局变量

Nginx rewrite 常用的全局变量如下

变量说明
$args存放了请求 url 中的请求指令。比如 http://www.myweb.name/server/source?arg1=value1&arg2=value2 中的arg1=value1&arg2=value2
$content_length存放请求头中的 Content-length 字段
$content_type存放了请求头中的 Content-type 字段
$document_root存放了针对当前请求的根路径
$document_uri请求中的 uri不包含请求指令 比如比如 http://www.myweb.name/server/source?arg1=value1&arg2=value2 中的 /server/source
$host存放了请求 url 中的主机字段比如 http://www.myweb.name/server/source?arg1=value1&arg2=value2 中的 www.myweb.name。如果请求中的主机部分字段不可用或者为空则存放 nginx 配置中该 server 块中 server_name 指令的配置值
$http_user_agent存放客户端的代理
$http_cookiecookie
$limit_ratenginx 配置中 limit_rate 指令的配置值
$remote_addr客户端的地址
$remote_port客户端与服务器端建立连接的端口号
$remote_user变量中存放了客户端的用户名
$request_body_file存放了发给后端服务器的本地文件资源的名称
$request_method存放了客户端的请求方式如 get,post 等
$request_filename存放当前请求的资源文件的路径名
$requset_uri当前请求的 uri,并且带有指令
$query_string$args含义相同
$scheme客户端请求使用的协议如 http, https, ftp 等
$server_protocol客户端请求协议的版本如 ”HTTP/1.0”, ”HTTP/1.1”
$server_addr服务器的地址
$server_name客户端请求到达的服务器的名称
$server_port客户端请求到达的服务器的端口号
$uri$document_uri

请解释ngx_http_upstream_module的作用是什么?

ngx_http_upstream_module用于定义可通过fastcgi传递、proxy传递、uwsgi传递、memcached传递和scgi传递指令来引用的服务器组。

聊聊stub_status和sub_filter指令的作用是什么?

Stub_status指令该指令用于了解Nginx当前状态的当前状态如当前的活动连接接受和处理当前读/写/等待连接的总数

Sub_filter指令它用于搜索和替换响应中的内容并快速修复陈旧的数据

聊聊Nginx 压缩了解吗如何开启压缩

开启nginx gzip压缩后图片、css、js等静态资源的大小会减小可节省带宽提高传输效率但是会消耗CPU资源。

gzip on;  
#开启gzip压缩功能
gzip_min_length 1k;
#设置允许压缩的页面最小字节数页面字节数从header头的content-length中获取。默认值是0,不管页面多大都进行压缩。建议设置成大于1k。如果小于1k可能会越压越大。
gzip_buffers 4 16k;
#压缩缓冲区大小。表示申请4个单位为16k的内容作为压缩结果流缓存默认值是申请与原始数据大小相同的内存空间来存储gzip压缩结果。
gzip_http_version 1.0;
#压缩版本默认1.1前端为squid2.5时使用1.0用于设置识别http协议版本默认是1.1,目前大部分浏览器已经支持gzip解压使用默认即可。
gzip_comp_level 2;
#压缩比率。用来指定gzip压缩比1压缩比量小处理速度快9压缩比量大传输速度快但处理最慢也必将消耗cpu资源。
gzip_types text/plain application/x-javascript text/css application/xml;
#用来指定压缩的类型“text/html”类型总是会被压缩。
gzip_vary on;
#vary header支持。该选项可以让前端的缓存服务器缓存经过gzip压缩的页面例如用squid缓存经过nginx压缩的数据。

要注意需要和不需要压缩的对象

1大于1k的纯文本文件html,js,css,xml,html.

2图片视频等不要压缩因为不但不会减小在压缩时消耗cpu和内存资源。

聊聊Nginx开启gzip压缩

Nginx 开启 Gzip 压缩功能 可以使网站的 css、js 、xml、html 文件在传输时进行压缩提高访问速度, 进而优化 Nginx 性能。

网站加载的速度取决于浏览器必须下载的所有文件的大小。减少要传输的文件的大小可以使网站不仅加载更快而且对于那些宽带是按量计费的人来说也更友好。

gzip 是一种流行的数据压缩程序。

您可以使用 gzip 压缩 Nginx 实时文件。这些文件在检索时由支持它的浏览器解压缩好处是 web 服务器和浏览器之间传输的数据量更小速度更快。

gzip 不一定适用于所有文件的压缩。例如文本文件压缩得非常好通常会缩小两倍以上。

另一方面诸如 JPEG或 PNG 文件之类的图像已经按其性质进行压缩使用 gzip 压缩很难有好的压缩效果或者甚至没有效果。压缩文件会占用服务器资源因此最好只压缩那些压缩效果好的文件。

聊聊开启压缩功能的好坏

  1. 好处:

    压缩是可以节省带宽提高传输效率。

  2. 坏处:

    但是由于是在服务器上进行压缩会消耗服务器起源

聊聊Nginx的gzip压缩的原理和优点

Nginx 开启 Gzip 压缩功能 可以使网站的 css、js 、xml、html 文件在传输时进行压缩提高访问速度, 进而优化 Nginx 性能。

网站加载的速度取决于浏览器必须下载的所有文件的大小。减少要传输的文件的大小可以使网站不仅加载更快而且对于那些宽带是按量计费的人来说也更友好。

gzip 是一种流行的数据压缩程序。您可以使用 gzip 压缩 Nginx 实时文件。这些文件在检索时由支持它的浏览器解压缩好处是 web 服务器和浏览器之间传输的数据量更小速度更快。

gzip 不一定适用于所有文件的压缩。例如文本文件压缩得非常好通常会缩小两倍以上。另一方面诸如 JPEG或 PNG 文件之类的图像已经按其性质进行压缩使用 gzip 压缩很难有好的压缩效果或者甚至没有效果。压缩文件会占用服务器资源因此最好只压缩那些压缩效果好的文件。

Nginx gzip配置作用

Nginx 开启 Gzip 压缩功能 可以使网站的 css、js 、xml、html 文件在传输时进行压缩提高访问速度, 进而优化 Nginx 性能! Web 网站上的图片视频等其它多媒体文件以及大文件因为压缩效果不好所以对于图片没有必要支压缩如果想要优化可以图片的生命周期设置长一点让客户端来缓存。

开启 Gzip 功能后Nginx 服务器会根据配置的策略对发送的内容, 如 css、js、xml、html 等静态资源进行压缩, 使得这些内容大小减少在用户接收到返回内容之前对其进行处理以压缩后的数据展现给客户。这样不仅可以节约大量的出口带宽提高传输效率还能提升用户快的感知体验, 一举两得; 尽管会消耗一定的 cpu 资源但是为了给用户更好的体验还是值得的。

经过 Gzip 压缩后页面大小可以变为原来的 30% 甚至更小这样用户浏览页面的时候速度会快得多。Gzip 的压缩页面需要浏览器和服务器双方都支持实际上就是服务器端压缩传到浏览器后浏览器解压并解析。浏览器那里不需要我们担心因为目前的巨大多数浏览器 都支持解析 Gzip 过的页面。

Nginx gzip配置参数

参数

参数描述
gzip on决定是否开启 gzip 模块on 表示开启off 表示关闭
gzip_min_length 1k设置允许压缩的页面最小字节(从 header 头的 Content-Length 中获取) 当返回内容大于此值时才会使用 gzip 进行压缩,以 K 为单位,当值为 0 时所有页面都进行压缩。建议大于 1k
gzip_buffers 4 16k设置 gzip 申请内存的大小其作用是按块大小的倍数申请内存空间,param2:int(k) 后面单位是 k。这里设置以 16k 为单位,按照原始数据大小以 16k 为单位的 4 倍申请内存
gzip_http_version 1.1识别 http 协议的版本,早起浏览器可能不支持 gzip 自解压,用户会看到乱码
gzip_comp_level 2设置 gzip 压缩等级等级越底压缩速度越快文件压缩比越小反之速度越慢文件压缩比越大等级1-9最小的压缩最快 但是消耗 cpu
gzip_types text/plain设置需要压缩的 MIME 类型,非设置值不进行压缩即匹配压缩类型
gzip_vary on启用应答头"Vary: Accept-Encoding"
gzip_proxied offnginx 做为反向代理时启用
gzip_disable msie6IE5.5 和 IE6 SP1 使用 msie6 参数来禁止 gzip 压缩 )指定哪些不需要 gzip 压缩的浏览器(将和User-Agents进行匹配),依赖于 PCRE 库

Nginx gzip参数介绍

gzip on

打开或关闭gzip
默认 off 关闭
代码块 http, server, location, if in location

gzip_buffers

设置用于处理请求压缩的缓冲区数量和大小。比如 32 4K 表示按照内存页one memory page大小以 4K 为单位即一个系统中内存页为 4K申请 32 倍的内存空间。建议此项不设置使用默认值。

Syntax: gzip_buffers number size;
Default:    
gzip_buffers 32 4k|16 8k;
Context:    http, server, location

gzip_comp_level

设置 gzip 压缩级别级别越底压缩速度越快文件压缩比越小反之速度越慢文件压缩比越大

Syntax: gzip_comp_level level;
Default:    
gzip_comp_level 1;
Context:    http, server, location

不是压缩级别越高越好其实 gzip_comp_level 1 的压缩能力已经够用了后面级别越高压缩的比例其实增长不大反而很吃处理性能。

另一方面压缩一定要和静态资源缓存相结合缓存压缩后的版本否则每次都压缩高负载下服务器肯定吃不住。

gzip_disable

通过表达式表明哪些 UA 头不使用 gzip 压缩

Syntax: gzip_disable regex ...;
Default:Context:    http, server, location
This directive appeared in version 0.6.23.

gzip_min_length

当返回内容大于此值时才会使用gzip进行压缩,以 K 为单位,当值为 0 时所有页面都进行压缩。

Syntax: gzip_min_length length;
Default:    
gzip_min_length 20;
Context:    http, server, location

gzip_http_version

用于识别 http 协议的版本早期的浏览器不支持 gzip 压缩用户会看到乱码所以为了支持前期版本加了此选项。默认在 http/1.0 的协议下不开启 gzip 压缩。

Syntax: gzip_http_version 1.0 | 1.1;
Default:    
gzip_http_version 1.1;
Context:    http, server, location

在应用服务器前如果还有一层 Nginx 的集群作为负载均衡在这一层上若果没有开启 gzip。

如果我们使用了proxy_pass 进行反向代理那么 nginx 和后端的 upstream server 之间默认是用 HTTP/1.0 协议通信的。

如果我们的 Cache Server 也是 nginx而前端的 nginx 没有开启 gzip。同时我们后端的 nginx 上没有设置gzip_http_version 为 1.0那么 Cache 的 url 将不会进行 gzip 压缩。

gzip_proxied

Nginx 做为反向代理的时候启用

  1. off – 关闭所有的代理结果数据压缩
  2. expired – 如果header中包含”Expires”头信息启用压缩
  3. no-cache – 如果header中包含”Cache-Control:no-cache”头信息启用压缩
  4. no-store – 如果header中包含”Cache-Control:no-store”头信息启用压缩
  5. private – 如果header中包含”Cache-Control:private”头信息启用压缩
  6. no_last_modified – 启用压缩如果header中包含”Last_Modified”头信息启用压缩
  7. no_etag – 启用压缩如果header中包含“ETag”头信息启用压缩
  8. auth – 启用压缩如果header中包含“Authorization”头信息启用压缩
  9. any – 无条件压缩所有结果数据
Syntax: gzip_proxied off | expired | no-cache | no-store | private | no_last_modified | no_etag | auth | any ...;
Default:    
gzip_proxied off;
Context:    http, server, location

gzip_types

设置需要压缩的 MIME 类型,如果不在设置类型范围内的请求不进行压缩

Syntax: gzip_types mime-type ...;
Default:    
gzip_types text/html;
Context:    http, server, location

gzip_vary

增加响应头”Vary: Accept-Encoding”告诉接收方发送的数据经过了压缩处理开启后的效果是在响应头部添加了Accept-Encoding:gzip这对于本身不支持 gzip 压缩的客户端浏览器有用。

Syntax: gzip_vary on | off;
Default:    
gzip_vary off;
Context:    http, server, location

Nginx gzip 案例

我们首先使用 vim 打开 nginx 的默认配置路径具体命令如下

vim /etc/nginx/conf.d/default.conf

我们执行如上命令打开配置文件此时配置文件如下

现在我们在 nginx 的根路径下新建一个 index.html并写入内容并使用浏览器访问此时浏览器输出如下

现在我们打开 nginx.conf 配置文件如下图所示

在 nginx 的 http 模块的配置里面开启 gzip 配置具体配置如下

gzip  on;
gzip_min_length  1k;
gzip_buffers     4 16k;
gzip_http_version 1.1;
gzip_comp_level 9;
gzip_types       text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php application/javascript application/json;
gzip_disable "MSIE [1-6]\.";
gzip_vary on;

配置完成后如下图所示

现在我们使用 reload 重新加载配置具体命令如下

nginx -s reload

执行完毕后我们再次使用浏览器访问此时输出如下

我们看到此时输出了 gzip并且浏览器的内容如下

我们看到浏览器的内容也正常输出了。

Nginx gzip配置总结

Nginx 开启 Gzip 压缩功能 可以使网站的 css、js 、xml、html 文件在传输时进行压缩提高访问速度, 进而优化 Nginx 性能。

聊聊Nginx是否支持将请求压缩到上游?

您可以使用Nginx模块gunzip将请求压缩到上游。

gunzip模块是一个过滤器它可以对不支持“gzip”编码方法的客户机或服务器使用“内容编码:gzip”来解压缩响应。

聊聊如何在Nginx中获得当前的时间?

要获得Nginx的当前时间必须使用SSI模块、$date_gmt和 $date_local的变量。
Proxy_set_header THE-TIME $date_gmt;

聊聊用Nginx服务器解释-s的目的是什么?

用于运行Nginx -s参数的可执行文件。

聊聊如何在Nginx服务器上添加模块?

在编译过程中必须选择Nginx模块因为Nginx不支持模块的运行时间选择。

Nginx动态添加模块

很多时候我们根据当时的项目情况和业务需求安装完 Nginx 后后续随着业务的发展往往会给安装好的 Nginx 添加其他的功能模块。在为 Nginx 添加功能模块时要求 Nginx 不停机。

这就涉及到如何为已安装的 Nginx 动态添加模块的问题。本文就和小伙伴们一起探讨如何为已安装的 Nginx 动态添加模块的问题。

聊聊如何为Nginx动态添加模块

这里以安装第三方 ngx_http_google_filter_module 模块为例。

Nginx 的模块是需要重新编译 Nginx而不是像 Apache 一样配置文件引用 .so。

下载扩展

下载第三方扩展模块 ngx_http_google_filter_module

# cd /data/software/
# git clone https://github.com/cuber/ngx_http_google_filter_module

查看安装模块

查看 Nginx 编译安装时安装了哪些模块将命令行切换到 Nginx 执行程序所在的目录并输入 ./nginx -V具体如下

[root@binghe sbin]# ./nginx -V
nginx version: nginx/1.19.1
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-17) (GCC) 
built with OpenSSL 1.0.2 22 Jan 2015
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx-1.19.1 --with-openssl=/usr/local/src/openssl-1.0.2 --with-pcre=/usr/local/src/pcre-8.37 --with-zlib=/usr/local/src/zlib-1.2.8 --with-http_ssl_module
[root@binghe sbin]# 

可以看出编译安装 Nginx 使用的参数如下

--prefix=/usr/local/nginx-1.19.1 --with-openssl=/usr/local/src/openssl-1.0.2 --with-pcre=/usr/local/src/pcre-8.37 --with-zlib=/usr/local/src/zlib-1.2.8 --with-http_ssl_module

重新编译

加入需要安装的模块重新编译这里添加 --add-module=/data/software/ngx_http_google_filter_module具体如下

./configure  --prefix=/usr/local/nginx-1.19.1 --with-openssl=/usr/local/src/openssl-1.0.2 --with-pcre=/usr/local/src/pcre-8.37 --with-zlib=/usr/local/src/zlib-1.2.8 --with-http_ssl_module -–add-module=/data/software/ngx_http_google_filter_module

如上将之前安装Nginx的参数全部加上最后添加 --add-module=/data/software/ngx_http_google_filter_module之后我们要进行编译操作如下

# make    //千万不要make install不然就真的覆盖

这里需要注意的是不要执行 make install 命令。

替换nginx二进制文件

# 备份原来的nginx执行程序
# mv /usr/local/nginx-1.19.1/sbin/nginx /usr/local/nginx-1.19.1/sbin/nginx.bak
# 将新编译的nginx执行程序复制到/usr/local/nginx-1.19.1/sbin/目录下
# cp /opt/nginx/sbin/nginx /usr/local/nginx-1.19.1/sbin/

聊聊如何设置超时时间

http {
	keepalive_timeout 60; ###设置客户端连接保持会话的超时时间超过这个时间服务器会关闭该连接。 
	
	tcp_nodelay on; ####打开 tcp_nodelay在包含了 keepalive 参数才有效
	
	client_header_timeout 15; ####设置客户端请求头读取超时时间如果超过这个时间客户端还没有发送任何数据 Nginx 将返回“Request time out(408)”错误
	
	client_body_timeout 15;####设置客户端请求主体读取超时时间如果超过这个时间客户端还没有发送任何数据 Nginx 将返回“Request time out(408)”错误
	
	send_timeout 15; ####指定响应客户端的超时时间。这个超过仅限于两个连接活动之间的时间如果超过这个时间客户端没有任何活动Nginx 将会关闭连接。

}

聊聊Nginx如何限制浏览器和爬虫

Nginx限制爬虫

修改 nginx.conf禁止网络爬虫的 ua返回 403具体配置如下

server{
	listen 80;
	server_name 127.0.0.1; 
	# 添加如下内容即可防止爬虫
	if ($http_user_agent ~* "qihoobot|Baiduspider|Googlebot|Googlebot-Mobile|Googlebot-Image|Mediapartners-Google|Adsbot-Google|Feedfetcher-Google|Yahoo! Slurp|Yahoo! Slurp China|YoudaoBot|Sosospider|Sogou spider|Sogou web spider|MSNBot|ia_archiver|Tomato Bot") 
	{
		return 403;
	}
}

Nginx限制浏览器访问

限制浏览器访问

if ($http_user_agent ~* "Firefox|MSIE")
{
     return 403;
}

Nginx限制IP访问

有时候我们需要针对屏蔽某些恶意的 IP 访问我们的网站或者限制仅仅某些白名单 IP 才能访问我们的网站。

这时候我们就可以在Nginx中通过简单的配置来达到目的。

#添加IP至allow例如我们将10.208.96.192和10.208.96.193加入)
location = /index.html
 { 
  allow 10.208.96.192; 
   allow 10.208.96.193; 
   deny all; 
   root /work/weichuangli; 
  }

屏蔽单个ip访问

# 格式 deny ip;
deny 123.68.23.5;

允许单个ip访问

# 格式 allow ip;
allow 123.68.25.6;

屏蔽所有ip访问

deny all;

允许所有ip访问

allow all;

屏蔽ip段访问

# deny ip/mask
# 屏蔽172.12.62.0到172.45.62.255访问的命令 
deny 172.12.62.0/24;

允许ip段访问

# allow ip/mask
# 屏蔽172.102.0.0到172.102.255.255访问的命令 
allow 172.102.0.0/16;

聊聊502报错可能原因有哪些

1FastCGI进程是否已经启动

2FastCGI worker进程数是否不够

3FastCGI执行时间过长

4FastCGI Buffer不够

nginx和apache一样有前端缓冲限制可以调整缓冲参数

fastcgi_buffer_size 32k;   
fastcgi_buffers 8 32k;

5Proxy Buffer不够

如果你用了Proxying调整

proxy_buffer_size 16k;  
proxy_buffers 4 16k;

6php脚本执行时间过长

将php-fpm.conf的<value name="request_terminate_timeout">0s</value>的0s改成一个时间

聊聊Nginx 如何解决跨域问题

跨域是前端开发中经常会遇到的问题前端调用后台服务时通常会遇到 No ‘Access-Control-Allow-Origin’ header is present on the requested resource 的错误这是因为浏览器的同源策略拒绝了我们的请求。

所谓同源是指域名协议端口相同浏览器执行一个脚本时同源的脚本才会被执行。

如果非同源那么在请求数据时浏览器会在控制台中报一个异常提示拒绝访问。

这个问题我们通常会使用 CORS(跨源资源共享)或者 JSONP 去解决这两种方法也是使用较多的方法。

细聊Nginx 如何 解决跨域问题

什么是跨域

跨域是前端开发中经常会遇到的问题前端调用后台服务时通常会遇到 No ‘Access-Control-Allow-Origin’ header is present on the requested resource 的错误这是因为浏览器的同源策略拒绝了我们的请求。

所谓同源是指域名协议端口相同浏览器执行一个脚本时同源的脚本才会被执行。如果非同源那么在请求数据时浏览器会在控制台中报一个异常提示拒绝访问。这个问题我们通常会使用 CORS(跨源资源共享)或者 JSONP 去解决这两种方法也是使用较多的方法。

Nginx解决跨域方案一

解决跨域

这个使用 Nginx 的代理功能即可在 a 服务器的 Nginx 添加如下示例配置

location ~ /xxx/ {
	proxy_pass http://b.com;
}

这样就把路径中带有 /xxx/ 的请求都转到了 b.com。如果不需要保存 cookie保持 session 这样的功能这样就可以了。

然而本项目就是要用到 cookie所以就有了下边的内容。

设置domain

因为 cookie 当中是有 domain 的两个服务器的一般不同比如 a 服务器返回的 Response Headers 中是

Set-Cookie:JSESSIONID=_3y4u02v4cbpBw10DoCrMSnjg7m34xuum1XRWBF1Uno; path=/; domain=a.com

而 b 服务器返回的是

Set-Cookie:JSESSIONID=_3y4u02v4cbpBw10DoCrMSnjg7m34xuum1XRWBF1Uno; path=/; domain=b.com

这时候如果 a 项目的页面调用了 b 的接口浏览器发现接口返回的 domain 不是 a.com就不会把 cookie 保存起来session 也就失效了。Nginx 引入了 proxy_cookie_domain 来解决这个问题。示例

location ~ /xxx/ {
	proxy_cookie_domain b.com a.com;
	proxy_pass http://b.com;
}

这样就可以在 Nginx 转接请求的时候自动把 domain 中的 b.com 转换成 a.com这样 cookie 就可以设置成功了。

但是对于有些情况这样转换不灵光。比如b 项目的 domain 是 .b.com前边多了一个小点那对应的改为 proxy_cookie_domain .b.com a.com; 可以不通过实践不行

通过查看 Nginx 文档找到了解决办法。其实除了上边那种配置方式外Nginx 还支持正则配置

location ~ /xxx/ {
	proxy_cookie_domain ~\.?b.com a.com;
	proxy_pass http://b.com;
}

这样就可以把 domain 中的 .b.com 转换成 a.com 啦。

设置path

正常情况下完成以上两步就可以了因为 cookie 中的 path 一般默认的是 path=/也就是所有请求都可以访问本 cookie。但有些服务器会指定只允许某个层级下的请求可以访问 cookie比如

Set-Cookie:JSESSIONID=_3y4u02v4cbpBw10DoCrMSnjg7m34xuum1XRWBF1Uno; path=/sub/; domain=b.com

这样就只允许相对根路径以 /sub/ 开头的请求路径才能访问 cookie。这时候就又可能出现 cookie 无效的问题了为了解决这个问题可以使用 proxy_cookie_path。示例

location ~ /xxx/ {
	proxy_cookie_domain ~\.?b.com a.com;
	proxy_cookie_path /sub/ /;
	proxy_pass http://b.com;
}

这样就把只允许 /sub/ 层级下的请求访问 cookie改为允许所有请求访问 cookie 了。

Nginx解决跨域方案二

或者我们也可以直接简单粗暴的设置全局配置了如下

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    #连接超时时间服务器会在这个时间过后关闭连接。
    keepalive_timeout  10;
    # gizp压缩
    gzip  on;
    # 直接请求nginx也是会报跨域错误的这里设置允许跨域
    # 如果代理地址已经允许跨域则不需要这些, 否则报错(虽然这样nginx跨域就没意义了)
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Headers X-Requested-With;
    add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
    # srever模块配置是http模块中的一个子模块用来定义一个虚拟访问主机
    server {
        listen       80;
        server_name  localhost;
        # 根路径指到index.html
        location / {
            root   html;
            index  index.html index.htm;
        }
        # localhost/api 的请求会被转发到192.168.0.103:8080
        location /api {
            rewrite ^/b/(.*)$ /$1 break; # 去除本地接口/api前缀, 否则会出现404
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://192.168.0.103:8080; # 转发地址
        }
        # 重定向错误页面到/50x.html
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

聊聊漏桶流算法和令牌桶算法知道

漏桶算法

漏桶算法是网络世界中流量整形或速率限制时经常使用的一种算法它的主要目的是控制数据注入到网络的速率平滑网络上的突发流量。漏桶算法提供了一种机制通过它突发流量可以被整形以便为网络提供一个稳定的流量。也就是我们刚才所讲的情况。漏桶算法提供的机制实际上就是刚才的案例突发流量会进入到一个漏桶漏桶会按照我们定义的速率依次处理请求如果水流过大也就是突发流量过大就会直接溢出则多余的请求会被拒绝。所以漏桶算法能控制数据的传输速率。

令牌桶算法

令牌桶算法是网络流量整形和速率限制中最常使用的一种算法。典型情况下令牌桶算法用来控制发送到网络上的数据的数目并允许突发数据的发送。Google开源项目Guava中的RateLimiter使用的就是令牌桶控制算法。令牌桶算法的机制如下存在一个大小固定的令牌桶会以恒定的速率源源不断产生令牌。如果令牌消耗速率小于生产令牌的速度令牌就会一直产生直至装满整个令牌桶。

参考

限流计数器、漏桶、令牌桶 三大算法的原理与实战史上最全

聊聊Nginx限流怎么做的

Nginx限流就是限制用户请求速度防止服务器受不了

限流有3种

  1. 正常限制访问频率正常流量
  2. 突发限制访问频率突发流量
  3. 限制并发连接数

Nginx的限流都是基于漏桶流算法底下会说道什么是漏桶流

正常限制访问频率正常流量

限制一个用户发送的请求我Nginx多久接收一个请求。

Nginx中使用ngx_http_limit_req_module模块来限制的访问频率限制的原理实质是基于漏桶算法原理来实现的。在nginx.conf配置文件中可以使用limit_req_zone命令及limit_req命令限制单个IP的请求处理频率。

#定义限流维度一个用户一分钟一个请求进来多余的全部漏掉
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/m;

#绑定限流维度
server{
		
	location/seckill.html{
		limit_req zone=zone;	
		proxy_pass http://lj_seckill;
	}
}

突发限制访问频率突发流量

限制一个用户发送的请求我Nginx多久接收一个。

上面的配置一定程度可以限制访问频率但是也存在着一个问题如果突发流量超出请求被拒绝处理无法处理活动时候的突发流量这时候应该如何进一步处理呢Nginx提供burst参数结合nodelay参数可以解决流量突发的问题可以设置能处理的超过设置的请求数外能额外处理的请求数。我们可以将之前的例子添加burst参数以及nodelay参数

#定义限流维度一个用户一分钟一个请求进来多余的全部漏掉
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/m;
  
#绑定限流维度
server{
  		
  	location/seckill.html{
  		limit_req zone=zone burst=5 nodelay;
  		proxy_pass http://lj_seckill;
  	}
  }

为什么就多了一个 burst=5 nodelay; 呢多了这个可以代表Nginx对于一个用户的请求会立即处理前五个多余的就慢慢来落没有其他用户的请求我就处理你的有其他的请求的话我Nginx就漏掉不接受你的请求

限制并发连接数

Nginx中的ngx_http_limit_conn_module模块提供了限制并发连接数的功能可以使用limit_conn_zone指令以及limit_conn执行进行配置。接下来我们可以通过一个简单的例子来看下

http {
    limit_conn_zone $binary_remote_addr zone=myip:10m;
    limit_conn_zone $server_name zone=myServerName:10m;
}
    
server {
    location / {
        limit_conn myip 10;
        limit_conn myServerName 100;
        rewrite / http://www.lijie.net permanent;
    }
}

上面配置了单个IP同时并发连接数最多只能10个连接并且设置了整个虚拟服务器同时最大并发数最多只能100个链接。当然只有当请求的header被服务器处理后虚拟服务器的连接数才会计数。刚才有提到过Nginx是基于漏桶算法原理实现的实际上限流一般都是基于漏桶算法和令牌桶算法实现的。接下来我们来看看两个算法的介绍

聊聊限流了解吗怎么限流的

Nginx 提供两种限流方式一是控制速率二是控制并发连接数。

1、控制速率 限流

ngx_http_limit_req_module 模块提供了漏桶算法(leaky bucket)可以限制单个IP的请求处理频率。

Nginx限流使用的是leaky bucket算法

限流计数器、漏桶、令牌桶 三大算法的原理与实战史上最全

控制速率基本原理

我们从最简单的限流配置开始

limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=10r/s;

server {
    location /login/ {
        limit_req zone=ip_limit;
        proxy_pass http://login_upstream;
    }
}
  • $binary_remote_addr 针对客户端ip限流
  • zone=ip_limit:10m 限流规则名称为ip_limit允许使用10MB的内存空间来记录ip对应的限流状态
  • rate=10r/s 限流速度为每秒10次请求
  • location /login/ 对登录进行限流

限流速度为每秒10次请求如果有10次请求同时到达一个空闲的nginx他们都能得到执行吗

空桶

漏桶漏出请求是匀速的。

10r/s是怎样匀速的呢每100ms漏出一个请求。

在这样的配置下桶是空的所有不能实时漏出的请求都会被拒绝掉。

所以如果10次请求同时到达那么只有一个请求能够得到执行其它的都会被拒绝。

这不太友好大部分业务场景下我们希望这10个请求都能得到执行。

Burst

我们把配置改一下解决上一节的问题

limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=10r/s;

server {
    location /login/ {
        limit_req zone=ip_limit burst=12;
        proxy_pass http://login_upstream;
    }
}
  • burst=12 漏桶的大小设置为12

Burst

逻辑上叫漏桶实现起来是FIFO队列把得不到执行的请求暂时缓存起来。

这样漏出的速度仍然是100ms一个请求但并发而来暂时得不到执行的请求可以先缓存起来。只有当队列满了的时候才会拒绝接受新请求。

这样漏桶在限流的同时也起到了削峰填谷的作用。

在这样的配置下如果有10次请求同时到达它们会依次执行每100ms执行1个。

虽然得到执行了但因为排队执行延迟大大增加在很多场景下仍然是不能接受的。

NoDelay

继续修改配置解决Delay太久导致延迟增加的问题

limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=10r/s;

server {
    location /login/ {
        limit_req zone=ip_limit burst=12 nodelay;
        proxy_pass http://login_upstream;
    }
}

nodelay 把开始执行请求的时间提前以前是delay到从桶里漏出来才执行现在不delay了只要入桶就开始执行

NoDelay

要么立刻执行要么被拒绝请求不会因为限流而增加延迟了。

因为请求从桶里漏出来还是匀速的桶的空间又是固定的最终平均下来还是每秒执行了5次请求限流的目的还是达到了。

但这样也有缺点限流是限了但是限得不那么匀速。以上面的配置举例如果有12个请求同时到达那么这12个请求都能够立刻执行然后后面的请求只能匀速进桶100ms执行1个。如果有一段时间没有请求桶空了那么又可能出现并发的12个请求一起执行。

大部分情况下这种限流不匀速不算是大问题。不过nginx也提供了一个参数才控制并发执行也就是nodelay的请求的数量。

limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=10r/s;

server {
    location /login/ {
        limit_req zone=ip_limit burst=12 delay=4;
        proxy_pass http://login_upstream;
    }
}

delay=4 从桶内第5个请求开始delay

DelayNum

这样通过控制delay参数的值可以调整允许并发执行的请求的数量使得请求变的均匀起来在有些耗资源的服务上控制这个数量还是有必要的。

控制速率 基本原理讲完了

接下来开始 控制速率 限流 的基础配置

1.1 控制速率 限流 的基础配置

基于客户端192.168.1.1进行限流

定义了一个大小为10M名称为myLimit的内存区用于存储IP地址访问信息。
rate设置IP访问频率rate=5r/s表示每秒只能处理每个IP地址的5个请求。

http {
	limit_req_zone 192.168.1.1 zone=myLimit:10m rate=5r/s;
}

server {
	location / {
		limit_req zone=myLimit;
		rewrite / http://www.hac.cn permanent;
	}
}

参数解释

limit_req_zone: 定义需要限流的对象。
zone: 定义共享内存区来存储访问信息。
rate: 用于设置最大访问速率。

Nginx限流是按照毫秒级为单位的也就是说1秒处理5个请求会变成每200ms只处理一个请求。如果200ms内已经处理完1个请求但是还是有有新的请求到达这时候Nginx就会拒绝处理该请求。

1.2 突发流量限制 访问频率

上面rate设置了 5r/s

如果有时候流量突然变大超出的请求就被拒绝返回503了突发的流量影响业务就不好了。

这时候可以加上burst 参数一般再结合 nodelay 一起使用。

server {
	location / {
		limit_req zone=myLimit burst=20 nodelay;
		rewrite / http://www.hac.cn permanent;
	}
}

burst=20 nodelay 表示这20个请求立马处理不能延迟相当于特事特办。不过即使这20个突发请求立马处理结束后续来了请求也不会立马处理。

burst=20 相当于缓存队列中占了20个坑即使请求被处理了这20个位置也只能按 100ms一个来释放。

2、控制并发连接数

ngx_http_limit_conn_module 提供了限制连接数功能。

主要是利用limit_conn_zone和limit_conn两个指令。

利用连接数限制 某一个用户的ip连接的数量来控制流量。

limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m; 

server {  
    listen       80;
    server_name  localhost;
    charset utf-8;
    location / {
        limit_conn perip 10;      # 单个客户端ip与服务器的连接数.
        limit_conn perserver 100; #限制与服务器的总连接数
        root   html;
        index  index.html index.htm;
    }
}

limit_conn perip 10 作用的key 是 $binary_remote_addr表示限制单个IP同时最多能持有10个连接。
limit_conn perserver 100 作用的key是 $server_name表示虚拟主机(server) 同时能处理并发连接的总数。

聊聊nginx如何配置https

#server端基本配置 server {
listen 80;
listen 443 ssl spdy;
server_name io.123.com;
include   ssl/io.com;      #注意看下一个文件
location / {
proxy_pass http:``//lb_io;
if``($scheme = http ) {
return``301 https:``//$host$request_uri;    #此项配置为转换为https的基本配置
}
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection``"upgrade"``;
}
access_log /data/logs/nginx/access/niuaero.log main;
}
ssl_certificate   ssl/ca/io.com.pem;    #这个为购买的https证书供应商会生成
ssl_certificate_key ssl/ca/io.com.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#启用TLS1.1、TLS1.2要求OpenSSL1.0.1及以上版本若您的OpenSSL版本低于要求请使用 ssl_protocols TLSv1;
ssl_ciphers HIGH:!RC4:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!EXP:+MEDIUM;
ssl_prefer_server_ciphers ``on``;

聊聊Nginx常用优化配置

  1. 调整worker_processes指定Nginx需要创建的worker进程数量刚才有提到worker进程数一般设置为和CPU核心数一致。
  2. 调整worker_connections设置Nginx最多可以同时服务的客户端数。结合worker_processes配置可以获得每秒可以服务的最大客户端数。
  3. 启动gzip压缩可以对文件大小进行压缩减少了客户端http的传输带宽可以大幅度提高页面的加载速度。
  4. 启用缓存如果请求静态资源启用缓存是可以大幅度提升性能的。

聊聊Nginx常见的优化配置有哪些

1、调整worker_processes

指Nginx要生成的worker数量,最佳实践是每个CPU运行1个工作进程。

了解系统中的CPU核心数输入

$ grep processor / proc / cpuinfo | wc -l

2、最大化worker_connections

Nginx Web服务器可以同时提供服务的客户端数。与worker_processes结合使用时获得每秒可以服务的最大客户端数

最大客户端数/秒=工作进程*工作者连接数

为了最大化Nginx的全部潜力应将工作者连接设置为核心一次可以运行的允许的最大进程数1024。

3、启用Gzip压缩

压缩文件大小减少了客户端http的传输带宽因此提高了页面加载速度

建议的gzip配置示例如下:( 在http部分内

4、为静态文件启用缓存

为静态文件启用缓存以减少带宽并提高性能可以添加下面的命令限定计算机缓存网页的静态文件

location ~* .(jpg|jpeg|png|gif|ico|css|js)$ {  
    expires 365d;  
}

5、Timeouts

keepalive连接减少了打开和关闭连接所需的CPU和网络开销获得最佳性能需要调整的变量可参考

6、禁用access_logs

访问日志记录它记录每个nginx请求因此消耗了大量CPU资源从而降低了nginx性能。

完全禁用访问日志记录

access_log off;

如果必须具有访问日志记录则启用访问日志缓冲

配置如下

access_log /var/log/nginx/access.log main buffer=32k flush=1m;

当系统处于负载状态时启用日志缓冲区以降低 nginx worker 进程阻塞。

大量的磁盘读写和 cpu 资源使用对于服务器资源也是一种巨大消耗。

将日志数据缓冲到内存中可能是很小的一个优化手段 buffer 参数意义是缓冲区的大小功能是当缓冲区已经写满时日志会被写入文件中

flush 参数意义是缓冲区内日志在缓冲区内存中保存的最长时间功能即当缓存中的日志超过最大缓存时间也会被写入到文件中 不足的地方即写入到日志文件的日志有些许延迟即时调试中应当关闭日志缓冲。 。

7、指令定义错误日志目录及记录错误日志的等级

为了精确定位 nginx 的错误日志使用自带的 error_log 指令定义错误日志目录及记录错误日志的等级配置如下

Bash

error_log /var/log/nginx/error.log warn;

error_log 指令配置时需要一个必选的日志目录和一个可选的错误等级选项。

除 if 指令外 error_log 指令能在所有的上下文中使用。错误日志等级包括

debug、info、notice、warn、error、crit、alert 和 emerg。给出的日志

等级顺序就是记录最小到最严谨的日志等级顺序。需要注意的是 debug 日志

需要在编译 nginx 服务器时带上 --with-debug 标识才能使用。

当服务器配置出错时首先需要查看错误日志以定位问题。错误日志

也是定位应用服务器(如 FastCGI 服务)的利器。

通过错误日志我们可以调试 worker 进程连接错误、内存分配、客户端 IP 和 应用服务器等问题。

错误日志格式不支持自定义日志格式 但他同样记录当前时间、日志等级和具体信息等数据。

注意错误日志的默认设置适用于全局。

要覆盖它请将 error_log 指令放在 main 顶级配置上下文中。 error_log 在开源 NGINX 1.5.2 版中添加了在同一配置级别指定多个指令的功能。

细致聊聊如何进行Nginx的调优

1、worker_processes的进程数数量要与CPU数量一致通过lscpu查看

worker_processes 1; 

2.1 worker process打开文件数的优化

worker_rlimit_nofile 65535;

2.2 优化了nginx的worker进程最多打开数量的参数之后还需要优化系统内核参数允许打开最多文件的参数

临时配置
ulimit -Hn 100000
ulimit -Sn 100000     
永久配置
vim /etc/security/limits.conf
* soft nofile 100000
* hard nofile 100000

3、单个进程最大连接数的优化

events {
    worker_connections 2048;
    multi_accept on;
    use epoll;
}

4、隐藏版本信息的优化

server_tokens off;

5、高效文件传输模式的

sendfile on;
tcp_nopush on;
tcp_nodelay on;

6、访问日志关闭的优化

access_log off;

7、超时时间的优化

keepalive_timeout 10; //设置客户端保持活动状态的超时时间
client_header_timeout 10; //客户端请求头读取超时时间
client_body_timeout 10; //客户端请求体读取超时时间
reset_timedout_connection on; //在客户端停止响应之后,允许服务器关闭连接,释放socket关联的内存
send_timeout 10; //指定客户端的超时时间如果在10s内客户端没有任何响应nginx会自动断开连接

8、gzip的优化

gzip on;//开启压缩
gzip_min_length 1000;//小文件不压缩
gzip_comp_level 6;//压缩比例
gzip_types text/plain text/css application/json application/x-javascript text/xml
application/xml application/xml+rss text/javascript;//对指定文件类型进行压缩

9、缓存静态页面的优化 文件句柄是打开文件的唯一标示

open_file_cache max=100000 inactive=20s; //设置服务器最大缓存10万个文件句柄关闭20s内无请求的句柄
open_file_cache_valid 30s;//文件句柄的有效期为30s
open_file_cache_min_uses 2;//最少打开2次才会被缓存
open_file_cache_errors on;

参考文献

限流计数器、漏桶、令牌桶 三大算法的原理与实战史上最全

推荐阅读

Docker面试题史上最全 + 持续更新
场景题假设10W人突访你的系统如何做到不 雪崩
尼恩Java面试宝典
Springcloud gateway 底层原理、核心实战 (史上最全)
Flux、Mono、Reactor 实战史上最全
sentinel 史上最全
Nacos (史上最全)
分库分表 Sharding-JDBC 底层原理、核心实战史上最全
TCP协议详解 (史上最全)
clickhouse 超底层原理 + 高可用实操 史上最全
nacos高可用图解+秒懂+史上最全
队列之王 Disruptor 原理、架构、源码 一文穿透
环形队列、 条带环形队列 Striped-RingBuffer 史上最全
一文搞定SpringBoot、SLF4j、Log4j、Logback、Netty之间混乱关系史上最全
单例模式史上最全
红黑树 图解 + 秒懂 + 史上最全
分布式事务 秒懂
缓存之王Caffeine 源码、架构、原理史上最全10W字 超级长文
缓存之王Caffeine 的使用史上最全
Java Agent 探针、字节码增强 ByteBuddy史上最全
Docker原理图解+秒懂+史上最全
Redis分布式锁图解 - 秒懂 - 史上最全
Zookeeper 分布式锁 - 图解 - 秒懂
Zookeeper Curator 事件监听 - 10分钟看懂
Netty 粘包 拆包 | 史上最全解读
Netty 100万级高并发服务器配置
Springcloud 高并发 配置 一文全懂

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: nginx