Nginx — Nginx处理Web请求机制解析

news2025/7/16 21:54:52

一、Nginx请求默认页面资源

1、配置文件详解

 

 修改端口号为8080并重启服务:

二、Nginx进程模型

1、nginx常用命令解析

master进程:主进程(只有一个)

worker进程:工作进程(可以有多个,默认只有一个进程)

生命周期的原理:

信号: (操作人在执行以下指令操作的时候,master会转递给worker相关的信息让worker去进行相关的操作)

./nginx                  #开启nginx服务。
./nginx -s stop          #暴力的关闭,如果后端有用户在连接如果用此命令会导致连接全部中断,如果发现有恶意攻击和黑客入侵的情况下可以用此命令。
./nginx -s stop          #重新加载配置文件信息。
./nginx -s quit          #优雅的关闭,如果后端有用户在连接会等待连接完成之后再去关闭,同时不会让新的请求访问进来(只针对http请求如果不是http请求时不行的)。
./nginx -t               #检测配置文件的语法是否正确。
./nginx -v               #查看当前的配置信息。
./nginx -V               #显示详细信息,包括了nginx的版本、gcc版本、configure编译路径等。
./nginx -c               #代表手动切换nginx的配置文件。
./nginx -h & ./nginx -h  #显示nginx的帮助命令。

 

 

每个worker之间相对独立,如果某个worker收到黑客的攻击,那么运维人员只需要关闭相关的worker进程,如果某个worker进程不存在只需要master重新fork以下即可。

 2、修改worker的进程数

 

三、Worker抢占机制

当client发起了请求之后client和worker之间会有一个护事锁(accept_mutex)服务端的众多worker会去抢这个锁,哪个worker抢到就由哪个worker来进行处理。

 

 

四、传统服务事件处理

假设一个client在进行请求的时候由worker1来进行处理,在处理的过程中用时比较长而且卡住了,客户端的请求就会被阻塞,假设在阻塞的过程中又有新的请求进来(假设client2、client3也同时连接到worker)要去处理。只有阻塞的请求处理完毕才回去处理client2、client3,所以master会去fork一个新worker进程。(在告并发情况下,这样的消耗会很大而且占用的资源会比较多)。

 

 

五、Nginx时间处理

假设一个client在进行请求的时候由worker1来进行处理,在处理的过程中用时比较长而且卡住了。对于Nginx而言是异步非阻塞的,如果发生阻塞同时又有新的请求进来那么worker会去处理下一个请求。用到的模型为epoll,(如果用到epoll那么一个worker进程可以处理6~8w的请求量,并且不会产生很多的开销),那么需要越高的并发量只需要增加服务器的配置就可以了(有钱解决)。

(一)Nginx的events模块支持的多种事件模型支持的模型

Nginx 的 events 模块主要用于配置 Nginx 如何处理连接,它提供了多种事件模型,以适应不同的操作系统和应用场景。下面为你详细介绍 Nginx 支持的主要事件模型:

1. select 模型

  • 原理select 是一种较为传统的事件驱动模型,它通过对文件描述符集合进行轮询,检查是否有文件描述符处于可读、可写或异常状态。当有事件发生时,select 函数会返回发生事件的文件描述符数量,然后程序需要遍历文件描述符集合来确定具体是哪些文件描述符发生了事件。
  • 适用场景:适用于连接数较少的场景,因为 select 模型在处理大量连接时,轮询操作会带来较高的 CPU 开销,性能会显著下降。同时,select 模型对文件描述符数量有限制,通常最大为 1024。
  • 配置示例
 

nginx

events {
    use select;
    worker_connections 1024;
}

2. poll 模型

  • 原理poll 是对 select 模型的改进,它同样采用轮询的方式检查文件描述符的状态,但 poll 没有文件描述符数量的限制。poll 使用一个结构体数组来存储文件描述符和对应的事件,避免了 select 对文件描述符数量的硬限制。
  • 适用场景:适用于连接数相对较多,但仍然不是非常大的场景。相比于 selectpoll 在处理大量连接时性能有所提升,但在处理超大量连接时,轮询操作仍然会带来较高的 CPU 开销。
  • 配置示例
 

nginx

events {
    use poll;
    worker_connections 2048;
}

3. epoll 模型

  • 原理epoll 是 Linux 内核为处理大批量文件描述符而作了改进的 poll,是 Linux 下多路复用 IO 接口 select/poll 的增强版本。它采用事件驱动的方式,只关注那些有事件发生的文件描述符,避免了对所有文件描述符的轮询,从而提高了效率。epoll 使用内核和用户空间共享内存的方式,减少了数据的拷贝次数。
  • 适用场景:适用于 Linux 系统下处理大量并发连接的场景,是 Nginx 在 Linux 系统上的首选事件模型。
  • 配置示例
 

nginx

events {
    use epoll;
    worker_connections 65535;
}

4. kqueue 模型

  • 原理kqueue 是 FreeBSD 系统上的一种高效事件通知机制,类似于 Linux 下的 epoll。它采用事件队列的方式,当有事件发生时,会将事件添加到队列中,程序可以从队列中获取发生事件的文件描述符。
  • 适用场景:适用于 FreeBSD 系统,在处理大量并发连接时性能较好。
  • 配置示例
 

nginx

events {
    use kqueue;
    worker_connections 65535;
}

5. rtsig 模型

  • 原理rtsig 是基于实时信号实现的事件模型,它通过发送实时信号来通知程序有事件发生。
  • 适用场景:该模型在实际应用中使用较少,因为实时信号的处理有一些限制,并且性能不如 epoll 和 kqueue 等模型。
  • 配置示例
 

nginx

events {
    use rtsig;
    worker_connections 1024;
}

6. /dev/poll 模型

  • 原理/dev/poll 是 Solaris 系统上的一种事件通知机制,它通过读取 /dev/poll 设备文件来获取事件信息。
  • 适用场景:适用于 Solaris 系统,在该系统上可以提供较好的性能。
  • 配置示例
 

nginx

events {
    use /dev/poll;
    worker_connections 65535;
}

自动选择模型

如果不指定 use 指令,Nginx 会根据操作系统自动选择最合适的事件模型。例如,在 Linux 系统上会优先选择 epoll 模型,在 FreeBSD 系统上会优先选择 kqueue 模型。示例如下:

 

nginx

events {
    worker_connections 65535;
}
 

在实际应用中,建议根据服务器的操作系统和具体的业务场景选择合适的事件模型,以提高 Nginx 的性能和稳定性。

(二)nginx默认的模型是epoll 

epoll 是 Linux 内核为处理大批量文件描述符而作了改进的 poll,是 Linux 下多路复用 IO 接口 select/poll 的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统 CPU 利用率。下面从几个方面详细介绍 epoll 模型:

基本概念

在网络编程中,服务器需要处理多个客户端的连接请求,传统的方法(如 select 和 poll)在处理大量连接时性能会下降。epoll 则通过事件驱动的方式,只关注那些有事件发生的文件描述符,避免了对所有文件描述符的轮询,从而提高了效率。

工作原理

epoll 的工作流程主要分为三个步骤:

 
  1. 创建 epoll 实例:使用 epoll_create 或 epoll_create1 函数创建一个 epoll 实例,它会返回一个文件描述符,后续的操作都基于这个描述符进行。
  2. 注册事件:使用 epoll_ctl 函数向 epoll 实例中添加、修改或删除需要监控的文件描述符以及对应的事件。例如,可以监控文件描述符的可读、可写等事件。
  3. 等待事件发生:使用 epoll_wait 函数等待事件的发生。当有事件发生时,该函数会返回有事件发生的文件描述符列表,程序可以对这些文件描述符进行相应的处理。

代码示例

以下是一个简单的使用 epoll 实现的 TCP 服务器示例代码:

 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <unistd.h>

#define MAX_EVENTS 10
#define BUF_SIZE 1024

int main() {
    int listen_fd, epoll_fd;
    struct sockaddr_in server_addr;
    struct epoll_event ev, events[MAX_EVENTS];

    // 创建监听套接字
    listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_fd == -1) {
        perror("socket");
        return 1;
    }

    // 初始化服务器地址
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(8080);

    // 绑定地址
    if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("bind");
        close(listen_fd);
        return 1;
    }

    // 监听连接
    if (listen(listen_fd, SOMAXCONN) == -1) {
        perror("listen");
        close(listen_fd);
        return 1;
    }

    // 创建 epoll 实例
    epoll_fd = epoll_create1(0);
    if (epoll_fd == -1) {
        perror("epoll_create1");
        close(listen_fd);
        return 1;
    }

    // 将监听套接字添加到 epoll 实例中
    ev.events = EPOLLIN;
    ev.data.fd = listen_fd;
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &ev) == -1) {
        perror("epoll_ctl: listen_fd");
        close(listen_fd);
        close(epoll_fd);
        return 1;
    }

    while (1) {
        int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
        if (nfds == -1) {
            perror("epoll_wait");
            continue;
        }

        for (int i = 0; i < nfds; i++) {
            if (events[i].data.fd == listen_fd) {
                // 处理新的连接
                struct sockaddr_in client_addr;
                socklen_t client_addr_len = sizeof(client_addr);
                int conn_fd = accept(listen_fd, (struct sockaddr *)&client_addr, &client_addr_len);
                if (conn_fd == -1) {
                    perror("accept");
                    continue;
                }

                // 将新的连接添加到 epoll 实例中
                ev.events = EPOLLIN;
                ev.data.fd = conn_fd;
                if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_fd, &ev) == -1) {
                    perror("epoll_ctl: conn_fd");
                    close(conn_fd);
                }
            } else {
                // 处理客户端数据
                char buf[BUF_SIZE];
                ssize_t n = read(events[i].data.fd, buf, BUF_SIZE);
                if (n <= 0) {
                    // 客户端关闭连接
                    close(events[i].data.fd);
                    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
                } else {
                    // 回显数据给客户端
                    write(events[i].data.fd, buf, n);
                }
            }
        }
    }

    // 关闭监听套接字和 epoll 实例
    close(listen_fd);
    close(epoll_fd);

    return 0;
}

优点

  • 高效处理大量连接epoll 使用事件驱动机制,只关注有事件发生的文件描述符,避免了 select 和 poll 对所有文件描述符的轮询,因此在处理大量并发连接时性能更优。
  • 内存拷贝优化epoll 使用内核和用户空间共享内存的方式,减少了数据的拷贝次数,提高了效率。
  • 水平触发和边缘触发模式epoll 支持水平触发(LT)和边缘触发(ET)两种模式,开发者可以根据具体需求选择合适的模式。

缺点

  • 平台依赖性epoll 是 Linux 特有的,在其他操作系统(如 Windows、macOS)上无法使用。
  • 实现复杂度较高:相比于 select 和 pollepoll 的使用和实现相对复杂,需要开发者对其原理有深入的理解。

 注:worker的进程要根据CPU实际情况来定不是越高越高,如果太高会造成请求访问卡顿。影响业务的正常运行。

epoll的配置

events {
    #默认使用epoll
    use epoll;
    #每个worker允许的客端最大连接数
    worker_connections  1024;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2325537.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5.0 WPF的基础介绍1-Grid,Stack,button

WPF: Window Presentation Foundation. WPF与WinForms的对比如下&#xff1a; 特性WinFormsWPF技术基础基于传统的GDI&#xff08;图形设备接口&#xff09;基于DirectX&#xff0c;支持硬件加速的矢量渲染UI设计方式拖拽控件事件驱动代码&#xff08;简单但局限&#xff09;…

Docker 端口映射原理

在 Docker 中&#xff0c;默认情况下容器无法直接与外部网络通信。 为了使外部网络能够访问容器内的服务&#xff0c;Docker 提供了端口映射功能&#xff0c;通过将宿主机的端口映射到容器内的端口&#xff0c;外部可以通过宿主机的IP和端口访问容器内的服务 以下通过动手演示…

SDL —— 将sdl渲染画面嵌入Qt窗口显示(附:源码)

🔔 SDL/SDL2 相关技术、疑难杂症文章合集(掌握后可自封大侠 ⓿_⓿)(记得收藏,持续更新中…) 效果 使用QWidget加载了SDL的窗口,渲染器使用硬件加速跑GPU的。支持Qt窗口缩放或显示隐藏均不影响SDL的图像刷新。   操作步骤 1、在创建C++空工程时加入SDL,引入头文件时需…

算法每日一练 (23)

&#x1f4a2;欢迎来到张翊尘的技术站 &#x1f4a5;技术如江河&#xff0c;汇聚众志成。代码似星辰&#xff0c;照亮行征程。开源精神长&#xff0c;传承永不忘。携手共前行&#xff0c;未来更辉煌&#x1f4a5; 文章目录 算法每日一练 (23)最大正方形题目描述解题思路解题代码…

UE5学习笔记 FPS游戏制作28 显式玩家子弹数

文章目录 添加变量修改ShootOnce方法&#xff0c;设计时减少子弹&#xff0c;没有子弹不能开枪在UI上显示 添加变量 在Gun类中添加BulletNum和ClipSize两个参数 BulletNum是当前还有多少子弹&#xff0c;ClipSize是一个弹匣多少子弹 Rifle的ClipSzie设置为30&#xff0c;Laun…

《构建有效的AI代理》学习笔记

原文链接:https://www.anthropic.com/engineering/building-effective-agents 《构建有效的AI代理》学习笔记 一、概述 核心结论 • 成功的AI代理系统往往基于简单、可组合的模式&#xff0c;而非复杂框架。 • 需在性能、成本与延迟之间权衡&#xff0c;仅在必要时增加复杂度…

数据处理专题(四)

目标 使用 Matplotlib 进行基本的数据可视化。‍ 学习内容 绘制折线图 绘制散点图 绘制柱状图‍ 代码示例 1. 导入必要的库 import matplotlib.pyplot as pltimport numpy as npimport pandas as pd 2. 创建示例数据集 # 创建示例数据集data { 月份: [1月, 2月, 3…

【目标检测】【深度学习】【Pytorch版本】YOLOV1模型算法详解

【目标检测】【深度学习】【Pytorch版本】YOLOV1模型算法详解 文章目录 【目标检测】【深度学习】【Pytorch版本】YOLOV1模型算法详解前言YOLOV1的模型结构YOLOV1模型的基本执行流程YOLOV1模型的网络参数YOLOV1模型的训练方式 YOLOV1的核心思想前向传播阶段网格单元(grid cell)…

云钥科技多通道工业相机解决方案设计

项目应用场景分析与需求挑战 1. 应用场景 ‌目标领域‌&#xff1a;工业自动化检测&#xff08;如精密零件尺寸测量、表面缺陷检测&#xff09;、3D立体视觉&#xff08;如物体建模、位姿识别&#xff09;、动态运动追踪&#xff08;如高速生产线监控&#xff09;等。 ‌核心…

从零到一:ESP32与豆包大模型的RTC连续对话实现指南

一、对话效果演示 ESP32与豆包大模型的RTC连续对话 二、ESP-ADF 介绍 乐鑫 ESP-ADF&#xff08;Espressif Audio Development Framework&#xff09;是乐鑫科技&#xff08;Espressif Systems&#xff09;专为 ESP32 系列芯片开发的一款音频开发框架。它旨在简化基于 ESP32 芯…

【深度学习与实战】2.3、线性回归模型与梯度下降法先导案例--最小二乘法(向量形式求解)

为了求解损失函数 对 的导数&#xff0c;并利用最小二乘法向量形式求解 的值‌ 这是‌线性回归‌的平方误差损失函数&#xff0c;目标是最小化预测值 与真实值 之间的差距。 ‌损失函数‌&#xff1a; 考虑多个样本的情况&#xff0c;损失函数为所有样本的平方误差之和&a…

【Django】教程-2-前端-目录结构介绍

【Django】教程-1-安装创建项目目录结构介绍 3. 前端文件配置 3.1 目录介绍 在app下创建static文件夹, 是根据setting中的配置来的 STATIC_URL ‘static/’ templates目录&#xff0c;编写HTML模板&#xff08;含有模板语法&#xff0c;继承&#xff0c;{% static ‘xx’ …

详解list容器

1.list的介绍 list的底层结构是双向带头循环链表&#xff0c;允许随机的插入和删除&#xff0c;但其内存空间不是连续的。随机访问空间能力差&#xff0c;需要从头到尾遍历节点&#xff0c;不像vector一样高效支持 2.list的使用 构造函数 1.默认构造函数&#xff1a;创建一个…

leetcode_977. 有序数组的平方_java

977. 有序数组的平方https://leetcode.cn/problems/squares-of-a-sorted-array/ 1.题目 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 示例 1&#xff1a; 输入&#xff1a;nums [-4,-1…

网络探索之旅:网络原理(第二弹)

上篇文章&#xff0c;小编分享了应用层和传输层深入的一点的知识&#xff0c;那么接下来&#xff0c;这篇文章&#xff0c;继续分享网络层和数据链路层。 网络层 了解这个网络层&#xff0c;那么其实就是重点来了解下IP这个协议 对于这个协议呢&#xff0c;其实也是和前面的…

深入剖析 JVM:从组成原理到调优实践

深入剖析 JVM&#xff1a;从组成原理到调优实践 深入剖析 JVM&#xff1a;从组成原理到调优实践一、JVM 组成架构&#xff1a;运行 Java 程序的 “幕后引擎”1.1 内存结构&#xff1a;数据存储的 “分区管理”1.2 执行引擎&#xff1a;字节码的 “翻译官”1.3 本地方法接口&…

阿里云下一代可观测时序引擎-MetricStore 2.0

作者&#xff1a;徐昊&#xff08;博澍&#xff09; 背景 作为可观测场景使用频度最高的数据类型&#xff0c;Metrics 时序数据在可观测领域一直占有着重要地位&#xff0c;无论是从全局视角来观测系统整体状态&#xff0c;还是从大范围数据中定位某一个异常的位置&#xff0…

从入门到精通【 MySQL】 数据库约束与设计

文章目录 &#x1f4d5;1. 数据库约束✏️1.1 NOT NULL 非空约束✏️1.2 DEFAULT 默认值约束✏️1.3 UNIQUE 唯一约束✏️1.4 PRIMARY KEY 主键约束✏️1.5 FOREIGN KEY 外键约束✏️1.6 CHECK 约束 &#x1f4d5;2. 数据库设计✏️2.1 第一范式✏️2.2 第二范式✏️2.3 第三范…

Dubbo 通信流程 - 服务的调用

Dubbo 客户端的使用 在 Dubbo 应用中&#xff0c;往类成员注解 DubboReference&#xff0c;服务启动后便可以调用到远端&#xff1a; Component public class InvokeDemoFacade {AutowiredDubboReferenceprivate DemoFacade demoFacade;public String hello(String name){// …

【数据结构】哈夫曼树

哈夫曼树 在学习哈夫曼树之前&#xff0c;先了解以下几个概念&#xff1a; 一&#xff1a;**路径长度&#xff1a;**在一棵树中&#xff0c;从一个节点到另一个节点所经过的“边”的数量&#xff0c;被我们称为两个节点之间的路径长度。 二&#xff1a;**树的路径长度&#xf…