提升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

相关文章

C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解

《C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解》:本文主要介绍C++,C#,Rust,Go,Java,Python,JavaScript性能对比全面... 目录编程语言性能对比、核心优势与最佳使用场景性能对比表格C++C#RustGoJavapythonjav

CPython与PyPy解释器架构的性能测试结果对比

《CPython与PyPy解释器架构的性能测试结果对比》Python解释器的选择对应用程序性能有着决定性影响,CPython以其稳定性和丰富的生态系统著称;而PyPy作为基于JIT(即时编译)技术的替... 目录引言python解释器架构概述CPython架构解析PyPy架构解析架构对比可视化性能基准测试测

MySQL 批量插入的原理和实战方法(快速提升大数据导入效率)

《MySQL批量插入的原理和实战方法(快速提升大数据导入效率)》在日常开发中,我们经常需要将大量数据批量插入到MySQL数据库中,本文将介绍批量插入的原理、实现方法,并结合Python和PyMySQ... 目录一、批量插入的优势二、mysql 表的创建示例三、python 实现批量插入1. 安装 PyMyS

Java JAR 启动内存参数配置指南(从基础设置到性能优化)

《JavaJAR启动内存参数配置指南(从基础设置到性能优化)》在启动Java可执行JAR文件时,合理配置JVM内存参数是保障应用稳定性和性能的关键,本文将系统讲解如何通过命令行参数、环境变量等方式... 目录一、核心内存参数详解1.1 堆内存配置1.2 元空间配置(MetASPace)1.3 线程栈配置1.

JS纯前端实现浏览器语音播报、朗读功能的完整代码

《JS纯前端实现浏览器语音播报、朗读功能的完整代码》在现代互联网的发展中,语音技术正逐渐成为改变用户体验的重要一环,下面:本文主要介绍JS纯前端实现浏览器语音播报、朗读功能的相关资料,文中通过代码... 目录一、朗读单条文本:① 语音自选参数,按钮控制语音:② 效果图:二、朗读多条文本:① 语音有默认值:②

在Node.js中使用.env文件管理环境变量的全过程

《在Node.js中使用.env文件管理环境变量的全过程》Node.js应用程序通常依赖于环境变量来管理敏感信息或配置设置,.env文件已经成为一种流行的本地管理这些变量的方法,本文将探讨.env文件... 目录引言为什么使php用 .env 文件 ?如何在 Node.js 中使用 .env 文件最佳实践引

使用Node.js和PostgreSQL构建数据库应用

《使用Node.js和PostgreSQL构建数据库应用》PostgreSQL是一个功能强大的开源关系型数据库,而Node.js是构建高效网络应用的理想平台,结合这两个技术,我们可以创建出色的数据驱动... 目录初始化项目与安装依赖建立数据库连接执行CRUD操作查询数据插入数据更新数据删除数据完整示例与最佳

Docker多阶段镜像构建与缓存利用性能优化实践指南

《Docker多阶段镜像构建与缓存利用性能优化实践指南》这篇文章将从原理层面深入解析Docker多阶段构建与缓存机制,结合实际项目示例,说明如何有效利用构建缓存,组织镜像层次,最大化提升构建速度并减少... 目录一、技术背景与应用场景二、核心原理深入分析三、关键 dockerfile 解读3.1 Docke

Three.js构建一个 3D 商品展示空间完整实战项目

《Three.js构建一个3D商品展示空间完整实战项目》Three.js是一个强大的JavaScript库,专用于在Web浏览器中创建3D图形,:本文主要介绍Three.js构建一个3D商品展... 目录引言项目核心技术1. 项目架构与资源组织2. 多模型切换、交互热点绑定3. 移动端适配与帧率优化4. 可

从原理到实战解析Java Stream 的并行流性能优化

《从原理到实战解析JavaStream的并行流性能优化》本文给大家介绍JavaStream的并行流性能优化:从原理到实战的全攻略,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的... 目录一、并行流的核心原理与适用场景二、性能优化的核心策略1. 合理设置并行度:打破默认阈值2. 避免装箱