Netty的几种IO模式的实现与切换

news2024/9/29 7:28:01

写在文章开头

今天我们就基于Netty来简单聊聊开发中几种常见的IO模式以及Netty对于这几种IO模式的实现,希望对你有帮助。

在这里插入图片描述

Hi,我是 sharkChili ,是个不断在硬核技术上作死的 java coder ,是 CSDN的博客专家 ,也是开源项目 Java Guide 的维护者之一,熟悉 Java 也会一点 Go ,偶尔也会在 C源码 边缘徘徊。写过很多有意思的技术博客,也还在研究并输出技术的路上,希望我的文章对你有帮助,非常欢迎你关注我的公众号: 写代码的SharkChili

因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

在这里插入图片描述

详解几种常见的IO模式

同步与异步

在了解IO模式之前我们需要了解几个重要的概念,先来聊聊同步与非同步的概念,同步即意味着若内核缓冲区存在就绪数据时,应用程序中到内核中主动read就绪数据:

在这里插入图片描述

而异步则是应用程序到系统内核获取就绪数据时,若没有数据则直接返回并注册回调,当有就绪的数据时,直接通过回调通知进程:

在这里插入图片描述

阻塞与非阻塞

网络IO中的阻塞和非阻塞,这个概念是针对应用程序数据读取阶段的,如果是阻塞读,当应用程序通过read方法到系统内核缓冲区中获取,如果缓冲区没有数据,那么当前线程就会阻塞。对应的写请求也是一样,如果缓冲区已满那么线程也会阻塞等待有足够空间再进行写入:

在这里插入图片描述

而非阻塞读取则反之,当内核缓冲区没有就绪数据时,系统调用会直接返回,写请求同理:

在这里插入图片描述

Netty提供的几种IO模式

有了上述概念的基础,我们就可以正式的介绍如下几种IO模式,它们分别是:

  1. BIO:同步阻塞模型,由上述的概念我们可以知晓这种模式如果在没有就绪数据时,线程会阻塞等待,一旦数据就绪之后也是主动调用系统内核函数主动阻塞read获取数据。
  2. NIO:同步非阻塞,很明显这种模式下到系统内核发现没有就绪的数据会直接返回,一旦有了就绪数据也是主动调用read函数获取。
  3. AIO:异步非阻塞,这种模式理论上是性能表现最出色的,系统内核没有就绪的事件它会直接注册回调并返回,后续一旦有就绪的数据则通过回调主动将数据推送给应用程序。

Netty中已经对这种模型做了封装,我们以BIO创建服务端为例对应的代码示例如下,可以看到我们的线程组和channel都是采用OiOold io模式。

这里补充说明一下,很多人认为BIO模式性能表现一定会差于NIO,这一点笔者是不认同的,个人认为对于连接少、并发度较低的场景, 的线程专注于处理这些仅有的连接的设计性能表现会更加出色:

EventLoopGroup bossGroup = new OioEventLoopGroup(1);
		//设置为BIO的事件轮询器
        EventLoopGroup workerGroup = new OioEventLoopGroup();
        final EchoServerHandler serverHandler = new EchoServerHandler();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
              //设置服务端channel为BIO
             .channel(OioServerSocketChannel.class);
            //......

如果我们希望切换为NIO则直接替换group创建和channel即可:

		//设置线程组为NIO
		EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        final EchoServerHandler serverHandler = new EchoServerHandler();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
            //设置channel为NIO类型
             .channel(NioServerSocketChannel.class);
             //......

需要了解的是Netty并没有为AIO进行相应的实现,其原因如下:

  1. AIOLinux上相较于epoll这种NIO模型性能没有太大的提升。
  2. AIOWindows上有着较成熟的方案,但是市场主流都是采用Linux作为主流服务器。
  3. AIOLinux上的实现还是不够成熟。

Netty对于IO模式自由切换的设计

可以看到Netty对于IO模式的切换只需在channel上进行简单的配置即,这一点它是如何设计与实现的呢?本质上channel方法采用的泛型抽象+工厂模式并结合反射这种理念,在配置引导类时,通过channel方法传入不同的IO模式策略class,其内部会基于这个class将其封装为channel工厂,后续服务初始化时就会基于这个channel工厂通过反射的方式生成服务端channel

在这里插入图片描述

这一点我们步入AbstractBootstrap的channel方法就可以看到,它会将我们的泛型class封装为反射工厂ReflectiveChannelFactory并通过channelFactory赋值给AbstractBootstrapchannelFactory

public B channel(Class<? extends C> channelClass) {
        //基于channelClass将其封装为ReflectiveChannelFactory然后复制给channelFactory
        return channelFactory(new ReflectiveChannelFactory<C>(
                ObjectUtil.checkNotNull(channelClass, "channelClass")
        ));
    }

后续服务端初始化方法initAndRegister就会通过channelFactorynewChannel反射生成服务端channel再调用init完成初始化:

final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
        	//调用newChannel进行反射创建channel
            channel = channelFactory.newChannel();
            //初始化channel
            init(channel);
        } catch (Throwable t) {
           //......
        }

        //......
    }

于是其内部就来到我们的实现ReflectiveChannelFactorynewChannel,可以看到它通过反射完成channel创建,很明显这种通过泛型抽象,工厂懒加载的设计很好的维护的channel的创建时机和拓展:

 @Override
    public T newChannel() {
        try {
            return constructor.newInstance();
        } catch (Throwable t) {
            throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
        }
    }

默认NIO已经实现了epoll,为什么Netty还需要自实现呢?

NIO默认已经实现了epoll,但是Netty还是自实现了一版本的epoll

  b.group(bossGroup, workerGroup)
             .channel(EpollServerSocketChannel.class)

这样做的其实是一种自信,NIO默认情况下是水平触发某些场景下开销很大,而Netty是支持自行配置水平触发和边缘触发,EpollServerSocketChannel在此基础上做了很多的参数封装,提供开发有更多的灵活的选择,对于后续的优化是可控的,且Netty实现的NIO相较于JDK默认的实现产生的垃圾更少且性能表现更出色。

小结

本文通过源码示例结合源码简单介绍了几种IO模式和Netty实现和设计理念,希望对你有帮助。

我是 sharkchiliCSDN Java 领域博客专家开源项目—JavaGuide contributor,我想写一些有意思的东西,希望对你有帮助,如果你想实时收到我写的硬核的文章也欢迎你关注我的公众号: 写代码的SharkChili
因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

在这里插入图片描述

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

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

相关文章

如何在RabbitMQ中防止消息丢失

如何在RabbitMQ中防止消息丢失 在分布式系统中&#xff0c;消息的可靠传递是至关重要的。RabbitMQ作为一个强大的消息队列系统&#xff0c;提供了多种机制来确保消息不会丢失。本文将介绍在RabbitMQ中防止消息丢失的几种方法。 消息确认机制 消息发布确认 在RabbitMQ中&…

pdf转换器哪个好?不要错过这4款转换工具

pdf转换器哪个好&#xff1f;选择一款高效的PDF转换器&#xff0c;无疑能极大地便利我们的日常工作与学习。它不仅能够轻松实现PDF文件与Word、Excel、图片等多种格式之间的互转&#xff0c;还支持批量处理&#xff0c;显著提高工作效率。无论是编辑修改、格式调整还是分享传阅…

深入浅出消息队列----【RocketMQ 和 Kafka 消息存储差异对比】

深入浅出消息队列----【RocketMQ 和 Kafka 消息存储差异对比】 RocketMQ 的消息存储Kafka 的消息存储对比 RocketMQ 与 Kafka 本文仅是文章笔记&#xff0c;整理了原文章中重要的知识点、记录了个人的看法 文章来源&#xff1a;编程导航-鱼皮【yes哥深入浅出消息队列专栏】 Roc…

指南!网上卖药品需要什么资质?

随着互联网技术的飞速发展&#xff0c;医药电商已经成为药品和医疗器械销售的重要渠道。处方药的网络销售政策逐步放宽&#xff0c;医药电商行业迎来了快速发展的春天。在这一领域&#xff0c;主要的参与者包括药品销售公司和电商平台。 为了吸引流量和满足处方药审方的需求&a…

第18课 Scratch入门篇:时钟-当前时间

时钟 故事背景&#xff1a; 在一个遥远的科技星球上&#xff0c;时间对于居民们来说无比珍贵。这个星球上的居民们都是技术高手&#xff0c;他们使用先进的编程技术来管理自己的生活。然而&#xff0c;星球上的时间系统最近出现了故障&#xff0c;导致时间的流逝变得不稳定。为…

【终极指南】大模型二次开发:从零基础到高手之路

随着人工智能技术的发展&#xff0c;预训练的大模型&#xff08;例如GPT系列、BERT等&#xff09;已成为自然语言处理领域的关键技术之一。对于开发者来说&#xff0c;掌握如何基于这些大模型进行二次开发&#xff0c;不仅可以提升自身的技术实力&#xff0c;还能为企业带来更多…

Flink 如何处理背压

文章目录 目录 前言 一、什么是背压&#xff1f; 二、处理背压的步骤 1.模拟背压机制 2.为什么要关心背压问题&#xff1f; 总结 前言 初次接触Flink的同学会对背压有很多的疑问。本文就是我学习的一些心得和体会&#xff0c;以及借鉴一些文章的感想。 Flink 如何处理背压效应…

使用snap的安装docker配置阿里云镜像加速

使用snap安装docker非常的简单&#xff0c;一条命令即可 snap install docker 但是通过这个命令安装的docker, 配置阿里云镜像跟常规安装的配置起来不太一样, 下面讲一下配置流程 修改docker配置文件/var/snap/docker/current/config/daemon.json 这个文件应该是已经创建好…

重磅!LangChain 官方发布 Agent IDE!!

1 LangChain 开发现状 LangChain 从应用开发框架出发&#xff0c;提供了一套代码级工具集&#xff0c;旨在降低 LLM 的开发难度&#xff0c;在过去一年中吸引了众多开发者&#xff0c;助力他们迅速打造 AI 大模型应用。然而&#xff0c;还有一群用户&#xff0c;他们希望门槛…

NC 最长无重复子数组

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 描述 给定一个长度…

idea连接oracle

配置 注意&#xff1a; SID指的是实例名称

C语言宠物系统3

在前面的基础上&#xff0c;加上了修改功能和排序功能&#xff0c;可以选择姓名排序&#xff0c;年龄排序&#xff0c;价格排序。 test.c源文件 #include "Pet.h"void menu() {printf("------------------------\n");printf("- 欢迎来到宠物商店 …

实践出真知:Agents 领域“一年打怪升级”的经验分享

编者按&#xff1a;在你构建 AI Agents 时&#xff0c;是否曾遇到这些困扰&#xff1a;总是在简单任务上出错&#xff0c;从而让你有时会怀疑自己的技术水平&#xff1f;面对客户的需求&#xff0c;AI Agent 表现得像个“笨蛋”&#xff0c;无法准确理解和执行指令&#xff1f;…

不同网络上的计算机怎么通信

从 一个网络上计算机的通信 &#xff0c;我们知道&#xff0c;在一个网络里&#xff0c;多台主机通过交换机连接起来&#xff0c;每台主机的网卡有全球唯一的 MAC 地址&#xff0c;一个网络上的主机通过 MAC 地址通信。 那么&#xff0c;多个网络之间如何互联和通信&#xff1…

【轨物方案】智慧供热物联网整体解决方案

目前城市供暖系统当中&#xff0c;供暖设备一直得不到更新和升级&#xff0c;没有合理的监控设备&#xff0c;导致对供暖的合理调控不理想&#xff0c;供暖严重失调而浑然不知&#xff0c;进而出现冷热不均的问题&#xff0c;极易造成资源严重浪费。缺乏成熟的管理系统&#xf…

上门按摩小程序项目开发功能介绍

上门按摩小程序通常设计为连接按摩服务提供者和客户的平台&#xff0c;提供便捷的预约和服务管理功能。以下是这类小程序可能包含的功能&#xff1a; 用户注册和登录&#xff1a; 用户可以注册个人账户并登录&#xff0c;以便管理个人信息和预约记录。 按摩师信息浏览&#xf…

JAVA中实现线程安全的三种方式

JAVA中实现线程安全的三种方式 1. 同步代码块2. 同步方法3. ReentrantLock4. 总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 1. 同步代码块 使用synchronized关键字加在需要同步的代码块上&#xff0c;并指定一个锁对象。这种方式可以…

Java作用域

目录 1.作用域 基本使用 2.作用域的注意事项和细节使用 1.作用域 基本使用 局部变量一般是成员方法里的变量 。全局变量有默认值&#xff0c;局部变量没有默认值。 在类内但是方法外定义的变量是局部变量&#xff0c;有初始值0可以不赋初值&#xff0c;在方法内的是局部变量…

本机IP地址可以随便改吗?怎样修改本机IP地址

在当今数字化时代&#xff0c;IP地址作为设备在网络中的唯一标识&#xff0c;扮演着至关重要的角色。然而&#xff0c;许多用户对于IP地址的修改存在诸多疑问&#xff0c;尤其是关于其是否可以随意更改以及如何操作。本文旨在深入探讨这些问题&#xff0c;帮助读者理解本机IP地…