大厂Offer收割机:Netty处理写事件之连环四问,你能抗住吗?

Unity海洋渲染实战:Ceto Ocean System核心原理与高级应用指南 实时水面渲染是计算机图形学中的重要课题,涉及波浪模拟、光照交互和着色器编程等核心技术。其原理通常基于物理模型,如使用Gerstner波模拟规则海浪,或通过快速傅里叶变换(FFT)处理频谱数据生成随机海面。这些技术的价值在于能以可控的性能开销,在游戏中实现具有体积感、反射和折射效果的真实水体。在开放世界、海战模拟等应用场景中,专业的海洋系统如Ceto Ocean System,通过模块化架构整合了波浪生成、动态网格和渲染管线,为开发者提供了完整的解决方案。本文深入探讨了其双引擎波浪系统和多层渲染结构,并分享了 阅读详情

该系列已分别介绍了服务端、客户端的启动流程、网络读事件处理流程,本文将重点剖析Netty是如何封装NIO的写事件。

温馨提示:本文虽然是源码分析,但强烈建议精读,因为根据源码阐述其背后的设计哲学,也用黑体进行了标注,请特别留意。

在阅读本篇文章之前,请稍微思考如下几个问题:

  • 写事件需要先注册才能往通道中写入数据?

  • 什么时候需要向通道注册写事件呢?

  • 业务线程池执行业务逻辑后,是如何通过IO线程将数据写入到网络中的呢?

  • Netty中如何针对写限流

1、写事件概述


写事件,顾名思义,就是将数据写入网络,通过网络传输给接收端,通常我们知道业务都会在专属的业务线程池中执行,那数据是如何通过IO线程写入网络中的呢?

图片


正如上图中的线程模型,业务线程池是如何将数据通过IO线程写入网络中的呢?

接下来我们将带着问题,尝试看Netty是如何封装NIO的写事件。

2、写事件处理流程分析


在Netty中,写事件的处理入口为NioEventLoop的processSelectedKey方法:

图片


根据调用链,最终调用AbstractChannel的内部类AbstractUnsafe的flush0方法。

图片

AbstractUnsafe#flush0


该方法有三个实现要点:

  • 获取写缓存队列,如果写缓存队列为空,则跳过本次写事件。每一个通道独享一个写缓存队列,写事件触发执行的动作就是要将写缓存中的数据写入到网络中。

  • 如果通道处于未激活状态,需要清理写缓存区

  • 通过调用doWrite方法将写缓存中的数据写入网络通道中。

技巧:该方法的触发点是事件选择器,即NIO中的Selector事件线程,需要写入的数据是该通道对应的通道缓存,那写缓存中的数据从哪里来呢?通常业务线程如何将数据写入到通道的写缓存呢?

2.1 NIO写事件的优雅封装

首先,我们将写缓存区当成一个黑盒,先重点看一下doWrite方法的实现,窥探一下Netty是如何基于NIO来处理网络写入的。

图片


Step1:如果写缓存区中没有可写的数据,取消注册写事件。我们来看一下取消写事件的经典实现技巧:

图片


首先判断一下注册键是否有效,然后通过位运算,取消写事件。

思考题:问题来了,取消写事件,从系统层面就无法继续触发写操作了,那后续如何触发写事件呢?

图片


写事件的处理要考虑如下几个问题:

  • 本次写缓存区中数据是否写完?

  • 如果底层网络Socket缓存区积压,导致写缓冲区未写完如何处理?

  • 如果网络缓存区数据特别大又如何处理?

Netty给出的解决方案如下:

  • 通过底层NIO的SocketChannel的write方法将数据写入到Socket缓存区,如果返回值为0,表示Socket缓冲区已满,需要暂停写入,具体做法,注册写事件,等待下次继续写入。

  • 如果写缓存区的数据全部处理完毕,可取消注册写事件,避免毫无意义的写事件就绪。

  • 如果写缓存区中数据很大,为了避免单个通道对其他通道的影响,默认设置单次写事件最多调用底层NIO SocketChannel的write方法次数,默认为16。

写事件的核心处理要点就介绍到这里了。

2.2 通道写缓冲区详解

在Netty中调用通道的write方法并不会立即将数据写入到底层网络Socket中,而是写入到“写缓存区”,为应用级别的缓存区,即ChannelOutboundBuffer,这是Netty实现写操作最重要的一个数据结构。

2.2.1 类图

ChannelOutboundBuffer 的核心类图如下:

图片


核心属性与方法简介:

  • FastThreadLocal

    NIO_BUFFERS
    可以看出是线程本地变量ThreadLocal的优化版本,存储一个一个ByteBuffer数组。
  • Channel channel
    该写缓存区所属的通道,每一个Channel独享一个写缓冲区。

  • Entry flushedEntry
    表示第一个被刷新的Entry,在写入时,从该Entry开始写。

  • Entry unflushedEntry
    在链表中第一个未刷新的节点(未刷新链表中第一个节点)。

  • Entry tailEntry
    在链表中尾部的节点。

  • int flushed
    待写入的entry个数,这个数据代表在执行一次真正的flush(flush0),将会有多少个entry中的内容会被写入到通道。

接下来我们按照写事件对待写入缓存区方法调用的顺序来讲解一下该方法的核心实现逻辑。

2.2.2  size方法详解

public int size() {
    return flushed;
}

返回本次写缓存区可期望刷新的消息个数(Entry)。在NioSocketChannel的doWriter方法中,如果isEmpty返回true,直接结束本次写入操作,更加准确的是结束本次flush操作。

flushed该字段代表的当时待写入的Entry,如果为0,表示没有待flush的Entry,但不代表ChannelOutboundBuffer中没有Entry存在,比如调用Channel.writer方法,会往ChannelOutboundBuffer增加Entry,但在没有调用addFlush方法之前,ChannelOutboundBuffer中的flushed 字段的值不会增加。

2.2.3  addMessage方法详解

图片


向写缓存中添加消息,方法本身的实现非常简单,因为ChannelOutboundBuffer其内部数据结构为一个链表,这是一个往链表中添加消息的过程,这里的关键点是该方法的调用入口为Channel的write方法,即调用通道的write方法只是将数据写入到写缓存,并不会触发真正的往网络中写消息。

该方法会调用incrementPendingOutboundBytes,我们简单看一下该方法的实现细节:

图片

该方法蕴含了Netty一个非常重要的机制,写操作限流,高低水位线机制。
当缓存区中存储的数据超过了设置的高水位线(阔值),则会设置为不可写,并向通道传播写状态变更事件。

2.2.4  addFlush方法详解

图片


该方法并没有真正的执行刷新动作,而是计算可刷写的Entry个数,一次刷新动作,会将unfluedEntry开始,一直扫描到tailEntry。

同样这里和Netty的写限流有关,将数据刷写后,会减少缓存区中的大小,如果低于设置的低水位线,会将缓存区恢复到可写状态。

该方法的调用入口为下图:

图片


即在调用通道的flush方法时会先计算本次看刷写到Socket缓存区中的数据,然后执行flush0方法执行真正的网络写,该方法在第一部分中已详细介绍。

 

SRAM compiler中 Number of banks 设置 的值时,需要考虑应用的性能需求、功耗要求和面积限制。设计者应根据具体的应用场景选择合适的bank数量,以优化整体系统性能。bank是一种用于分离存储器访问的设计结构,允许同时对不同的存储区域进行读写操作,从而提高存储器的并发访问性能。选项用于指定 SRAM 存储器的 并发存储区域。在 SRAM 编译器中, 阅读详情

相关推荐

手把手教你用Gazebo和VINS-MONO搞定VIO SLAM仿真(附Realsense D435i模型配置)

本文详细介绍了如何使用Gazebo和VINS-MONO构建VIO SLAM仿真环境,包括Realsense D435i模型的配置与集成。通过实战指南,帮助开发者快速搭建高保真仿真平台,优化VIO性能,并解决常见问题,适用于机器人感知与定位导航领域。

weixin_30682415的博客 159

Netty4使用指南(三) 流量控制

Netty4使用指南(三) 流量控制 概述 在实际生活中我们可能会因为某些原因需要控制服务端的读写速率,根据业务需求对不同的用户提供不同的下载速度,Netty本身也提供了高低水位和流量整形,两种方式来控制流量。 高低水位 netty中的高低水位机制会在发送缓冲区的数据超过高水位时触发channelWritabilityChanged事件同时将channel的写状态设置为false,但是这个写状态只是程序层面的状态,程序还是可以继续写入数据。所以使用这个机制时需要自行判断是否可写,并做相应的处理。 流

qq_34772568的博客 6186

WebRTC Qos优化杂记

本文是笔者对WebRTC Qos性能研究、优化的一些思考,希望对有兴趣的读者有一些启发。

sonysuqin的专栏 6677

Netty Tcp 限流

在 TCP 连接中,窗口大小()表示服务端可以接收的最大数据量。我们的目标是根据这个窗口大小动态调整客户端发送数据的速率。获取服务器的窗口大小:通过读取通道的可用字节数。控制发送速率:根据可用的窗口大小来决定每次发送多少数据,以及发送的频率。});// 连接到服务端// 启动发送线程// 计数器// 获取可用窗口大小。

1063

2 利用ITK实现多帧Dicom读取,VTK实现数据显示

vtk中也有dicom读写类,但是只能完成单帧DICOM数据读取,这对于实际应用是非常不利的。而ITK可以实现dicom多帧读取,通常情况ITK与VTK也会结合使用(ITK处理,VTK显示),所以就一起学习下吧!

buerbuhuitou的博客 1564

PHP证书图片生成

$realname = "姓名"; $schoolname = "学校"; $idcard = "身份证号"; $image = imagecreatefrompng('certification.png'); // 证书模版图片文件的路径 $red = imagecolorallocate($image,00,00,00); // 字体颜色

4036

大厂Offer收割机:Netty优雅的网络写设计之连坏4问

写事件需要先注册才能往通道中写入数据?什么时候需要向通道注册写事件呢?业务线程池执行业务逻辑后,是如何通过IO线程将数据写入到网络中的呢?Netty中如何针对写限流?

中间件兴趣圈 4970

【Unity学习笔记】事件系统EventSystem

1.EventSystem物体 第一次在Unity中创建UI元素时,总会自动生成一个EventSystem物体,它包含三个组件:Transform、EventSystem、Standalone Input Module。如果我们把它删除了,会发现UI上的事件(比如点击、拖拽)将不会被检测到。没错,它就是用来处理UI相关的事件的。 1.1 EventSystem组件 EventSystem基于输入给物体发送事件,它在整个事件系统中扮演的主要角色是: 1.管理被选中的物体 2.管理正在使用的Input Modu

一白梦人的博客 1万+

内置消息限流控制

4.资源释放问题,在Channel关闭或者流量整形ChannelHandler被移除时,由于ChannelTrafficShaping-Handler持有消息发送队列,如果不对消息队列进行清空处理,则会导致待发送消息丢失,或者消息队列积压,引起内存泄漏(频繁地断连和重连,会创建N个ChannelTrafficShaping-Handler实例,对应N个消息发送队列)。除了动态流控,有时候还需要对消息的读取和发送速度做控制,以便消息能以较恒定的速度发送到下游网元,保护下游各系统不受突发的流量冲击。

这个人很懒什么都没有~ 1018

白话机器学习算法理论+实战番外篇之Xgboost

1. 写在前面 如果想从事数据挖掘或者机器学习的工作,掌握常用的机器学习算法是非常有必要的,在这简单的先捋一捋, 常见的机器学习算法: 监督学习算法:逻辑回归,线性回归,决策树,朴素贝叶斯,K近邻,支持向量机,集成算法Adaboost等 无监督算法:聚类,降维,关联规则, PageRank等 我前面已经尝试用最白话的语言完成了一个白话机器学习算法理论+实战系列,这个系列已经基本包含了上面这些算...

Miracle8070 1万+

OsgEarth —— 笔记6 - 开发阶段加入漫游飞行(附源码)

效果      视频地址   源码 源码下载请私信   代码      代码相关内容:           OSG —— 笔记1 - 指令调用模型           OsgEarth —— 笔记1 - 创建地球的earth文件           OsgEarth —— 笔记2 - Qt窗口加载earth地球(附源码)           OsgEarth —— 笔记3 - 为地

1896

系统降级熔断限流和排队

这类问题的主要原因在于系统压力太大、负载太高,导致无法快速处理业务请求,由此引发更多的后续问题。最常见的情况就是,数据库慢查询将数据库的服务器资源耗尽,导致读写超时,业务读写数据库时要么无法连接数据库、要么超时,最终用户看到的现象就是访问很慢,一会儿访问抛出异常,一会儿访问又是正常结果。如果进一步探究,导致接口级故障的原因可以分为两大类:内部原因:包括程序 bug 导致死循环,某个接口导致数据库慢查询,程序逻辑不完善导致耗尽内存等。外部原因:包括黑客攻击,促销或者抢购引入了超出平时几倍甚至几十倍的用户,第三

andy.cao的博客 1905

2025年“区块链技术”职业院校技能大赛赛后复盘与总结(必看)

记录一次2025年“区块链技术”职业院校技能大赛的参加经验总结与赛后复盘

我是网络安全兼技能大赛工程师,专注网络安全技术学习与技能大赛实战!持续分享最新的技术文章,帮你少走弯路,一起在技术赛道上进步~ 1992

大厂Offer收割机:Netty优雅的网络写设计之连坏4问,2024年最新电商秒杀java面试题

Java架构进阶面试及知识点文档笔记这份文档共498页,其中包括Java集合,并发编程,JVM,Dubbo,Redis,Spring全家桶,MySQL,Kafka等面试解析及知识点整理Java分布式高级面试问题解析文档其中都是包括分布式的面试问题解析,内容有分布式消息队列,Redis缓存,分库分表,微服务架构,分布式高可用,读写分离等等!互联网Java程序员面试必备问题解析及文档学习笔记Java架构进阶视频解析合集。

2401_84447262的博客 544

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

大厂Offer收割机:Netty优雅的网络写设计之连坏4问(1),腾讯数据分析笔试面试

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!技术提升。**需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)

2401_84447262的博客 675

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

2024年最新大厂Offer收割机:Netty优雅的网络写设计之连坏4问,字节跳动架构师面试

本人面试腾讯,阿里,百度等企业总结下来的面试经历,都是真实的,分享给大家!

2401_84584817的博客 309

知道了这些BAT大厂面试“潜规则”,让你成为行走的“offer收割机”

一、写在前面 不少Java程序员兄弟,在在应聘一些中大型互联网公司的Java工程师岗位时,经常会遇到如下困惑。 这些同学说自己也做了精心准备,网上搜集了不少Java面试题。 然而实际去互联网公司面试才发现,人家问的,和你准备的根本对不上号,面试现场经常弥漫着尴尬的气氛,最后的面试结果也是不言而喻! 二、先来体验一个真实的面试连环炮 那么,为什么这些兄弟会出现这种情况呢? 首先,我们来看看真实的一二...

weixin_44541500的博客 291

互联网寒冬!阿里架构师的Java知识地图(28个知识点),让我成了offer收割机

在目前流行的互联网架构中,对一个应用来说,Tomcat是首,SSM是中,JVM是尾,我们通常对于SSM是比较了解的,而忽略了首尾,而Tomcat在目前的网络编程中是举足轻重的,但是我们其实对Tomcat中很多原理性的东西不太了解,如果能够掌握Tomcat的原理,那么是非常有用的。SSM框架,是Spring + Spring MVC + MyBatis的缩写,这个是继SSH之后,目前比较主流的Java EE企业级框架,适用于搭建各种大型的企业级应用系统,也是Java程序员必须要掌握的技术。

2501_90433155的博客 574

Java开发者进阶:从面试准备到技术体系构建

Java作为企业级开发的核心语言,其技术体系涵盖JVM原理、并发编程和分布式系统设计等关键领域。理解JVM内存模型与GC调优机制是性能优化的基础,而并发编程中的可见性、有序性和原子性问题是构建高并发系统的核心挑战。在分布式场景下,CAP定理的灵活运用能有效解决如秒杀系统等高并发需求。通过系统化的知识图谱构建和算法训练,开发者可以全面提升技术深度与工程实践能力,这些经验对于应对大厂技术面试和实际项目开发都具有重要价值。

weixin_30294295的博客 370

“解决限流失效问题:通过配置类优化Sentinel在前置模块处理H5请求和Netty接收Socket请求中的应用“

限流失效

懿 576

基于 Netty 的帧调度策略,自行实现流量控制及可靠性通信

Java 服务器和硬件设备通信的过程中,众多的硬件设备可能数据帧处理能力较差,可靠性较差,所以在 Netty 模块中使用了帧调度算法。服务器大规模下发数据帧时,可进行有效的拥塞控制、超时重发,可有效提升集群设备的可靠性,降低集群设备的研发难度。

雪中亮 4300

Netty是一个由JBOSS提供的开源Java框架,目前已经成为Github上的独立项目

Netty是一个基于NIO的客户、服务器端的编程框架,使用Netty可以确保快速和简单地开发出网络应用,例如实现了某种协议的客户、服务端应用。它简化和流线化了网络应用的编程开发过程,例如基于TCP和UDP的socket服务开发。最终,Netty成功地找到了一种方式,在保证易于开发的同时还保证了其应用的性能、稳定性和伸缩性。它提供了一个异步、事件驱动的网络应用程序框架和工具,用于快速开发高性能、高可靠性的网络服务器和客户端程序。以上信息仅供参考,如有需要,建议您查阅相关网站。

[Blog][Domain] programb.blog.youkuaiyun.com 1288

netty大文件下载

ChannelTrafficShapingHandler 限流 ChannelPipeline pipeline = ch.pipeline(); //**流量整形,必须放在第一位;使用DefaultFileRegion(sendFile)时该限制不起作用** pipeline.addLast(new ChannelTrafficShapingHandl

seaman712的专栏 1411

【netty】netty的pipeline理解

Netty 的 Pipeline 是一种非常重要的概念,它负责对 Channel 上的事件进行处理,并提供了一种灵活的扩展机制。整个 Pipeline 的处理流程就像一个工厂的生产线一样,每个 Handler 扮演着不同的角色。Pipeline 是 Netty 中非常重要的一个组件,它通过灵活的 Handler 链式处理机制实现了高效、稳定、可扩展的网络编程。Pipeline 由一系列的 Handler 组成,Handler 通常会被添加到 Pipeline 中,从而形成一个有序的 Handler 链。

热爱技术,享受生活 1万+

Netty 中的流控与统计

转自:https://emacsist.github.io/2018/04/26/netty-中的流控与统计/Netty 流量相关的包io.netty.handler.trafficChannelTrafficShapingHandler : Channel 级别的GlobalChannelTrafficShapingHandler : 全局级别的(无论打开多少Channel) 以及 每条 Cha...

infi 7212
上一篇: 通俗讲解分布式锁,这次你一定能懂!
下一篇: 19张图带你梳理SpringCloud体系中的重要技术点!
Java斗帝之路
博客等级 码龄7年 2392粉丝 687原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值