Nginx面试常见问题

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
EMR Serverless StarRocks,5000CU*H 48000GB*H
简介: 吐血给大家整理了一些面试官常问到的有关Nginx的问题

image-20220916155106757.png
什么是Nginx?

Nginx是一个轻量级(消耗资源小)、高性能(处理2-3万并发连接数)的反向代理web服务器,支持HTTP、HTTPS、SMTP、POP3 和 IMAP 协议;可以实现反向代理、负载均衡的功能

Nginx有哪些优点

  1. 跨平台、配置简单
  2. 采用异步非阻塞网络I/O,支持高并发连接(官方监测能支持 5 万并发)
  3. 轻量,开启10个Nginx才占150M内存
  4. 开源,成本低
  5. 稳定性高,支持不停机升级(热升级)
  6. 内置健康检查功能,实现服务的高可用

Nginx有哪些常见应用场景?

  1. Http服务器。Nginx支持Http、Https协议。可以提供Http服务,称为网页静态服务器
  2. 虚拟主机。Nginx可以在一台服务器上搭建多个虚拟网站
  3. 负载均衡。当面对一些高并发大流量的场景时,Nginx可以将流量均衡的分发到后端的服务器集群,使后端每台服务器能够平坦压力;而且对客户端是透明的,即客户端认为自己访问的是后端服务器,其实访问的是Nginx服务器,Nginx服务器对后端服务器集群进行了隔离保护
  4. 反向代理。Nginx服务器将客户端请求代理到后端服务器集群上。对客户端透明,即客户端认为自己访问的是后端服务器,其实访问的是Nginx服务器;对后端服务器进行了隔离,保证了后端服务器的安全

Nginx怎么实现高并发

一句话概括:采用异步非阻塞IO机制+epoll事件驱动模型

简单来说,每当有一个请求进来,就会有一个worker进程去负责处理,但不是全程负责,它处理到可能发生阻塞的地方(比如说向后端服务器转发request,并等待后端服务器返回结果),在等待返回结果这段时间里worker进程不会傻傻等着,它会在转发完请求后注册一个事件——“如果结果返回了就通知我一声,我再接着处理”,之后就休息去了

如果再有请求进来,worker进程就可以按上面那种方式去处理请求;一旦后端服务器的结果返回了,worker才会回来继续处理请求

关于这个内容我会专门拿出一个章节来讲

正向代理&反向代理

  • 正向代理

image-20220916110118404.png
位于客户端和后端服务器之间,将客户端的请求代理到后端服务器(替客户端去发起请求)

客户端明确的知道要访问的服务器地址。但是后端服务器只清楚是哪个代理服务器发来请求,它并不知道这个请求来自于哪个具体的客户端(即屏蔽了客户端的具体信息)

例子:VPN、运营商

  • 反向代理

image-20220916110346855.png
位于客户端和后端服务器之间,多个客户端给服务器发送请求,反向代理服务器(例如Nginx)收到之后,按照一定的规则将请求分发给后面的服务器来处理

反向代理模式将后端服务器隔离起来(客户端并不知道自己访问的是一个代理),能够保证后端服务器的安全

为什么Nginx不使用多线程

Nginx是多进程/单线程模式,进程之间是相互独立的,不共享资源,不需要加锁,一 个worker进程挂了不会影响到其他worker进程

一个进程退出后, 其它进程还在工作,服务不会中断,master 进程则很快重新启动新的 worker 进程

Nginx和Apache的异同之处

  • 相同点

    • web服务器,提供http服务
    • 可以实现负载均衡和反向代理的功能
  • 差异点

    • Nginx是一个基于事件的web服务器;apache是一个基于流程的服务器
    • Nginx采取异步非阻塞网络IO;Apache采取了同步阻塞网络IO;Nginx的抗高并发能力会更好,可以同时处理更多请求
    • Nginx更加轻量化,占用更少的内存和资源
    • Apache性能更稳定,比Nginx的bug要少

Nginx负载均衡的算法怎么实现的?策略有哪些?

  • RR(轮询)

将接收到的请求按照顺序逐一分发到不同的后端服务器,如果某台后端服务器出现故障或者宕机,会自动去除故障服务器,使用户访问不受影响

upstream backserver { 
 server 192.168.0.1; 
 server 192.168.0.2; 
} 
  • weight(加权轮询)

指带权重值的轮询算法,weight值越大,分配到的概率也就越高

主要用于后端每台服务器性能不均衡的情况,或者说仅仅为在主从的情况下设置不同的权重(weight)值,可以有效的利用服务器资源

# 权重越高,在被访问的概率越大。如例,分别是20%,80%。
upstream backserver { 
 server 192.168.0.1 weight=2; 
 server 192.168.0.2 weight=8; 
} 
  • ip_hash(ip绑定)

将来自于同一个源ip地址的请求始终分发到第一次分配到的后端服务器

upstream backserver { 
 ip_hash; 
 server 192.168.0.1; 
 server 192.168.0.2; 
} 
  • url_hash(url哈希)

按照访问的url的哈希结果来进行分配,每个相同请求的url会被定向到某一台后端服务器,进一步提高后端服务器缓存的效率

如果要使用这种算法,则需要安装Nginx的hash软件包

upstream backserver { 
 server squid1:3128; 
 server squid2:3128; 
 hash $request_uri; 
 hash_method crc32; 
} 
  • fair(智能调度)

以根据后端服务器的响应请求时间智能地进行均衡分发,比如说响应时间短的优先分配。如果要使用这种算法,则需要安装upstream_fair模块

# 哪个服务器的响应速度快,就将请求分配到那个服务器上。
upstream backserver { 
 server server1; 
 server server2; 
 fair; 
} 

能聊聊location吗?

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

  • location优先级
匹配符 匹配规则 优先级
= 精确匹配 1
^~ 以某个字符串开头普通匹配 2
~ 区分大小写的正则匹配 3
~* 不区分大小写的正则匹配 4
!~ 区分大小写不匹配的正则 5
!~* 不区分大小写不匹配的正则 6
/ 普通匹配,任何请求都会匹配到 7
  • location匹配规则

首先精确匹配优先级最高,如果没有精确匹配的话就进行普通匹配,然后保存具有最长匹配前缀的结果(注意这里是保存,而不是匹配完成)

保存结果后开始正则匹配,如果有正则匹配则按照配置里正则表达式出现的顺序进行匹配(匹配最先出现那个),匹配到之后返回正则匹配结果

如果没有正则匹配就返回具有最长匹配前缀的结果(即一开始保存那个)

PS:如果最长匹配前缀有^~,则忽略正则匹配,直接返回结果

Nginx如何实现后端服务健康检查

  • 利用 nginx 自带模块 ngx_http_proxy_module 和 ngx_http_upstream_module 对后端节点做健康检查
  • 利用 nginx_upstream_check_module 模块对后端节点做健康检查(推荐使用这个

生产中如何设置worker进程的数量呢

推荐设置成auto模式,即根据系统CPU个数来自动分配worker进程

Nginx 如何处理高并发

在Nginx里面,一般我们使用异步非阻塞处理请求方式+epoll机制的IO多路复用网络I/O模型

什么是异步同步,什么是阻塞非阻塞

  • 异步:程序执行 I/O 操作后,不用等待完成和完成后的响应,而是继续执行就可以。等到这次 I/O 完成后,响应会用事件通知的方式,告诉应用程序
  • 同步:程序执行 I/O 操作后,要一直等到整个 I/O 完成后,才能获得 I/O 响应
  • 阻塞:程序执行I/O操作后,如果没有获得响应,就会阻塞当前线程,自然就不能执行其他任务
  • 非阻塞:程序执行I/O操作后,不会阻塞当前线程,可以继续执行其他任务,随后通过轮询或者事件通知的形式获取调用的结果

在Nginx里面,每个worker进程接收到客户端的请求之后,会进行相关的操作然后等待响应/结果,在等待的这个过程中worker进程是可以去处理其他请求的(非阻塞)

而Nginx客户端这时候也无需等待,可以去处理其他事件(异步)

如果响应/结果返回,就会通知worker进程(事件通知),这时候worker就会去返回处理请求

I/O事件通知

在介绍I/O多路复用之前,我们先来看一下I/O事件通知

I/O事件通知可分为水平触发(Level Trigger)和边缘触发(Eage Trigger)

  • 水平触发(LT)

文件描述符的状态没有改变(可以非阻塞的执行I/O),就会触发通知。也就是说,应用程序可以随时检查文件描述符的状态,然后再根据状态,进行 I/O 操作

读操作:

  1. 读缓冲区中有数据,且数据被读出一部分缓冲区还不为空

写操作:

  1. 写缓冲区还没满,还能继续写
  • 边缘触发(ET)

只有在文件描述符的状态发生改变(也就是 I/O 请求达到)时,才发送一次通知

这时候,应用程序需要尽可能多地执行 I/O,直到无法继续读写,才可以停止。

如果 I/O 没执行完,或者因为某种原因没来得及处理,那么这次通知也就丢失了

读操作:

  1. buffer由不可读状态变为可读状态(由空变为不空)
  2. 当有新数据到达时,即缓冲区中的待读数据变多的时候
  3. 当缓冲区有数据可读,且应用进程对相应的描述符进行EPOLL_CTL_MOD 修改EPOLLIN事件时

写操作:

  1. buffer由不可写变为可写(由空变为不空)
  2. 缓冲区中的内容变少(有数据被发送走)
  3. 当缓冲区有空间可写,且应用进程对相应的描述符进行EPOLL_CTL_MOD 修改EPOLLOUT事件时

IO多路复用

I/O多路复用也就是我们见到的select、poll、epoll

  • select和poll

selct和poll均采用非阻塞I/O+水平触发通知

selct和poll从文件描述符中找出哪些可以进行I/O操作,然后执行,由于是非阻塞I/O,一个线程可以同时监控一批套接字的文件描述符,就达到了单线程处理多请求的目的

但是selct和poll是对套接字的文件描述符列表进行轮询,请求多的时候就会比较耗时

而且程序每次调用select和poll时,需要把fd列表从用户空间传入内核空间,内核修改后再传出用户空间,消耗了两次系统调用,增加了处理成本

select使用固定长度的数组来表示fd的集合,所以会有最大描述符数量的限制,但是poll使用pollfd指针,没有最大描述符数量的限制(优于select)

  • epoll

epoll使用红黑树,在内核中管理fd的集合,相较于select和poll少了两次系统调用,减少成本

epoll使用事件驱动的机制,而非select和poll的轮询;只关注有I/O事件发生的fd

由于epoll采用边缘触发通知机制,当有边缘触发时,应用程序就需要尽可能地多执行I/O

#为什么边缘触发机制下一旦有通知程序要尽可能I/O?
因为边缘触发的原理是文件描述符的状态发生改变才会触发通知,之后便不再触发
例如进行读操作时,buffer有不可读变为可读,触发一次边缘通知,程序开始读buffer里的内容,如果没有读完,buffer里面剩余的内容是不会再次触发边缘通知的,就有可能导致读数据丢失

Nginx常见工作模型

  • 主进程 + 多个 worker 子进程

这是最常用的一种模型,主进程fork出多个子进程,每个子进程来处理请求

为啥使用多进程模式的Nginx性能还这么好?

其实这些worker进程实际上并不需要经常创建和销毁,而是在没任务时休眠,有任务时唤醒,只有在 worker 由于某些异常退出时,主进程才需要创建新的进程来代替它
image-20220916154154579.png
但是这种模型会存在一个惊群问题,即当有网络请求过来时,多个进程会被同时唤醒,但实际上只有一个进程来响应这个事件,其他被唤醒的进程都会重新休眠

为了避免惊群问题,Nginx在每个worker进程中都增加了一个全局锁((accept_mutex)。这些 worker 进程需要首先竞争到锁,只有竞争到锁的进程,才会加入到 epoll 中,这样就确保只有一个 worker 子进程被唤醒)

  • 多进程监听相同端口模型

在这种方式下,所有的进程都监听相同的接口,并且开启 SO_REUSEPORT 选项,由内核负责将请求负载均衡到这些监听进程中去

由于内核确保了只有一个进程被唤醒,就不会出现惊群问题了
image-20220916154812689.png

相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
5月前
快速排序--面试最常见问题
快速排序--面试最常见问题
31 1
|
1月前
|
负载均衡 算法 Java
腾讯面试:说说6大Nginx负载均衡?手写一下权重轮询策略?
尼恩,一位资深架构师,分享了关于负载均衡及其策略的深入解析,特别是基于权重的负载均衡策略。文章不仅介绍了Nginx的五大负载均衡策略,如轮询、加权轮询、IP哈希、最少连接数等,还提供了手写加权轮询算法的Java实现示例。通过这些内容,尼恩帮助读者系统化理解负载均衡技术,提升面试竞争力,实现技术上的“肌肉展示”。此外,他还提供了丰富的技术资料和面试指导,助力求职者在大厂面试中脱颖而出。
腾讯面试:说说6大Nginx负载均衡?手写一下权重轮询策略?
|
1月前
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
67 2
|
1月前
|
缓存 负载均衡 应用服务中间件
解决Nginx常见问题的技术指南
解决Nginx常见问题的技术指南
139 0
|
3月前
|
缓存 负载均衡 算法
面试准备-nginx
面试准备-nginx
|
3月前
|
JavaScript 前端开发 Java
常见问题:Go的面试问题和答案(2)
常见问题:Go的面试问题和答案(2)
|
3月前
|
存储 Java 程序员
常见问题:Go的面试问题和答案(1)
常见问题:Go的面试问题和答案(1)
|
4月前
|
负载均衡 网络协议 Unix
Nginx 面试题总结大全
Nginx 面试题总结大全
89 0
|
5月前
|
存储 NoSQL MongoDB
MongoDB实战面试指南:常见问题一网打尽
MongoDB实战面试指南:常见问题一网打尽
|
5月前
|
前端开发 应用服务中间件 程序员
老程序员分享:Nginx相关面试题
老程序员分享:Nginx相关面试题
57 2