公众号|松华说|Netty源码探究之理论篇
  • 分享在京东工作的技术感悟,还有JAVA技术和业内最佳实践,大部分都是务实的、能看懂的、可复现的

扫一扫
关注公众号

Netty源码探究之理论篇

博客首页文章列表 松花皮蛋me 2020-02-29 13:51

一、经典的三种I/O模式


三种模式包括阻塞BIO(类似排队打饭)、非阻塞NIO(点菜)、异步AIO(包厢)。


注:要明确阻塞与非阻塞、同步与异步的区别。


延展:为什么删掉已经做好的AIO支持?什么是水平触发和边缘触发?NIO一定优于BIO嘛?


二、Netty是怎么切换IO模式的


延展:服务端切换模式后,为什么客户端不需要进行切换?


三、Netty如何支持三种Reactor


Reactor是一种开发模式,模式的核心流程是注册感兴趣的事件-》扫描是否有感兴趣的事件发生-》事件发生后做出相应的处理。


三种Reactor版本包括Reactor单线程模式、非主从Reactory多线程模式、主从Reactor多线程模式。有点类似“一个包揽所有”、“多招几个伙计”、“进一步分工”的工作模式。


源码分析:SelectorProvider


三、Netty是如何处理TCP粘包、半包的


一个发送可能可能被多次接收,多个发送可能被一次接收,而且,一个发送可能占用多个传输包,多个发送可能仅用一个传输包。背后原因是SOCK缓存区大小限制、接收方数据处理能力限制、协议MTU大小限制。


粘包、半包处理方式也就是如何寻找消息边界方式,包括改用短连接、固定长度、分割符、内容中保存长度信息。


Netty对三种常用封桢支持有FixedLengthFrameDecoder、DelimiterBasedFrameDecoder、LengthFieldBasedFrameDecoder。


注:UDP没有粘包和半包问题


源码分析:ByteToMessageDecoder#channelRead


四、常用的”二次”编解码


一次解码的结果是字节,需要转化成项目中能用的对象。


源码分析:MessageToMessageDecoder


五、keepalive与idle监测


不需要keepalive的场景:连接已坏,但是还浪费资源维持,下次直接用会直接报错。
需要keepalive的场景:对端异常”崩溃”、对端在但是处理不过来、对端在但是不可达。


设计keepalive需要考虑哪些?问题出现概率小,没有必要频繁探测。判断需”谨慎”(比如连续多少次),不能武断。


idle监测是为了减少keepalive次数的,也就是无数据传输超过一定时间后,没有读写意图,就判断为idle,然后发keepalive消息。而不是无数据传输就发keepalive消息。


注:这里说的keepalive和HTTP应用层的Connection:keep-alive长链接是不一样的。


六、Netty的那些”锁”事

(1)、在意锁的对象和范围,减少粒度。

(2)、注意锁的对象本身大小,减少空间占用。比如ChannelOutBoundBuffer中使用两个对象代替AtomicLong对象。

(3)、注意锁的速度,提高并发性。比如PlatformDependent中的代码,及时衡量和使用JDK最新的代码。

(4)、不同场景选择不同的并发包。

(5)、衡量好锁的价值,能不用则不用。


Netty使用一个队列和多个线程模式,保证了局部串行、整体并行。

七、Netty如何玩转内存使用

  • (1)、减少对象本身大小。能用基本类型就不要用包装类,应该定义为类变量的不要定义为实例变量。
  • (2)、对分配内存进行预估。可以提前算好初始size或者直接使用。
  • (3)、Zero-Copy。使用逻辑组合或者包装,代替实际复制。或者直接调用JDK底层的file#transferTo。
  • (4)、堆外内存。
  • (5)、内存池、对象池。比如io.netty.util.Recycler。


源码分析:DefaultChannelConfig、Recycler、PooledDirectByteBuf、PooledByteBuf、PooledByteBufAllocator