• Nginx面试常问题&工作原理揭秘


    原文参考:

    blog.csdn.net/wuzhiwei549/article/details/1227589

    吐血给大家整理了一些面试官常问到的有关Nginx的问题

    Nginx面试常问题

    在这里插入图片描述

    什么是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才会回来继续处理请求

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

    正向代理&反向代理

    • 正向代理

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

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

    例子:VPN、运营商

    • 反向代理
      在这里插入图片描述

    位于客户端和后端服务器之间,多个客户端给服务器发送请求,反向代理服务器(例如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; 
    } 
    
    • 1
    • 2
    • 3
    • 4
    • weight(加权轮询)

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

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

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

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

    upstream backserver { 
     ip_hash; 
     server 192.168.0.1; 
     server 192.168.0.2; 
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • url_hash(url哈希)

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

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

    upstream backserver { 
     server squid1:3128; 
     server squid2:3128; 
     hash $request_uri; 
     hash_method crc32; 
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • fair(智能调度)

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

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

    能聊聊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里面剩余的内容是不会再次触发边缘通知的,就有可能导致读数据丢失
    
    • 1
    • 2
    • 3

    Nginx常见工作模型

    • 主进程 + 多个 worker 子进程

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

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

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

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

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

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

    由于内核确保了只有一个进程被唤醒,就不会出现惊群问题了
    在这里插入图片描述

  • 相关阅读:
    【同名cookie引发的血案】多个站点平台采用同名cookie引起用户信息被覆盖
    第2章 第一个Spring Boot项目
    Mocha + Chai 测试环境配置,支持 ES6 语法
    c语言结构体与共用体
    机器学习——过拟合
    服务注册发现_解读Eureka注册中心UI界面
    【Matlab】笔记:GeographicCellsReference 地理坐标知多少?矩阵、空间坐标、地理坐标之间转换等
    (原创)[C#] GDI+ 之鼠标交互:原理、示例、一步步深入、性能优化
    0基础2小时搭建自己的网站
    layui--记录
  • 原文地址:https://blog.csdn.net/s_alted/article/details/126896264