如何解决 Netty Channel.isWritable 返回 false

简介: 在 Netty 里,有4个方法用来查询 Channel 的状态:isOpen,isRegistered,isActive,isWritable,其中,isWritable 在并发量很高时会返回很多 false。 isWritable 是什么含义? isWritable:Returns true if and only if the I/O thread will perform the req

在 Netty 里,有4个方法用来查询 Channel 的状态:isOpen,isRegistered,isActive,isWritable,其中,isWritable 在并发量很高时会返回很多 false。

isWritable 是什么含义?

isWritable:Returns true if and only if the I/O thread will perform the requested write operation immediately. Any write requests made when this method returns false are queued until the I/O thread is ready to process the queued write requests.

为什么 isWritable 会返回 false?而且这个问题在 stackoverflow,netty 社区也被很多人问到。

i.e.

if (channel.isWritable()) {
    channel.writeAndFlush(data);
}

 

首先,说下 netty 处理 writeAndFlush 的原理:

1、业务线程调用 writeAndFlush 发送消息,会生成 WriteAndFlushTask,交由 IO 线程处理,write 操作将消息写入 ChannelOutboundBuffer(不会写到 socket),flush 操作将 ChannelOutboundBuffer 写 入socket 的发送缓冲区;(这里注意,writeAndFlush 它只是一个语法糖,意味着这不是原子操作,因此在此方法执行的中间,可能在多个线程之间进行了上下文切换。)

2、ChannelOutboundBuffer 它配置一个高水位线和低水位线,当 buffer 的大小超过高水位线的时候对应 channel 的 isWritable 就会变成 false,当 buffer 的大小低于低水位线的时候,isWritable 就会变成 true。

其中,高水位线和低水位线是字节数,默认高水位是64K,低水位是32K,通过以下方式进行设置:

.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 64 * 1024)
.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 32 * 1024)

 

如何解决这个问题?

ChannelOutboundBuffer 的容量过高或过低时都会触发 fireChannelWritabilityChanged 方法,因此可通过重写 channelWritabilityChanged 方法调整消息产生速度。

在常用的中间件里,我们看看它们是如何处理的:

1、Notify 在给订阅组投递消息时,先检查此订阅组的 Channel 是否超过最高位,如果是,则此次不投递,如果不是,继续投递。

2、Flink 核心发送方法中如果 Channel 不可写,则会跳过发送,当 Channel 再次可写后,Netty 会调用该 Handle 的 ChannelWritabilityChanged 方法,从而重新触发发送函数。

3、Duboo 发送请求时,判断是否已经关闭的 Channel,如果是,不再放入连接池,重新申请连接。

总之,在使用 Channel 写数据之前,建议使用 isWritable 方法来判断一下当前 ChannelOutboundBuffer 里的写缓存水位,防止 OOM 发生。

目录
相关文章
|
前端开发 网络协议 Dubbo
超详细Netty入门,看这篇就够了!
本文主要讲述Netty框架的一些特性以及重要组件,希望看完之后能对Netty框架有一个比较直观的感受,希望能帮助读者快速入门Netty,减少一些弯路。
97741 33
超详细Netty入门,看这篇就够了!
|
关系型数据库 MySQL Java
【YashanDB知识库】原生mysql驱动配置连接崖山数据库
【YashanDB知识库】原生mysql驱动配置连接崖山数据库
【YashanDB知识库】原生mysql驱动配置连接崖山数据库
|
网络协议 算法 网络性能优化
第十一问:TCP的窗口机制是什么?
TCP的窗口机制是实现流量控制和拥塞控制的重要手段,主要包括滑动窗口、接收窗口(rwnd)和拥塞窗口(cwnd)。滑动窗口定义了发送方允许发送的数据范围,接收窗口控制接收方的缓冲区容量,拥塞窗口防止网络拥塞。这些窗口通过动态调整,确保数据传输的高效性和可靠性。
|
缓存 监控 负载均衡
一文讲明Hystrix熔断器
这篇文章详细阐述了Hystrix熔断器的原理和应用,解释了分布式系统中服务雪崩的问题,并展示了如何在Spring Cloud框架中使用Hystrix进行熔断和降级处理。
一文讲明Hystrix熔断器
|
SQL 存储 关系型数据库
InnoDB深度剖析:MySQL默认存储引擎的奥秘
InnoDB是MySQL默认存储引擎,以其高性能、高可靠性著称。本文深入解析其核心架构,涵盖内存结构(缓冲池、日志缓冲区)、磁盘结构(表空间、重做日志)、事务机制(ACID实现、锁系统)、索引实现(B+树结构)及后台线程管理,帮助理解其如何支持高并发、保障数据安全,并提供优化实战技巧,助你充分发挥MySQL性能。
|
Java 开发者
使用BigDecimal类进行精确的加、减、乘、除操作,并比较BigDecimal数组元素大小
总结起来,BigDecimal类是Java中一个强大的工具,用于精确控制浮点数运算,避免了传统浮点类型因精度问题可能造成的错误。在需要精确计算的场景中,如金融系统、科学计算等,BigDecimal是首选。通过以上介绍的方法,可以对BigDecimal进行高效稳定的算数操作及大小比较。
1375 12
|
Java Maven
LambdaQueryWrapper的使用
LambdaQueryWrapper的使用
505 6
LambdaQueryWrapper的使用
|
jenkins Shell 持续交付
Jenkins持续集成GitLab项目 GitLab提交分支后触发Jenkis任务 持续集成 CI/CD 超级详细 超多图(二)
Jenkins持续集成GitLab项目 GitLab提交分支后触发Jenkis任务 持续集成 CI/CD 超级详细 超多图(二)
724 0
WK
|
监控 Ubuntu Linux
Linux系统平均负载如何查看?
在Linux系统中,有多种命令可用于查看平均负载,包括实时和历史数据。常用方法有:`uptime`命令显示系统运行时间和平均负载;`top`命令实时监控系统进程和资源使用;`w`命令展示用户信息及负载;通过`cat /proc/loadavg`查看特定文件中的负载信息;`sar`命令提供详尽的系统资源监控;而`htop`则以交互方式展示系统负载和资源使用情况。这些工具帮助用户全面了解系统性能状态。
WK
730 2
|
Oracle Java 关系型数据库
2022 年超详细过程步骤讲解 CentOS 7 安装jdk1.8
这篇文章提供了在CentOS 7系统上安装JDK 1.8的详细步骤,包括卸载系统自带的JDK、下载Oracle官网的JDK安装包、上传至虚拟机、解压安装包、配置环境变量,并验证安装是否成功。
2022 年超详细过程步骤讲解 CentOS 7 安装jdk1.8