提升Node.js性能之SO_REUSEPORT的探讨

2024-03-27 21:08

本文主要是介绍提升Node.js性能之SO_REUSEPORT的探讨,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言:多个进程不能同时绑定同一个IP和端口,这是早期Linux内核的一个限制,这个限制给服务器带来了很多不便之处,因为服务器的架构通常不是单进程的,尤其在多核的时代,但是3.9的内核带来了新的特征SO_REUSEPORT。不仅使得服务器的代码逻辑变得简单,对服务器的性能也提升了不少。SO_REUSEPORT的意义是支持同用户下的多个进程同时监听一个IP和端口,本文介绍在Node.js中支持SO_REUSEPORT,以提升Node.js的性能。

目前,Node.js的TCP模块还没有支持SO_REUSEPORT。但是服务器通常是多进程架构的,不管是早期Apache的一个进程处理一个请求的模式,还是现代基于epoll+单线程+多核的模式(Nginx、Redis、Node.js),整体上都是多进程的架构,这就会涉及到一个问题,多个进程如何同时处理请求。传统的方法主要有以下几种(具体可以参考服务器处理连接的架构演变)。
1 主进程接收请求,分发给子进程处理,这种模式的好处是不需要处理多进程同时监听同一个IP端口的问题,因为只有主进程监听。

2 通过fork绕过内核的检查机制。我们看一下一个服务器启动的代码。

int socketfd = socket();
bind(socketfd);
listen(socketfd);

其中在bind这一步,内核会检测IP端口的合法性,如果这个IP和端口已经被监听,那么就会报错,所以如果多个进程同时bind同一个IP端口,那么第二个进程就会失败。但是有办法可以绕过这个限制,那就是不执行bind,我们看看具体怎么做。
2.1 主进程执行bind,这时候的底层架构如下。

2.2 主进程fork多个子进程,这时候的架构如下。

我们看到,fork之后的子进程继承了主进程中的文件描述符fd。这时候子进程不需要执行bind也绑定到了和主进程同样的IP和端口。
2.3 子进程执行listen修改socket状态为监听状态。
这时候就成功地完成了多个进程同时绑定一个IP和端口。

3 通过文件描述符传递的方式绕过内核的检查机制。具体做法如下。
3.1 主进程执行bind
3.2 主进程fork多个子进程,但是不继承主进程fd(fork的时候设置O_CLOEXEC)。
3.3 主进程通过文件描述符传递的方式把fd传给子进程,架构和2.2中的一样。
3.4 子进程执行listen。

Node.js中支持1和3这两种方式,具体在Cluster模块实现。但是上面的几种方式虽然解决了多个进程监听同一个IP端口的问题,但是性能上会存在一些问题。第一种模式存在的问题是,只有主进程可以接收请求,子进程被动接受主进程传过来的请求。那么主进程接收请求的能力会成为服务器的瓶颈。第二第三种模式存在的问题是,当连接到来时,多个进程会同时被唤醒,从而竞争去处理这个连接,连接最终被哪个进程处理,这取决于内核的进程调度,剩下的进程会被无效唤醒,这就是著名的惊群现象,解决惊群现象方式目前有两种,一种是在应用层解决,比如nginx会控制同时只有一个进程阻塞在socket上,保证连接到来时,只有一个进程被唤醒。另一种是在内核解决,新版的内核支持设置标记保证每次只有一个进程被唤醒,哪个进程被唤醒取决于内核实现。这往往会带来服务器代码的复杂处理和多个进程处理连接的负载不均衡。比如在Nginx和Node.js中都有相关的处理(参考Node.js的UV_HANDLE_TCP_SINGLE_ACCEPT标记)。

这时候,SO_REUSEPORT出现了,SO_REUSEPORT更彻底地支持多个进程同时绑定同一个IP端口,架构如下。

SO_REUSEPORT使得每个进程拥有独立的socket和连接队列,内核不仅允许多个进程绑定同一个IP端口,同时在分配连接到对应socket的连接队列时可以做到负载均衡,这使得应用层变得简单了很多。应用层不再需要解决负载均衡的问题,更加不用为了绕过内核对绑定地址的检测想尽办法。这意味着Node.js的Cluster模块很多代码可以不要了。他只需要管理进程,不再需要处理绑定IP端口的问题,同时net模块也变得简单。

支持SO_REUSEPORT不仅(理论上)可以提高Node.js作为服务器的性能,同时也简化了代码的逻辑。不过对Node.js来说,Cluster模块无法从SO_REUSEPORT特性获益,因为Cluster模块的share工作模式本质是通过传递文件描述符的方式让多个进程共享socket的。而不是一个进程一个socket。那么如何从SO_REUSEPORT特性获益呢?直接使用child_process模块,fork多个子进程,每个子进程调用listen函数就行(如果Node.js真的支持SO_REUSEPORT的话,后续Cluster只是作为降级/兼容方案,Node.js可以暴露接口判断是否支持SO_REUSEPORT,不过应用层可能又要封装兼容的代码。。。)。

1 具体pr可以参考https://github.com/libuv/libuv/pull/3198。
2 性能测试可以参考Nginx这个文章
3 SO_REUSEPORT的原理可以参考从内核看SO_REUSEPORT的实现(基于5.9.9)。

这篇关于提升Node.js性能之SO_REUSEPORT的探讨的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

JVisualVM之Java性能监控与调优利器详解

《JVisualVM之Java性能监控与调优利器详解》本文将详细介绍JVisualVM的使用方法,并结合实际案例展示如何利用它进行性能调优,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全... 目录1. JVisualVM简介2. JVisualVM的安装与启动2.1 启动JVisualVM2

Java使用MethodHandle来替代反射,提高性能问题

《Java使用MethodHandle来替代反射,提高性能问题》:本文主要介绍Java使用MethodHandle来替代反射,提高性能问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录一、认识MethodHandle1、简介2、使用方式3、与反射的区别二、示例1、基本使用2、(重要)

使用Python获取JS加载的数据的多种实现方法

《使用Python获取JS加载的数据的多种实现方法》在当今的互联网时代,网页数据的动态加载已经成为一种常见的技术手段,许多现代网站通过JavaScript(JS)动态加载内容,这使得传统的静态网页爬取... 目录引言一、动态 网页与js加载数据的原理二、python爬取JS加载数据的方法(一)分析网络请求1

Java内存区域与内存溢出异常的详细探讨

《Java内存区域与内存溢出异常的详细探讨》:本文主要介绍Java内存区域与内存溢出异常的相关资料,分析异常原因并提供解决策略,如参数调整、代码优化等,帮助开发者排查内存问题,需要的朋友可以参考下... 目录一、引言二、Java 运行时数据区域(一)程序计数器(二)Java 虚拟机栈(三)本地方法栈(四)J

PyTorch高级特性与性能优化方式

《PyTorch高级特性与性能优化方式》:本文主要介绍PyTorch高级特性与性能优化方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、自动化机制1.自动微分机制2.动态计算图二、性能优化1.内存管理2.GPU加速3.多GPU训练三、分布式训练1.分布式数据

VSCode中配置node.js的实现示例

《VSCode中配置node.js的实现示例》本文主要介绍了VSCode中配置node.js的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录一.node.js下载安装教程二.配置npm三.配置环境变量四.VSCode配置五.心得一.no

Java的"伪泛型"变"真泛型"后对性能的影响

《Java的伪泛型变真泛型后对性能的影响》泛型擦除本质上就是擦除与泛型相关的一切信息,例如参数化类型、类型变量等,Javac还将在需要时进行类型检查及强制类型转换,甚至在必要时会合成桥方法,这篇文章主... 目录1、真假泛型2、性能影响泛型存在于Java源代码中,在编译为字节码文件之前都会进行泛型擦除(ty

JS+HTML实现在线图片水印添加工具

《JS+HTML实现在线图片水印添加工具》在社交媒体和内容创作日益频繁的今天,如何保护原创内容、展示品牌身份成了一个不得不面对的问题,本文将实现一个完全基于HTML+CSS构建的现代化图片水印在线工具... 目录概述功能亮点使用方法技术解析延伸思考运行效果项目源码下载总结概述在社交媒体和内容创作日益频繁的

Node.js 数据库 CRUD 项目示例详解(完美解决方案)

《Node.js数据库CRUD项目示例详解(完美解决方案)》:本文主要介绍Node.js数据库CRUD项目示例详解(完美解决方案),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考... 目录项目结构1. 初始化项目2. 配置数据库连接 (config/db.js)3. 创建模型 (models/

使用Node.js制作图片上传服务的详细教程

《使用Node.js制作图片上传服务的详细教程》在现代Web应用开发中,图片上传是一项常见且重要的功能,借助Node.js强大的生态系统,我们可以轻松搭建高效的图片上传服务,本文将深入探讨如何使用No... 目录准备工作搭建 Express 服务器配置 multer 进行图片上传处理图片上传请求完整代码示例