Netty 与 RPC(一)

Netty RPC

Netty 原理

Netty 是一个高性能、异步事件驱动的 NIO 框架,基于 JAVA NIO 提供的 API 实现。它提供了对TCP、UDP 和文件传输的支持,作为一个异步 NIO 框架,Netty 的所有 IO 操作都是异步非阻塞的,通过 Future-Listener 机制,用户可以方便的主动获取或者通过通知机制获得 IO 操作结果。

Netty 高性能

在 IO 编程过程中,当需要同时处理多个客户端接入请求时,可以利用多线程或者 IO 多路复用技术进行处理。IO 多路复用技术通过把多个 IO 的阻塞复用到同一个 select 的阻塞上,从而使得系统在单线程的情况下可以同时处理多个客户端请求。与传统的多线程/多进程模型比,I/O 多路复用的最大优势是系统开销小,系统不需要创建新的额外进程或者线程,也不需要维护这些进程和线程的运行,降低了系统的维护工作量,节省了系统资源。与 Socket 类和 ServerSocket 类相对应,NIO 也提供了 SocketChannel 和 ServerSocketChannel

两种不同的套接字通道实现。

多路复用通讯方式

Netty 架构按照 Reactor 模式设计和实现,它的服务端通信序列图如下:

image-20231223085934999

客户端通信序列图如下:

image-20231223090117557

Netty 的 IO 线程 NioEventLoop 由于聚合了多路复用器 Selector,可以同时并发处理成百上千个客户端 Channel,由于读写操作都是非阻塞的,这就可以充分提升 IO 线程的运行效率,避免由于频繁 IO 阻塞导致的线程挂起。

异步通讯 NIO

由于 Netty 采用了异步通信模式,一个 IO 线程可以并发处理 N 个客户端连接和读写操作,这从根本上解决了传统同步阻塞 IO 一连接一线程模型,架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。

零拷贝(DIRECT BUFFERS 使用堆外直接内存)
  1. Netty 的接收和发送 ByteBuffer 采用 DIRECT BUFFERS,使用堆外直接内存进行 Socket 读写,不需要进行字节缓冲区的二次拷贝。如果使用传统的堆内存(HEAP BUFFERS)进行 Socket 读写,JVM 会将堆内存 Buffer 拷贝一份到直接内存中,然后才写入 Socket 中。相比于堆外直接内存,消息在发送过程中多了一次缓冲区的内存拷贝。

  2. Netty 提供了组合 Buffer 对象,可以聚合多个 ByteBuffer 对象,用户可以像操作一个 Buffer 那样方便的对组合 Buffer 进行操作,避免了传统通过内存拷贝的方式将几个小 Buffer 合并成一个大的Buffer。

  3. Netty的文件传输采用了transferTo方法,它可以直接将文件缓冲区的数据发送到目标Channel,避免了传统通过循环 write 方式导致的内存拷贝问题

内存池(基于内存池的缓冲区重用机制)

随着 JVM 虚拟机和 JIT 即时编译技术的发展,对象的分配和回收是个非常轻量级的工作。但是对于缓冲区 Buffer,情况却稍有不同,特别是对于堆外直接内存的分配和回收,是一件耗时的操作。为了尽量重用缓冲区,Netty 提供了基于内存池的缓冲区重用机制。

高效的 Reactor 线程模型

常用的 Reactor 线程模型有三种,Reactor 单线程模型, Reactor 多线程模型, 主从 Reactor 多线程模型。

Reactor 单线程模型

Reactor 单线程模型,指的是所有的 IO 操作都在同一个 NIO 线程上面完成,NIO 线程的职责如下:

  1. 作为 NIO 服务端,接收客户端的 TCP 连接;
  2. 作为 NIO 客户端,向服务端发起 TCP 连接;
  3. 读取通信对端的请求或者应答消息;
  4. 向通信对端发送消息请求或者应答消息。

image-20231223090423607

由于 Reactor 模式使用的是异步非阻塞 IO,所有的 IO 操作都不会导致阻塞,理论上一个线程可以独立处理所有 IO 相关的操作。从架构层面看,一个 NIO 线程确实可以完成其承担的职责。例如,通过Acceptor 接收客户端的 TCP 连接请求消息,链路建立成功之后,通过 Dispatch 将对应的 ByteBuffer派发到指定的 Handler 上进行消息解码。用户 Handler 可以通过 NIO 线程将消息发送给客户端。

Reactor 多线程模型

Rector 多线程模型与单线程模型最大的区别就是有一组 NIO 线程处理 IO 操作。 有专门一个NIO 线程-Acceptor 线程用于监听服务端,接收客户端的 TCP 连接请求; 网络 IO 操作-读、写等由一个 NIO 线程池负责,线程池可以采用标准的 JDK 线程池实现,它包含一个任务队列和 N个可用的线程,由这些 NIO 线程负责消息的读取、解码、编码和发送;

image-20231223090517833

主从 Reactor 多线程模型

服务端用于接收客户端连接的不再是个 1 个单独的 NIO 线程,而是一个独立的 NIO 线程池。Acceptor 接收到客户端 TCP 连接请求处理完成后(可能包含接入认证等),将新创建的SocketChannel 注册到 IO 线程池(sub reactor 线程池)的某个 IO 线程上,由它负责SocketChannel 的读写和编解码工作。Acceptor 线程池仅仅只用于客户端的登陆、握手和安全认证,一旦链路建立成功,就将链路注册到后端 subReactor 线程池的 IO 线程上,由 IO 线程负责后续的 IO 操作。

image-20231223090558372

无锁设计、线程绑定

Netty 采用了串行无锁化设计,在 IO 线程内部进行串行操作,避免多线程竞争导致的性能下降。表面上看,串行化设计似乎 CPU 利用率不高,并发程度不够。但是,通过调整 NIO 线程池的线程参数,可以同时启动多个串行化的线程并行运行,这种局部无锁化的串行线程设计相比一个队列-多个工作线程模型性能更优。

image-20231223090625315

Netty 的 NioEventLoop 读取到消息之后,直接调用 ChannelPipeline 的fireChannelRead(Object msg),只要用户不主动切换线程,一直会由 NioEventLoop 调用到用户的 Handler,期间不进行线程切换,这种串行化处理方式避免了多线程操作导致的锁的竞争,从性能角度看是最优的。

高性能的序列化框架

Netty 默认提供了对 Google Protobuf 的支持,通过扩展 Netty 的编解码接口,用户可以实现其它的高性能序列化框架,例如 Thrift 的压缩二进制编解码框架。

  1. SO_RCVBUF 和 SO_SNDBUF:通常建议值为 128K 或者 256K。

小包封大包,防止网络阻塞

  1. SO_TCPNODELAY:NAGLE 算法通过将缓冲区内的小封包自动相连,组成较大的封包,阻止大量小封包的发送阻塞网络,从而提高网络应用效率。但是对于时延敏感的应用场景需要关闭该优化算法。

软中断 Hash 值和 CPU 绑定

  1. 软中断:开启 RPS 后可以实现软中断,提升网络吞吐量。RPS 根据数据包的源地址,目的地址以及目的和源端口,计算出一个 hash 值,然后根据这个 hash 值来选择软中断运行的 cpu,从上层来看,也就是说将每个连接和 cpu 绑定,并通过这个 hash 值,来均衡软中断在多个 cpu 上,提升网络并行处理性能。

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

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

相关文章

React学习计划-React16--React基础(四)生命周期和diffing算法,key的作用

1. 生命周期 1. 声命周期的三个阶段(旧) 初始化阶段:由ReactDOM.render()触发—初次渲染 1. constructor() 2. componentWillMount() 3. render() 4. componentDidMount() > 常用一般在这个钩子中做一些初始化的事情,例如&am…

亚马逊测评的重要性和技术选择

亚马逊测评是指卖家通过各种途径,如测评平台、社区、红人等,联系到亚马逊的买家,让其对卖家的产品进行评价和留下真实的综合评价,这对于跨境电商卖家来说非常重要,因为亚马逊的排名和转化率很大程度上取决于产品的评价…

Python代码示例 | 时间序列数据的组成

时间序列数据是以固定的时间间隔记录或收集的数据点序列。它是一种跟踪变量随时间演变的数据,如销售,股票价格,温度等。定期的时间间隔可以是每天,每周,每月,每季度或每年,数据通常表示为线图或…

ArchLinux搭建riscv测试环境(失败)

参考 Boot an Arch Linux RISC-V using qemu-system - JieJiSS Blog 安装ArchLinux安装所需包 sudo pacman -S arch-install-scripts git qemu-img qemu-system-riscv sudo pacman -S riscv64-linux-gnu-gcc 安装yay git clone https://aur.archlinux.org/yay-bin cd yay-b…

Java小案例-Bean是如何注入到Spring中的,有几种注入方式

前言 关于Bean注入Spring容器的方式网上也有很多相关文章,但是很多文章可能会存在以下常见的问题 注入方式总结的不全 没有分析可以使用这些注入方式背后的原因 没有这些注入方式在源码中的应用示例 ... 所以本文就带着解决上述的问题的目的来重新梳理一下Bea…

关于增强监控以检测针对Outlook Online APT活动的动态情报

一、基本内容 2023年6月,联邦民事行政部门(FCEB)在其Microsoft 365(M365)云环境中发现了可疑活动。该机构迅速向Microsoft和网络安全和基础设施安全局(CISA)报告了此情况。经过深入调查&#x…

C 语言中布尔值的用法和案例解析

C语言中的布尔值 在编程中,您经常需要一种只能有两个值的数据类型,例如: 是/否开/关真/假 为此,C语言有一个 bool 数据类型,称为布尔值。 布尔变量 在C语言中,bool 类型不是内置数据类型,例…

docker安装的php 在cli中使用

1: 修改 ~/.bashrc 中新增 php7 () {ttytty -s && tty--ttydocker run \$tty \--interactive \--rm \--volume /website:/website:rw \--workdir /website/project \--networkdnmp_dnmp \dnmp_php php "$" }–networkdnmp_dnmp 重要, 不然连不上数据库, 可通…

【数字通信原理】复习笔记

哈喽ノhi~ 小伙伴们许久没有更新啦~ 花花经历了漫长的考试周~ 要被累成花干啦。今天来更新《数字通信原理》手写笔记给需要的小伙伴~ (注:这是两套笔记,是需要结合来看的哦~) 第一套的笔记请结合bilibili:张锦皓的复习课程来哦。 第…

图神经网络并在 TensorFlow 中实现

asokraju.medium.com 一、说明 本文将引导您了解图神经网络 (GNN) 并使用 TensorFlow 实现该网络。在后续的 文章中,我们讨论 GNN 的不同变体及其实现。这是一个分步计划: 图神经网络 (GNN) 的使用:我们首先讨论 GNN 是什么、它们如何工作以及…

项目管理常用的ChatGPT通用提示词模板

项目目标设定:如何设定明确、可衡量的项目目标? 项目计划制定:如何制定详细的项目计划,包括时间表、任务分配、资源需求等? 风险管理:如何识别和评估项目风险,并制定相应的应对措施&#xff1…

Leetcode—415.字符串相加【简单】

2023每日刷题(六十八) Leetcode—415.字符串相加 实现代码 class Solution { public:string addStrings(string num1, string num2) {string ans;int len1 num1.size();int len2 num2.size();int i len1 - 1, j len2 - 1;int sum 0, c 0;while(i…

Leetcode-230.二叉搜索树中第k小的元素(Python)

题目链接 此题看题解,其实这道题蛮简单的,需要注意二叉搜索树左小右大,为什么还需要看题解,需要反思! # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNon…

Unity Destroy和DestroyImmediate方法

Destroy和DestroyImmediate都是Unity用于销毁游戏对象的方法。 它们的语法是: Destroy(gameObject); DestroyImmediate(gameObject); 都接受一个参数,即销毁的对象。 但是它们是有一定区别的。 1、Destroy方法它会延迟销毁,当我们调用它…

MFC 自定义压缩,解压缩工具

界面效果如下: 对外提供的接口如下: public: void setCallback(zp::Callback callback, void* param); bool open(const zp::String& path, bool readonly false); bool create(const zp::String& path, const zp::String& inputPath)…

【JavaWeb】Listener Filter

Listener监听器 一、Listener概述 1、监听器概念 web的三大组件之一。 2、事件监听机制 事件:一件事情事件源:事件发生的地方监听器:一个对象注册监听:将事件、事件源、监听器绑定在一起。 当事件源上发生某个事件后&#xf…

P5410 【模板】扩展 KMP/exKMP(Z 函数)

【模板】扩展 KMP/exKMP(Z 函数) 题目描述 给定两个字符串 a , b a,b a,b,你要求出两个数组: b b b 的 z z z 函数数组 z z z,即 b b b 与 b b b 的每一个后缀的 LCP 长度。 b b b 与 a a a 的每一个后缀的 LC…

关于“Python”的核心知识点整理大全37

目录 13.6.2 响应外星人和飞船碰撞 game_stats.py settings.py alien_invasion.py game_functions.py ship.py 注意 13.6.3 有外星人到达屏幕底端 game_functions.py 13.6.4 游戏结束 game_stats.py game_functions.py 13.7 确定应运行游戏的哪些部分 alien_inva…

C#学习笔记 - C#基础知识 - C#从入门到放弃 - C# 结构、类与属性

C# 入门基础知识 - C# 结构、类与属性 第9节 结构、类与属性9.1 结构的使用9.2 枚举9.3 面向对象概述9.4 类与对象的关系9.5 类的声明9.6 属性的使用9.6.1 属性9.6.2 属性使用 9.7 构造函数和析构函数9.7.1 构造函数9.7.2 析构函数 9.8 类的继承9.9 类的封装9.10 类的多态 更多…

非阻塞 IO(NIO)

文章目录 非阻塞 IO(NIO)模型驱动程序应用程序模块使用 非阻塞 IO(NIO) 上一节中 https://blog.csdn.net/tyustli/article/details/135140523,使用等待队列头实现了阻塞 IO 程序使用时,阻塞 IO 和非阻塞 IO 的区别在于文件打开的时候是否使用了 O_NONB…