netty划重点

1、Netty的线程模型是怎样的?

netty划重点_第1张图片

2、Netty的粘包/拆包是怎么处理的,有哪些实现?

  • 消息定长度,传输的数据大小固定长度,例如每段的长度固定为100字节,如果不够空位补空格
  • 在数据包尾部添加特殊分隔符,比如下划线,中划线等,这种方法简单易行,但选择分隔符的时候一定要注意每条数据的内部一定不能出现分隔符

  • 发送长度:发送每条数据的时候,将数据的长度一并发送,比如可以选择每条数据的前4位是数据的长度,应用层处理时可以根据长度来判断每条数据的开始和结束

Netty提供了多个解码器,可以进行分包的操作,如下:

  • LineBasedFrameDecoder (回车换行分包)
  • DelimiterBasedFrameDecoder(特殊分隔符分包)
  • FixedLengthFrameDecoder(固定长度报文来分包)

3、Netty的protobuf编解码机制是怎样的?

入站消息会被解码,出栈消息会被编码成字节

Netty提供了很多编解码器,比如编解码字符串的StringEncoder和StringDecoder,编解码对象的ObjectEncoder和ObjectDecoder等

如果要实现高效的编解码可以用protobuf,但是protobuf需要维护大量的proto文件比较麻烦,现在一般可以使用protostuff。

protostuff是一个基于protobuf实现的序列化方法,它较于protobuf最明显的好处是,在几乎不损耗性能的情况下做到了不用我们写.proto文件来实现序列化

4、Netty如何实现断线自动重连?

客户端启动连接服务端时,如果网络或服务端有问题,客户端连接失败,可以重连,重连的逻辑加在客户端

5、说下Netty零拷贝的原理?

netty划重点_第2张图片

Netty的接收和发送ByteBuf采用DIRECT BUFFERS,使用堆外直接内存进行Socket读写,不需要进行字节缓冲区的二次拷贝。

如果使用传统的JVM堆内存(HEAP BUFFERS)进行Socket读写,JVM会将堆内存Buffer拷贝一份到直接内存中,然后才能写入Socket中。JVM堆内存的数据是不能直接写入Socket中的。相比于堆外直接内存,消息在发送过程中多了一次缓冲区的内存拷贝。

6、说下Netty如何实现长连接心跳保活机制?

在 TCP 长连接中, 客户端和服务器之间定期发送的一种特殊的数据包, 通知对方自己还在线, 以确保 TCP 连接的有效性

  • IdleStateHandler 将通过 IdleStateEvent 调用 userEventTriggered
  • 如果连接没有接收或发送数据超过60秒钟,则心跳发送到远端
  • 发送的心跳并添加一个侦听器,如果发送操作失败将关闭连接
  • 若事件不是 IdleStateEvent ,就将它传递给下一个处理程序

7、Netty的内存池是怎么实现的?

DirectBuffer和HeapBuffer

其中对应堆内存和直接内存的池化实现分别是PooledHeapByteBuf和PooledDirectByteBuf,在各自的实现中都维护着一个Recycler

8、Netty是如何解决NIO底层epoll空轮询导致CPU 100%的Bug?

若Selector的轮询结果为空,也没有wakeup或新消息处理,则发生空轮询,CPU使用率100%

解决方案:

  • 对Selector的select操作周期进行统计,每完成一次空的select操作进行一次计数
  • 若在某个周期内连续发生N次空轮询,则触发了epoll死循环bug
  • 重建Selector,判断是否是其他线程发起的重建请求,若不是则将原SocketChannel从旧的Selector上去除注册,重新注册到新的Selector上,并将原来的Selector关闭

9、直接内存使用的优缺点?

优点:

  • 不占用堆内存空间,减少了发生GC的可能
  • java虚拟机实现上,本地IO会直接操作直接内存(直接内存=>系统调用=>硬盘/网卡),而非直接内存则需要二次拷贝(堆内存=>直接内存=>系统调用=>硬盘/网卡)

缺点:

  • 初始分配较慢
  • 没有JVM直接帮助管理内存,容易发生内存溢出。为了避免一直没有FULL GC,最终导致直接内存把物理内存耗完。我们可以指定直接内存的最大值,通过-XX:MaxDirectMemorySize来指定,当达到阈值的时候,调用system.gc来进行一次FULL GC,间接把那些没有被使用的直接内存回收掉。

10、ByteBuf扩容机制?

Netty的ByteBuf需要动态扩容来满足需要,扩容过程: 默认门限阈值为4MB(这个阈值是一个经验值,不同场景,可能取值不同),当需要的容量等于门限阈值,使用阈值作为新的缓存区容量 目标容量,如果大于阈值,采用每次步进4MB的方式进行内存扩张((需要扩容值/4MB)*4MB),扩张后需要和最大内存(maxCapacity)进行比较,大于maxCapacity的话就用maxCapacity,否则使用扩容值 目标容量,如果小于阈值,采用倍增的方式,以64(字节)作为基本数值,每次翻倍增长64 -->128 --> 256,直到倍增后的结果大于或等于需要的容量值

10、Netty高并发高性能体现在哪些方面?

  • 主从Reactor线程模型
  • NIO多路复用非阻塞
  • 无锁串行化设计思想:在IO线程内部进行串行操作,避免多线程竞争导致的性能下降
  • 支持高性能序列化协议
  • 零拷贝(直接内存的使用)
  • ByteBuf内存池设计
  • 灵活的TCP参数配置能力:Netty在启动辅助类ChannelOption中可以灵活的配置TCP参数,满足不同的用户场景
  • 并发优化:volatile的大量、正确使用;CAS和原子类的广泛使用;线程安全容器的使用;通过读写锁提升并发性能。

 

你可能感兴趣的:(Netty,netty)