Nginx基础详解2(首页解析过程、进程模型、处理Web请求机制、nginx.conf语法结构)

害羞的白菜 2024-10-08 12:33:02 阅读 70

续:Nginx基础详解1(单体部署与集群部署、负载均衡、正反代理、nginx安装)-CSDN博客

目录

4.Nginx默认首页的过程解析

5.Nginx进程模型的详解

5.1启动nginx后的关于nginx的进程查看

5.2master进程与process进程

5.3Nginx进程图解

5.4worker进程的数量控制

5.5nginx分成master进程和worker进程的好处

6.Nginx处理Web请求机制的详解

6.1worker的抢占模式

6.2图解Work的抢占模式

6.3传统服务器抢占模式

6.4Nginx对于传统抢占模式的优化

6.4.1epoll

6.4.1.1epoll概念

6.4.1.2epoll的特点

6.4.1.3epoll的工作流程:

6.5设定最大的连接数

7.ngin.confx配置的结构与语法结构

7.1全局配置main模块

7.2配置工作模式和连接数event模块

7.3http模块

7.4server模块

7.5location模块

7.6upstream服务器集群模块


        我们从上一次验证完的nginx网页之后开始学习!

4.Nginx默认首页的过程解析

        整个流程都是在HTTP协议的支持下进行的,所以客户机浏览器输入的http://可以省略,直接输入IP地址也是可以的。

        客户端浏览器输入服务器的域名或IP地址,交付给Nginx反向代理服务器进行处理,Nginx默认监听80端口,这也是http协议的默认端口。而服务器大概率并不是一台构成而是以集群为单位进行客户机请求报文的接收工作,根据算法找到一台最优的服务器处理客户机的一部分请求(注意不不是客户机全部的请求),找到相对应的server服务器之后将服务器上的页面**.html反馈给Nginx反向代理服务器,Nginx接收到该界面进行接收和转发相应给客户机浏览器,这就完成的用户点击界面到界面给你完整的反馈的整个过程。

        需要注意的是:Nginx根据配置的负载均衡算法将请求分配给集群中的一台服务器。这个过程是自动的,用户不需要了解背后的复杂逻辑。

5.Nginx进程模型的详解

5.1启动nginx后的关于nginx的进程查看

        我们在/usr/local/nginx/sbin目录下直接输入./nginx或nginx启动nginx这个软件之后,查看关于nginx的进程(如下图)

ps aux |grep nginx

        我们发现关于nginx进程共有两个,一个是master process进程,另一个则是worker process进程,而master进程的所有者为root、worker进程的所有者为nobody。

5.2master进程与process进程

        master进程:是nginx的主进程,仅能存在一个。也是 Nginx 架构中的管理者,它负责启动整个 Nginx 服务,加载配置文件,并创建 worker 进程。Master 进程不直接处理客户端请求,而是作为守护进程运行在后台负责监控和管理工作进程。当接收到外部信号,如重启或关闭服务的命令时,Master 进程会相应地管理 worker 进程,确保服务的平滑过渡。此外,Master 进程还负责记录关键的日志信息,以便监控服务的运行状态。

常见的nginx的信号有一下几种:

        ./nginx -s stop

        ./nginx -s reload

        ./nginx -s quit

        ./nginx -t

        worker进程:是nginx的工作进程,可以手动进行设置,可以有多个,它们是处理客户端请求的实体。Worker 进程的数量通常设置为与服务器的 CPU 核心数相同,以充分利用多核优势。这些进程之间会共享相同的内存空间,但各自独立运行,从而实现高效的请求处理。当有新的请求到达时,Nginx 的事件模型会自动将请求分配给其中一个 worker 进程进行处理,确保了服务的高并发和高性能。

        需要注意的是nginx的工作进程worker需要结合实际的硬件条件设置数量,如果硬件条件不是很好的前提下还是不建议设置多个worker工作进程的。如果需要考虑在云服务器上配置nginx的worker的数量,而且云服务器还开启了Redies、zookeeper等相关的占用cpu性能的服务,那么worker的数量我建议为:

cpu的核数-1

5.3Nginx进程图解

           如果上述的master进程和worker进程大家还是不理解,我从网上找了一张图片,下面我给大家用比喻的维度去理解。

       

        想象一下,Nginx就像一个大型的快递分拣中心。在这个中心,有一个总指挥(master进程),他的工作是确保整个分拣流程的顺利进行。他负责监督整个中心的运作,包括招聘和培训分拣员(worker进程),以及处理突发事件。

        分拣员(worker进程)是实际处理快递包裹的人。他们每个人都可以同时处理多个包裹(客户端连接),将它们分拣到正确的运输车辆上。当一个新的包裹(客户端请求)到达时,总指挥会将这个任务分配给一个空闲的分拣员(master将信号分给闲置的worker)。

        快递分拣中心的目的是尽可能高效地处理大量的包裹,这就需要分拣员之间进行平衡的工作分配,以确保没有人过于忙碌或过于清闲。这就是负载均衡的概念。

        如果一个分拣员突然生病了(一个worker进程崩溃),总指挥会立即安排一个新的分拣员来接替他的工作,以确保分拣流程不会中断。

        有时候,分拣中心需要更新分拣规则(更新配置),总指挥可以在不影响整个分拣流程的情况下,指导分拣员逐步适应新的规则。

        通过这个比喻,我们可以理解Nginx的进程模型是如何工作的:总指挥(master进程)负责整个中心的管理和调度,分拣员(worker进程)负责实际的处理工作,而快递包裹(客户端连接)则是需要被处理的对象。

5.4worker进程的数量控制

        通过5.2我们了解了master进程和worker进程的概念,我们知道了worker进程可以存在多个,那么在Nginx的配置界面如何更改worker的数量呢?

        答案就藏在nginx.conf这个默认配置文件中!我之前也说过我们后续的大部分学习都是围绕着nginx.conf这个默认的配置文件展开。

打开nginx.conf

vim /usr/local/nginx/conf/nginx.conf

找到下方代码:

#user nobody:定义worker进程的属主,默认也是nobody,如果想要更改进程的属主需要

        第一步:去掉‘#’号

        第二步:更改nobody的值,可以改成超管root或者其他的普通账户的用户名

worker_process 1:决定了nginx会生成多少个worker进程数量,默认为1

我们做出如下更改并进行验证:

验证方法:

ps -ef |grep nginx

我们发现worker进程的属主没有变成root,数量并没有变成3个,这是为什么呢?

注意:

        只要更改了nginx.conf的配置,都需要重新加载nginx程序!只要更改了nginx.conf的配置,都需要重新加载nginx程序!只要更改了nginx.conf的配置,都需要重新加载nginx程序!重要的话说三遍!!!!!

        原因就是我们没有重新加载nginx的配置,所以导致的nginx还是原来的配置,新的配置没有记录到nginx中!

        解决方法:

第一步:回到nginx的可执行目录 sbin下

cd /usr/local/nginx/sbin

第二步:简称配置文件是否出错

./nginx -t

        只有出现nginx.conf test is successful才表示成功

第三步:重新加载nginx的配置文件

./nginx -s reload

        配置完成这些我们再来看nginx进程文件的worker的属主和数量(属主成功变成了root,数量成功变成了3个!试验成功)

5.5nginx分成master进程和worker进程的好处

        Nginx的master-worker模型在多个方面提供了显著的优势,包括稳定性、资源隔离、易于管理、负载均衡、多核CPU利用、灵活性、资源限制、简化调试、平滑重启、减少内存占用、提高响应速度、容错性、隔离性、快速恢复、限制攻击影响、资源限制、安全策略和日志记录。以下是这些优势的整合概述:

稳定性与容错性

Master进程负责管理worker进程,确保服务的持续可用性。如果一个worker进程崩溃,master进程可以迅速重启新的worker进程,最小化服务中断时间,提高整个系统的容错性。

资源隔离与限制

Master进程和worker进程之间的隔离有助于保护Nginx的核心功能,即使在worker进程崩溃的情况下,Nginx也能继续运行。通过限制worker进程的资源使用量,可以防止单个worker进程占用过多资源,从而影响其他进程。

易于管理

Master进程可以轻松地管理多个worker进程,包括平滑重启和升级,而不需要停止整个服务。这使得Nginx可以在不中断服务的情况下进行维护。

负载均衡与利用多核CPU

多个worker进程可以并行处理请求,Nginx通过内部机制将请求分配给不同的worker进程,从而实现负载均衡。同时,Nginx可以配置多个worker进程来充分利用多核CPU的计算能力,提高处理请求的效率。

灵活性

Master进程可以动态地调整worker进程的数量,以适应不同的负载需求。

简化调试

在开发和测试阶段,可以设置单个worker进程来简化调试过程。

平滑重启

Master进程可以控制worker进程的启动和关闭,实现平滑重启,这意味着在更新配置或代码时,不需要停止服务。

减少内存占用

由于worker进程是轻量级的,它们可以快速启动和关闭,这有助于减少内存占用。

提高响应速度

多个worker进程可以同时处理多个请求,这样可以提高响应速度和吞吐量。

隔离性

每个worker进程是相互隔离的,这意味着如果一个worker进程被黑客攻陷,其他worker进程和master进程不受影响,可以继续正常工作。

限制攻击影响

由于worker进程通常拥有较低的权限,即使被攻陷,攻击者也很难通过一个worker进程获取到服务器的控制权或敏感信息。

安全策略

Nginx可以配置各种安全策略,如限制请求频率、过滤恶意请求等,这些措施可以在worker层面上提供额外的安全防护。

日志记录

所有worker进程的访问和错误日志都会记录在文件中,master进程可以监控这些日志,及时发现异常行为。

6.Nginx处理Web请求机制的详解

6.1worker的抢占模式

        在Nginx中因为master进程可以fork多个Worker进程(fork:nginx的一种原语进程之间是如何进行fork的“第五篇:Linux进程的相关知识总结(1)-CSDN博客”这篇文章我已经讲解过了),这些Worker进程之间是并行执行的,简单来说默认的并行Worker对于新来的client请求是需要去“抢”的,更具体地来讲,每一个客户端都对应了一个accept_mutex互斥锁(防止出现多个Worker进程同时处理一个请求的情况),生成的全部的Worker进程都是去抢锁从而就相当于抢到了客户端的请求。

6.2图解Work的抢占模式

        和上面讲的一样,我们假设有三个Worker进程,但是仅传来一个client的请求,且请求上附着着accrpt_mutex互斥锁,假设worker1抢到了这把互斥锁,那么worker1就和client建立了连接(worker2和3暂时闲置等到再来client继续执行上述的抢占行为),连接建立完成之后由worker1断开连接,而不是客户端来断开这个连接。

6.3传统服务器抢占模式

       传统的服务器仅存在一个worker进程和一个master进程,就和我们未配置worker进程时的nginx一样,这时传来一个client请求worker就直接处理了,但是如果该请求比较复杂,worker进程处理的事件较长,等到后面client2、client3……都来了之后client的请求还没处理完,这样就造成了阻塞,master继续使用fork命令新建一个worker进程来处理client2、client3……这样一个worker进程仅处理一个client。

        上述看似一对一的处理,实际上加重了处理器的负担(因为现实情况时服务器每秒会有成千上万的客户机发出请求,而一个客户机又不一定发出一个请求,所以请求的数量是成倍数上涨的),这也是早期服务器经常会遇到的瓶颈问题,也是nginx为什么逐渐称为最受欢迎的反向代理服务器的原因,Nginx生成的多个worker进行抢占避免了这种情况的发生。

6.4Nginx对于传统抢占模式的优化

        我们一开始还是默认的一个master进程和一个worker进程,如果多个客户机问询一个worker进程,发生了阻塞之后(不一定仅阻塞一个client,可能会有连续的多个client发生了阻塞),Nginx会使用默认的事件处理机制epoll(语法为use epull;)跳过阻塞的client客户端请求,一直继续向下找未阻塞的client请求,直到找到一个未阻塞的client请求即可截至并建立连接。这样一个worker进程使用该种处理机制可以处理6-8万的client请求,大大提高了工作效率。

6.4.1epoll

6.4.1.1epoll概念

        epoll 是 Linux 操作系统下的一种 I/O 事件通知机制,它是 selectpoll 的高效替代方案。epoll 在处理大量并发 socket 连接时表现出色,因为它在内核和用户空间之间提供了更高效的通信方式。

6.4.1.2epoll的特点

轻量级

epoll 使用更少的资源,因为它不需要像 select 和 poll 那样在每次调用时都传递和复制整个文件描述符集合。

无限制

epoll 没有 select 所具有的文件描述符数量限制(通常是 1024),它仅受限于操作系统的内存和进程的地址空间。

水平触发与边缘触发

epoll 支持水平触发(Level Triggered, LT)和边缘触发(Edge Triggered, ET)两种模式。

水平触发:只要文件描述符仍然有事件待处理,就会一直通知。边缘触发:仅在状态发生变化时通知一次。

高效的事件通知

epoll 通过维护一个事件列表来减少不必要的唤醒和处理,从而提高效率。

内核态与用户态共享数据

epoll 通过内核与用户空间共享数据结构,减少了数据复制的开销。

6.4.1.3epoll的工作流程:

创建 epoll 实例

使用 epoll_create() 系统调用创建一个 epoll 实例。

添加文件描述符

使用 epoll_ctl() 将需要监听的文件描述符注册到 epoll 实例。

等待事件

使用 epoll_wait() 等待事件发生,该调用会阻塞直到至少有一个监控的文件描述符上有事件发生。

处理事件

当 epoll_wait() 返回时,应用程序可以处理这些事件。

关闭 epoll 实例

使用 close() 系统调用关闭 epoll 实例。

Linux:推荐使用 epollWindows:推荐使用 IOCP。macOS:推荐使用 kqueue

6.4.1.4配置epoll的方法

第一步:进入nginx的配置界面

vim /usr/local/nginx/conf/nginx.conf

第二步:找到event模块,输入如图配置,并ESC->:wq报错后退出

第三步:回到nginx的sbin目录下检查nginx的配置文件是否出错

./nginx -t

第四步:重新加载nginx的配置文件

./nginx -s reload

        上面的epoll讲解的还是太过“官方”了,如果实在感觉晦涩难懂的话大家就记住上面那张图片吧~

6.5设定最大的连接数

        我们6.4学过了Linux的处理机制,如果发现未阻塞的client就建立连接,那么如何定义最大的连接呢(注意:该连接为最大的同时连接数)?

        还是在nginx.conf这个文件中!我们基础操作离不开nginx的默认配置文件(在event块下的work_connections决定了每个worker进程的最大连接数!

vim /usr/local/nginx/conf/nginx.conf

7.ngin.confx配置的结构与语法结构

上一篇我们配置了nginx的目录(配置在了/usr/local/nginx目录下)

        我们进入内部的配置文件进行查看默认的配置

cat /usr/local/nginx/conf/nginx.conf

 

#user  nobody;

worker_processes  1;

 

#error_log  logs/error.log;

#error_log  logs/error.log  notice;

#error_log  logs/error.log  info;

 

#pid        logs/nginx.pid;

 

 

events {

    worker_connections  1024;

}

 

 

http {

    include       mime.types;

    default_type  application/octet-stream;

 

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '

    #                  '$status $body_bytes_sent "$http_referer" '

    #                  '"$http_user_agent" "$http_x_forwarded_for"';

 

    #access_log  logs/access.log  main;

 

    sendfile        on;

    #tcp_nopush     on;

 

    #keepalive_timeout  0;

    keepalive_timeout  65;

 

    #gzip  on;

 

    server {

        listen       80;

        server_name  localhost;

 

        #charset koi8-r;

 

        #access_log  logs/host.access.log  main;

 

        location / {

            root   html;

            index  index.html index.htm;

        }

 

        #error_page  404              /404.html;

 

        # redirect server error pages to the static page /50x.html

        #

        error_page   500 502 503 504  /50x.html;

        location = /50x.html {

            root   html;

        }

 

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80

        #

        #location ~ \.php$ {

        #    proxy_pass   http://127.0.0.1;

        #}

 

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000

        #

        #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;

        #}

 

        # deny access to .htaccess files, if Apache's document root

        # concurs with nginx's one

        #

        #location ~ /\.ht {

        #    deny  all;

        #}

    }

 

 

    # another virtual host using mix of IP-, name-, and port-based configuration

    #

    #server {

    #    listen       8000;

    #    listen       somename:8080;

    #    server_name  somename  alias  another.alias;

 

    #    location / {

    #        root   html;

    #        index  index.html index.htm;

    #    }

    #}

 

 

    # HTTPS server

    #

    #server {

    #    listen       443 ssl;

    #    server_name  localhost;

 

    #    ssl_certificate      cert.pem;

    #    ssl_certificate_key  cert.key;

 

    #    ssl_session_cache    shared:SSL:1m;

    #    ssl_session_timeout  5m;

 

    #    ssl_ciphers  HIGH:!aNULL:!MD5;

    #    ssl_prefer_server_ciphers  on;

 

    #    location / {

    #        root   html;

    #        index  index.html index.htm;

    #    }

    #}

 

}

        默认的nginx.conf应该如上代码所示,而nginx.conf的配置界面也是存在语法结构的,我们后期也是会详细地解释每一个结构(如下图)

7.1全局配置main模块

这是Nginx配置文件中最顶层的配置部分,它影响整个Nginx服务器的全局行为。在这里可以设置用户、用户组、工作目录、PID文件路径等。你可以这样理解为:只要打开了nginx.conf的配置文件,就是进入了main的全局配置模块,因为nginx是俄罗斯的公司设计的,底层的语言仍然使用的是C语言,这就相当与C语言的主函数main,而C语言的主函数的作用是作为程序的入口来使用。即:你进入了nginx.conf这个文件,就是进入了nginx默认配置的入口。main 模块是 Nginx 配置的根基,它为整个服务器的运行提供了基础环境和全局参数。

7.2配置工作模式和连接数event模块

event模块定义了Nginx如何处理连接的接收和关闭。这里可以设置工作模式(如单线程或多线程)、连接数上限等

7.3http模块

HTTP模块用于配置与HTTP协议相关的参数,如保持连接的超时时间、日志文件的位置、HTTP头部的设置等。HTTP模块可以嵌套server块。http模块也是我认为Nginx的精髓所在,是Nginx配置的核心部分!

7.4server模块

server块定义了虚拟主机的配置。每个server块可以有自己的监听端口、日志文件、location块等。server块是HTTP模块的子模块。

7.5location模块

location块定义了请求的路由规则,可以根据请求的URI来匹配特定的location块。在这里可以设置代理、重定向、静态文件服务等。

7.6upstream服务器集群模块

upstream块定义了一个服务器组,通常用于负载均衡。在这里可以配置一组后端服务器,Nginx会根据定义的策略将请求分发到这些服务器。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。