nginx 全相联结构的引申

news2024/11/22 19:00:51

修改 nginx 纯属巧合,任务是将 reuseport 的支持换一种方式。目前 nginx 的方式是 master 创建 worker 数量个 reuseport listening socket,由 worker 继承。在这种实现方式下,效果是 “所有 worker 可以处理所有 listening socket”
这不就是典型的全相联结构吗?挺好,但因不符合我们的依赖模型,不得不将 socket 的创建移到每一个 worker 中,因此,每一个 worker 只能看到自己创建的 socket,这是一一映射结构,在服务器/消费者模型中显然没有全相联结构更 “好”(好字要额外解释)。

再次牵涉到多队列还是单队列(超市收银台倾向右边,银行大厅倾向左边,为什么?):
在这里插入图片描述
至于组相联,介于二者间,在组内全相联,组间一一映射。

这些惯常知识很重要但不是本文的重点,本文先讲个历史,再说个理念。

我将 nginx 从全相联改成一一映射属实开历史倒车,因为最开始 nginx 引入对 reuseport 的支持时就采用了一一映射的方式,最初的 patch:Initial SO_REUSEPORT support

但最终采用了全相联结构:
Socket Sharding in NGINX Release 1.9.1
RE: [Patch] SO_REUSEPORT support from master process

nginx reuseport 经历了从一一映射到全相联的过程,我给改回去了。但在最初的 patch 中还有个细节,作者没谈但应该已意识到。

该 patch 为每一个 worker 创建了 worker 个 listening socket,但没有必要,且平添 socket 结构的维护开销:
在这里插入图片描述

于是我又改了一下,在 ngx_open_listening_sockets 里的 for 循环遍历 listening socket 的开头加入下语句:

if (ls[i].sockaddr->sa_family == AF_INET && 
    ls[i].type == SOCK_STREAM && 
    worker != -1 && ls[i].worker != (ngx_uint_t)worker) {
                continue;
}

ngx_configure_listening_sockets 同理,保持每一个 worker 仅持有一个 listening socket。

但这里是不是一个引入组相联的好契机呢?如:
在这里插入图片描述

我想是的,我要是编程编得好,应该能就这个点做一个类似 apache mem 的框架,把所有相联结构都引入,nginx 就成了 apache-like,并且,显然 nginx 牛叉的地方是异步 epoll(关于 epoll 机制,我曾写过一篇文章还不错:再谈Linux epoll惊群) 而不是 master/worker 模型,加入 mpm 岂不如虎添翼。

这引出一个理念。要分清什么才是资源。可落实到实际处理逻辑的硬件才是资源,软件只是为了易于管理资源,不是资源。这是一个反云原生的说辞,但正因为这样才有必要单独拿出来说,因为云原生的理念在抽象的道路上越走越远,我这里倒过来说。

容器不是资源,进程不是资源,线程不是资源,协程不是资源,socket 不是资源,它们只是 “虚拟层”,只有 CPU 核才是资源。是 CPU 在处理连接报文,而不是进程或线程在处理 socket。

将所有连接在所有 CPU 上调度,自然而然就是一个全相联结构。至于进程,线程,协程,socket 这些抽象层,其威力在工程,生产力和生态,而非性能,当你觉得事情错综复杂时,“加一个层解决”,但加一个层势必影响性能。

去年那篇 It’s Time to Replace TCP in the Datacenter 中,作者提到 TCP 不宜多核心发挥优势,TCP 明确串行处理,无法发挥并行优势。按上述理念理解,根因在于 TCP 也是一个抽象层。故,抽象不是解决问题的手段,而是问题产生的原因。

关于 TCP 的问题,回到本文第一幅图,看右边,TCP 是个一一映射结构的抽象。

要么把逻辑装进 task(各种 x 程),托管给系统调度,要么自己调度,总之都是调度,不同的是,托管费省不了,task 内存开销,task 切换的 CPU 开销,无论创建多少 task,可同时运行的也不超过 CPU 核数(再次强调,task 不是资源,CPU,内存才是),挂起的 task 就是纯消耗资源,比如 TCP 连接的 CPU 开销,不活跃长连接的内存开销。有人想直触 CPU,有人想自研传输协议,都一回事,绕开抽象层。

一路向下越过所有抽象层,一直触碰到实际硬件资源,就在那个层面上调度。反之,将会产生过度设计,用尽各种 “x 程”,将系统人为喂胖,典型的为了一碟醋包了一顿饺子。

回到 nginx。

即使 nginx worker 和 连接报文全相联,还是有 gap,因为 worker 是一个进程抽象而不是 CPU 本身。进程的粒度是一条一直执行到睡眠等待的指令流,而 CPU 的粒度是指令,这是一个和 TCP 一样的问题。如果所有 worker 都睡眠在文件 IO 上,所有 CPU 都会 idle,即使这样这些 CPU 也无法处理到达 socket 的数据,因为没有任何进程在 socket 上等待。

解决方案似乎回到了传统 mpm,多创建几个进程,在其它进程等待其它事件时,总有一些进程等待 socket,但这无非是在利用统计学,代价也大:
在这里插入图片描述

CPU 的粒度为指令,理论上一个 worker 的粒度无限接近指令粒度就 OK,因此要为 worker 选择一个足够小的粒度,那就以 worker 的睡眠等待作为分割边界咯。以下是一个例子。

以 CPU 数量为依据创建数量固定的 worker,将 worker 分类,每类若干实例,保证每类 worker 只在一个点等待,比如第一类 worker 只等待文件 IO,第二类 worker 只等待 socket,第三类 worker 只处理数据等等,总之执行程足够短,足够小,就能最大化效能:
在这里插入图片描述

剩下的交给统计学,不要绑核。大概协程就有点这个意思,看似回到了 mpm 的设计原点,但这回抓住了本质。

full-mesh 结构是好的,被认为硬件成本过高而取而代之以各种折中方案,对于软件虚拟结构,full-mesh 的成本可低到被忽略,它和全相联是一回事。

当然,上图这么复杂的结构显然涉及很多锁,远不如 nginx worker 简洁高效,但这显然是实现问题而非架构问题了,显然上图的全相联(full-mesh)结构的可扩展性更强。

理解了资源的本质,再辅以抽象思想,就彻底解决了 “三高” (高并发,高性能,高可用)问题。画完最后一幅图后,想起了 wireguard-go,于是我删掉了协程绑定 channel 的代码,统计学比我更了解系统。

皮鞋没有蹬上,露着白袜子。

浙江温州皮鞋湿,下雨进水不会胖。

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

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

相关文章

安卓内部存储不需要申请权限,外部文件需要申请权限

内部存储和外部存储的访问权限区别&#xff1a; 内部路径&#xff1a;/data/user/0/com.xxx.xxx/ getExternalFilesDir可以获取到属于 App 自身的文件路径&#xff0c;通常是~/Android/data/<package-name>/**/。在该目录中读写文件均不需要申请权限,随着APP卸载就会删…

华为云云耀云服务器L实例评测|Git 私服搭建指南

前言 本文为华为云云耀云服务器L实例测评文章&#xff0c;测评内容是 云耀云服务器L实例 Git 私有服务器搭建指南 系统配置&#xff1a;2核2G 3M Ubuntu 20.04 我们平时在使用代码托管服务的时候&#xff0c;可能某些代码托管平台对成员有限制&#xff0c;或是由于内容原因会对…

自动编码器

Autoencoder is designed in a way to perform task of data encoding plus data decoding to reconstruct input. -- Anushka Jain 前言 两兄弟 N.Coder 和 D.Coder 经营着一家艺术画廊。一周末&#xff0c;他们举办了一场特别奇怪的展览&#xff0c;因为它只有一面墙&#x…

nginx中sent_timeout属性使用注意事项

send_timeout使用注意事项 send_timeout:指客户端向服务器发送请求并且等待服务器返回数据的时间&#xff0c;超过这个时间链接就断开。如果咱们返回的数据复杂&#xff0c;很耗时&#xff0c;就将该值设置大些。注意该时间指准备过程&#xff0c;不是传输过程&#xff08;下载…

在线海报图片设计器、图片编辑器源码/仿照稿定设计源码

在线海报设计系统素材设计源码是一个漂亮且功能强大的在线海报图片设计器&#xff0c;仿照稿定设计而成。该系统适用于多种场景&#xff0c;包括海报图片生成、电商分享图、文章长图、视频/公众号封面等。用户无需下载软件&#xff0c;即可轻松实现创意&#xff0c;迅速完成排版…

7-38 掉入陷阱的数字

输入样例: 5 输出样例: 1:16 2:22 3:13 4:13 ACcode: #include <bits/stdc.h>using namespace std;int main(){int n;cin >> n;vector<int> ans;int limit 1;ans.push_back(n);for(int i0; i<limit; i){//各位数字的和int sum 0;int num ans[i];w…

独立开发了一款Material3风格的RSS阅读器 - Agr Reader

截图 背景&#x1f4d6; 在之前接触到RSS后&#xff0c;发现RSS真是一个十分不错的信息聚合的方式&#xff0c;虽然现在看来RSS的时代已经开始落幕&#xff0c;但是至少目前还是处于能用的阶段。 在我用了Android上好几个RSS阅读App后&#xff0c;发现很多在全文解析方面不是…

栈与队列经典题目——用栈实现队列

上篇文章对栈和队列的一个经典题目——Leetcode.225-用队列实现栈进行讲解。本篇文章将对另一个题目Leetcode.232-用栈实现队列进行讲解 1. Leetcode.232——用栈实现队列&#xff1a; 题目如下&#xff1a; 1.1 大体思路分析&#xff1a; 题目要求需要实现下列函数所表示的…

JAVA注解总结

总结一下java注解。 元注解 元注解也是一种注解。元注解的作用就是来限制和定义一个普通的注解。 注解的语法 public(可选) interface 注解名称{ 具体的参数 } 注解里面的参数 第一个表示参数的类型是什么&#xff0c;类型后面可以跟[],表示数组&#xff0c;在后面就是参数…

详解机器视觉性能指标相关概念——混淆矩阵、IoU、ROC曲线、mAP等

目录 0. 前言 1. 图像分类性能指标 1.1 混淆矩阵(Confusion Matrix) 1.2 准确率(Precision) 1.3 召回率(Recall) 1.4 F1值(F1 score) 1.5 ROC曲线(接收者工作特征曲线&#xff0c;Receiver Operating Characteristic curve) 1.6 mAP(mean Average Precision) 2. 图像分…

Apereo CAS反序列化漏洞中数据加解密研究

Apereo CAS反序列化漏洞中数据加解密研究 0x01、简介0x02、网上获取资料0x03、初步运行失败1、分析&#xff1a;2、Tips&#xff1a; 0x04、分析原因1、自己写解密算法 / 直接使用cas工程的相关jar包、java文件&#xff0c;调用解密函数2、为什么会解密失败&#xff1f; 0x05、…

企业级数据仓库-数仓实战

数仓实战 安装包大小 安装清单 环境搭建 一、环境搭建01&#xff08;机器准备&#xff09; 准备好三台虚拟机&#xff0c;并进行修改hostname、在hosts文件增加ip地址和主机名映射 。 1、设置每个虚拟机的hostname vi /etc/sysconfig/network 修改HOSTNAMEnode02修改hostna…

PY32F003F18之输入捕获

输入捕获是定时器的功能之一&#xff0c;配合外部引脚&#xff0c;捕获脉宽时间或采集周期。 CPU中的定时器最基本的功能就是计数功能&#xff0c;其次是输入捕获(IC)&#xff0c;再次就是比较输出(OC)&#xff0c;还有就是使用引脚对外部时钟进行计数&#xff0c;触发信号捕捉…

6- 华为云查看容器日志

1 查看位置 二 进入容器查看 ls cat main.py # 退出命令是 exit() 或者 quit() cat main.py 在docker使用该命令进入文件后的退出命令

Mapbox gl HTML经纬度点渲染,动态轨迹播放,自定义图形以及轨迹上显示箭头方向

Mapbox gl HTML经纬度点渲染&#xff0c;动态轨迹播放&#xff0c;自定义图形以及轨迹上显示箭头方向 1. 效果图2. 源码2.1 line.html2.2line_arrow.html 参考 今天要排查个问题&#xff0c;需要显示多个经纬度点连接成线段的方向&#xff0c;于是尝试下展示。 1. mapbox渲染经…

element plus封装el-select添加后缀图标并添加远程搜索和对话框功能

当提交的表单Form需要填某个实体的外键ID时&#xff0c;当然不可能使用el-input组件&#xff0c;这个适合提交字符串&#xff0c;然后用户又不可能记住某个引用的外键ID&#xff0c;这时候使用el-select还是必要的。 el-select组件一般都作为下拉选择框使用&#xff0c;但仅在…

Java实现通过文字生成图片

一、前言 在实际应用中&#xff0c;我们可能需要将用户姓名作为头像显示&#xff0c;那么我们可以通过Java来实现。 二、如何实现 1.定义一个工具类&#xff0c;代码如下&#xff1a; import org.slf4j.Logger; import org.slf4j.LoggerFactory;import javax.imageio.ImageIO…

三分钟使用ngrok实现内网穿透

1.官网注册 官网地址&#xff1a;https://ngrok.com/ tips:若使用邮箱注册自行认证 2.下载对应部署电脑 压缩包&#xff08;此处笔者使用自己电脑因此以Windows11作为案例&#xff09; 解压下载的ngrok压缩包&#xff0c;在对应目录进入命令提示符装口&#xff08;也可直接…

竞赛 基于机器视觉的银行卡识别系统 - opencv python

1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的银行卡识别算法设计 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng…

基于 I2C 协议的 AD实验(附代码)

目录 1. 理论学习 1.1 AD介绍 1.2 I2C 简介 1.2.1 I2C物理层 1.2.2 I2C协议层 1.3 PCF8591芯片简介 1.3.1 引脚信息 1.3.2 功能描述 2. 实验 2.1 硬件资源 2.2 模块框图 2.3 程序设计 2.3.1 工程整体框图 2.3.2 I2C驱动模块 1. 模块框图 2. 波形图分析&#xf…