Netty高并发下数据丢失问题与性能优化配置

Netty高并发下数据丢失问题与性能优化配置,第1张

Netty高并发下数据丢失问题与性能优化配置 一、Netty高并发下数据丢失问题分析处理

1、现象

客户端与服务端采用长连接通讯, 传输数据量不大情况下不会出现数据丢失,在大数据量高并发场景下,会出现极少数的数据丢失,存在偶发性。 仔细分析代码处理逻辑,并无问题,查看netty的配置以及编解码处理, 也没有问题。

2、定位

数据丢失可能在传输任何环节都会出现, 需要定位缩小排查范围。 在服务端整个流转环节上都加上日志: 解码器->数据接收->业务逻辑处理->数据发送->编码器,发现数据接收的数量与客户端发送的数量一致, 业务逻辑处理数与数据发送都一致,但编码器的编码数量不一致, 存在缺失。

3、分析

问题范围已经明确,需要知道什么原因导致发送与编码的数量不一致, 增加发送回调处理,监听失败异常:

发现报出堆外内存超出限制的异常:

这里堆外内存的大小和JVM设置的Xmx大小一致, 都为16G。说明发送数据量过大, 产生严重的堆积阻塞。检查代码,因为是查询hbase的历史数据,返回发送的数据量确实会很大,那么该如何处理? 很直接的方法,是直接增加内存, 但数据量如果再增长, 这种方式就很被动。 结合业务场景来看, 并不需要很强的实时性,那么可以在发送前做个检查判断, 如果水位线过高, 阻塞等待, 直到水位降低,再进行发送, 这样就不会导致积压过多消息, 由于内存不足而产生数据丢失的问题。 这种方式会降低性能吗? 如果网络没有瓶颈且接收端处理速度足够快,是不会产生影响。

4、解决

改造之前需要先了解Netty的高低水控制作用,ChannelOutboundBuffer 提供了高低水位线的配置,当buffer缓冲区大小超过高水位时,该Channel的isWritable状态为false变成不可发送; 当buffer缓冲区低于低水位线时,isWritable又会变回true,可以重新发送数据。 那么高低水位线该如何配置? 在Netty服务端初始化的时候进行配置:

接下来改造发送代码, 增加阻塞等待:

这样改造貌似没有问题, 但其实隐藏一个很大的坑, 如果客户端异常断开, 那么该channel会一直处于不可写的状态,占用服务端的处理线程,如果大量客户端中断,整个服务就会不可用,甚至造成崩溃的风险, 进一步改造:

增加channel的有效性判断,同时设定最大等待上限, 每次阻塞100毫秒, 总计30秒的等待时间,实际根据业务场景进行设定, 对于我们业务来讲,时间是足够。至此,服务端发送数据丢失的问题, 就已经成功解决。

二、Netty服务端性能优化配置

1、场景

适用大数据量,请求交互频繁的场景, 采用自定义的二进制数据结构进行传输。

2、服务端配置

1) 基础配置

bossGroup与workGroup如果没有特殊需要, 可以按默认配置。 TCP/IP 第三次握手的请求队列最大长度, 如果在TCP连接上没有丢包与阻塞, 不需要设置过大。

2) 高低水位与缓冲区设置


此配置可以支撑5~10M/S的数据处理, 如有更大数据量,可以适当调高些,但不能设置过大。

3)编解码等其他配置


为防止粘包/拆包问题,采用LengthFieldbasedframeDecoder解码器, 偏移量根据自定义二进制数据结构进行设置。

3、编码与解码配置

1)编码配置

通过MessageToByteEncoder进行编码,为减少内存空间占用, 及时释放回收,可以将相关引用都设为null。

2) 解码配置

通过ByteToMessageDecoder进行解码, 最后调用discardReadBytes()方法,及时释放空间,减少内存占用。

4、业务处理异步化

Netty虽然有较高的性能, 但业务逻辑如果单线程处理, 仍可能出现阻塞,这时候开启采用线程池做业务逻辑处理, 保障性能最大化。

1)线程池定义:

2)线程池拒绝handler处理

这里是直接拒绝, 如果不想返回失败, 也阻塞, 等待重新加入线程池处理。

3) 在handle进行调用处理

业务逻辑异步处理完成之后,再通过DataHander中传入的ctxl通道上下文进行数据发送。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5715535.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存