Netty — 性能优化与实战
📋 本文节选自《Netty 面试题》,返回 查看全部章节
34. ChannelPromise
继承ChannelFuture,进一步扩展用于设置 IO 操作的结果
35. 编解码
java序列化/反序列化,url编解码,base64编解码java自带序列化的缺点:
1、 无法跨语言;
2、 序列化后的码流太大,数据包太大;
3、 序列化和反序列化性能比较差;
业界其他编解码框架:PB,Thrift,Marshalling,KyroNetty里面的编解码:
- 解码器:主要负责处理入站 InboundHandler
- 编码器: 主要负责处理出站 OutBoundHandler Netty默认编解码器,也支持自定义编解码器 Encoder(编码器),Decoder(解码器),Codec(编解码器)
36. Netty解码器 Decoder
Decoder对应 ChannelInboundHandler,主要就是字节数组转换成消息对象方法:
- decode :常用
- decodeLast: 用于最后的几个字节处理,也就是 cahnnel 关闭的时候,产生的最后一个消息 解码器:
- ByteToMessageDecoder 用于将字节转为消息,需要检查缓冲区是否有足够的字节
- ReplayingDecoder 继承ByteToMessageDecoder,不需要检查缓冲区是否有足够多的数据,速度略慢于 ByteToMessageDecoder
- MessageToMessageDecoder 用于将一种消息解码到另外一种消息(例如 POJO 到 POJO) 常用的解码器:(主要解决 TCP 底层的粘包和拆包问题)
- DelimiterBasedFrameDecoder:执行消息分隔符的解码器
- LineBasedFrameDecoder:以换行符为结束标志的解码器
- FixedLengthFrameDecoder:固定长度的解码器
- LengthFieldBasedFrameDecoder: message = header + body,基于长度解码的通用解码器
- StringDecoder:文本解码器,将接收到的消息转为字符串,一般会与上面的几种进行组合,然后再 后面加业务的 handler
37. Netty 编码器 Encoder
Encoder 对应就是 ChannelOutboundHandler ,消息对象转换成字节数组编码器:
- MessageToByteEncoder 消息转为字节数组,调用 write方法,会先判断当前编码器是否支持需要发送的消息类型,如果不 支持,则透传
- MessageToMessageEncoder 从一种消息编码为另外一种消息
38. Netty 组合编解码器 Codec
优点:成对出现,编解码都是在一个类里完成缺点:耦合,扩展性不佳
- ByteToMessageCodec
- MessageToMessageCode
39. TCP 粘包,拆包
![ ][nbsp 9]
TCP拆包:一个完整的包可能被 TCP 拆分成多个包进行发送TCP 粘包:把多个小的包封装成一个大的数据包发送,client发送的若干数据包, server接收时粘在一个包发送方和接收方都可能出现这个原因发送方的原因:TCP 默认会使用 Nagle算法接收方的原因:TCP 接收到数据放置缓存中,应用程序从缓存中读取比较慢UDP 无粘包、拆包问题,有边界协议
40. TCP 半包读写解决方案
发送方:关闭 Nagle 算法接收方:TCP 是无界的数据流,并没有处理粘包现象的机制,且协议本身无法避免粘包,半包读写的发生需要在应用层进行处理应用层解决半包读写方法:
1、 设置定长消息(10个字符);abcdefgh11abcdefgh11abcdefgh11
2、 设置消息边界(?切割);dfdsfdsfdf?dsfsdfdsf$dsfdsfsdf
3、 使用带消息头的协议,消息头存储消息开始标识及消息的长度信息;header + body
41. Netty 自带解决 TCP 半包读写方案
DelimiterBasedFrameDecoder:指定消息分隔符的解码器LineBasedFrameDecoder:以换行符为结束标志的解码器FixedLengthFrameDecoder:固定长度解码器LengthFieldBasedFrameDecoder : message = header + body ,基于长度解码的通用解码器
42. 实战半包读写
LineBasedFrameDecoder:以换行符为结束标志的解码器StringDecoder 解码器将对象转成字符串
43. 自定义分隔符解决 TCP 读写问题
DelimiterBasedFrameDecodermaxLength: 表示一行最大的长度,超过长度依然没检测自定义分隔符,抛出TooLongFrameExceptionfailFast: 如果为true,则超过 maxLength后立即抛出TooLongFrameException,不进行继续解码,如果为 false,则等到完整消息被解码后,再抛出TooLongFrameExceptionstripDelimiter:解码后的消息是否去除分隔符delimiters:分隔符,ByteBuf类型
44. 自定义长度半包读写器 LengthFieldBasedFrameDecoder
maxFrameLength 数据包最大长度lengthFieldOffset 长度字段的偏移量,长度字段开始的地方(跳过指定长度个字节之后的才是消息体字段)lengthFieldLength 长度字段占的字节数,帧数据长度的字段本身的长度lengthAdjustment一般 Header + Body ,添加到长度字段的补偿值,如果为负数,开发人员认为这个Header的长度字段是整个消息包的长度,,则Netty应该减去对应的数字initialBytesToStrip从解码帧中第一次去除的字节数,获取完一个完整的数据包之后,忽略前面的指定位数的长度字节,应用解码器拿到的就是不带长度域的数据包
45. ByteBuf
![ ][nbsp 10]
字节容器,
- JDK 中原生 ByteBuffer 读和写公用一个索引,每次换操作都需要Flip() 扩容麻烦,而且扩容后容易造成浪费
- Netty ByteBuf 读写使用不同的索引,所以操作便捷 自动扩容,便捷
46. ByteBuf 创建方法与常见的模式
ByteBuf:传递字节数据的容器ByteBuf的创建方法:
1、 ByteBufAllocator;Netty 4.x之后默认使用池化(PooledByteBufAllocator)提高性能,最大程度减少内存碎片非池化:UnPooledByteBufAllocator 每次返回一个新的实例
2、 Unpooled:提供静态方法创建未池化的ByteBuf,可以创建堆内存和直接内存缓冲区;ByteBuf使用模式:
3、 堆缓存区;优点:heap buffer 存储在 jvm的堆空间中,快速的分配和释放缺点:每次使用前会拷贝到直接缓存区 (堆外内存)
4、 直接缓存区;Direct buffer优点:不用占用 JVM 的堆内存,存储在堆外内存缺点:内存的分配和释放,比在堆缓存区更复杂
5、 复合缓冲区;创建多个不同的 ByteBuf,然后放在一起,但是只是一个视图选择:大量 IO 数据读写,用直接缓存区,业务消息编解码用堆缓存区
47. Netty 设计模式
Builder 构造器模式:ServerBootstrap责任链设计模式:pipeline的事件传播工厂模式:创建 channel适配器模式:HandlerAdapter
48. Netty 单机百万实战
1、 网络IO模型;
2、 Linux文件描述符;单进程文件描述符(句柄数),每个进程都有最大的文件描述符限制全局文件句柄数,也有默认值,不同系统版本会不一样
3、 如何确定唯一TCP连接;TCP 四元组:源 IP,源端口,目标 IP,目标端口服务端端口范围(1024~65535)
![ ][nbsp 11]
65545优化:
4、 sudovim/etc/security/limits.conf修改局部fd数目,修改后要重启,ulimit-n查看当前这个用;户每个进程最大 FD 数
root soft nofile 1000000
root hard nofile 1000000
* soft nofile 1000000
* hard nofile 10000001、 sudovim/etc/sysctl.conf修改全局fd数目;
fs.file-max=1000000sysctl -p 重启生效参数cat /proc/sys/fs/file-max 查看全局fd数目
1、 重启生效reboot;
-Xms5g -Xmx5g -XX:NewSize=3g -XX:MaxNewSize=3g49. 数据链路
浏览器同域名下资源加载有并发数限制,建议不同资源用不同域名输入域名-》浏览器内核调度-》本地DNS解析-》远程 DNS解析-》IP-》路由多层跳转-》目的服务器-》服务器内核-》应用程序
为了帮助更多的粉丝朋友,找到个好工作,多拿几个offer。苏三最近建一些工作内推群,群里目前已经收集了很多内推岗位,大厂、中厂、小厂、外包都有。欢迎HR、开发、测试、运维和产品加入。

扫描下方微信,备注:网站+所在城市,即可拉你进工作内推群。
