Netty的编码与解码
- 编解码:出站消息会把Java对象转换成字节,入站消息则将字节转成Java对象
- Netty内部提供了一系列内置编解码API
- 如StringEncoder和StringDecoder和编解码对象的ObjectEncoder和ObjectDecoder
- 如果要实现高效的编解码可以用protobuf
- protobuf要维护大量proto文件,比较麻烦,一般可以使用protostuff,使用简单
Netty粘包拆包
- TCP是一个流协议,就是没有界限的一长串二进制数据
- TCP作为传输层协议并不不了解上层业务数据的具体含义
- 务上认为是一个完整的包,可能会被TCP拆分成多个包进行发送
- 也有可能把多个小的包封装成一个大的数据包发送
- 以上描述的就是粘包和拆包,如何解决?
- 消息定长,不够补空位;有点浪费
- 消息数据包尾部添加特殊结束符;简单,但要保证内容不能出现特殊符号
- 发送数据时,将数据长度一并发送出去;
- Netty内置有3种编码器支持分包操作
- LineBasedFrameDecoder(回车换行分包)
- DelimiterBasedFrameDecoder(特殊分隔符分包)
- FixedLengthFrameDecoder(固定长度报文来分包)
- 也可自定义
Netty心跳检测机制
- 客户端和服务器之间定期发送的一种特殊的数据包,通知对方自己还在线
- Netty中实现心跳机制的关键是 IdleStateHandler
断线重连
- 网络出现问题,客户端需要支持重连机制
- 客户端断开连接后可感知到,并通过Handler的channelInactive方法进行重连
Netty高并发高性能架构设计精髓
-
主从Reactor线程模型
-
NIO多路复用非阻塞
-
无锁串行化思想
- 消息的处理尽可能在同一个线程内完成
- 避免了多线程操作导致的锁的竞争
- NIO的多路复用就是一种无锁串行化的设计思想
-
高性能的序列化协议
-
零拷贝,使用直接内存
- 直接内存并不是虚拟机运行时数据区的一部分
- 也不是Java虚拟机规范中定义的内存区域
- java里用DirectByteBuffer可以分配一块直接内存(堆外内存)
- 元空间对应的内存也叫作直接内存,它们对应的都是机器的物理内存
- 直接内存申请较慢,但访问效率高
- 零拷贝:直接内存=>系统调用=>硬盘/网卡
- 二次拷贝:堆内存=>直接内存=>系统调用=>硬盘/网卡
- 优点:不占用堆内存空间,减少了发生GC的可能,访问效率高
- 缺点:初始分配慢,没有JVM直接管理内存,容易发生内存溢出
- 通过-XX:MaxDirectMemorySize来指定阈值,达到阈值后会触发FULLGC回收内存
- 零拷贝:使用堆外直接内存进行Socket读写,不需要进行字节缓冲区的二次拷贝
-
ByteBuf内存池设计
- Netty提供了基于ByteBuf内存池的缓冲区重用机制
- 需要的时候直接从池子里获取ByteBuf使用即可
- 使用完毕之后就重新放回到池子里去
-
灵活的TCP参数配置能力
- 根据实例业务情况,合理设置TCP参数,可有效提升性能
- 比如设置:发送缓冲区和接收缓冲区