一:为什么Netty适合做网络编程?
- 使用简单:封闭了 Java 原生 NIO 类库繁琐的 API,使用起来更加高效;
- 功能强大:预置多种编码能力,支持多种主流协议。同时通过 ChannelHandler 可以进行灵活的拓展,支持很强的定制能力;
- 高性能:与其它业界主流 NIO 框架相比,Netty 综合更优。主要体现在吞吐量更高、延迟更低、减少资源消耗以及最小化不必要的内存复制;
- 社区活跃:版本更新周期短,BUG 修复速度快
二:Netty性能好的原因是什么?
- 非阻塞I0模型:Netty采用了IO多路复用技术,让多个IO的阻塞复用到一个select线程阻塞上,能够有效的应对大量的并发请求
- 高效的Reactor线程模型:支持多种Reactor线程模型,可以根据业务场景的性能诉求,自行选择
- 零拷贝:尽量做到不必要的内存拷贝
- 内存池设计:使用直接内存,并且可重复利用
- 无锁串行化设计:避免使用锁带来的额外开销
- 高性能序列化协议:支持 protobuf 等高性能序列化协议
三:Netty的线程模型是怎么样的?
Netty 的线程模型并不是一成不变的,它实际取决于用户的启动参数配置。通过设置不同的启动参数,Netty支持三种模型,分别是Reactor单线程模型、Reactor多线程模型、Reactor主从多线程模型
- Reactor单线程模型:一个Reactor既负责处理连接请求,又要负责处理读写请求,一般来说处理连接请求是很快的,但是处理具体的读写请求就要涉及字节的复制,相对慢太多了。Reactor正在处理读写请求的时候,其他请求只能等着,只有等处理完了,才可以处理下一个请求。
- Reactor多线程模型:当多个客户端进入服务器后,Reactor线程会监听多种事件,如果监听到连接事件,则把该事件分配给acceptor处理,如果监听到读事件,那么则会发起系统调用,将数据写入内存,之后再把数据交给工作线程池进行业务处理。
这个时候我们会发现,业务处理的逻辑已经变成多线程处理了。不过一个Reactor既要负责连接事件,又要负责读写事件,同时还要负责数据准备的过程。因为拷贝数据是阻塞的,假如说Reactor阻塞到拷贝数据的时候,服务器进来了很多连接,这些连接是很有可能会被服务器拒绝掉的。所以,单个Reactor看来是不够的,我们需要使用多个Reactor来处理。 - Reactor主从多线程模型:在主从Reactor模型中,主Reactor线程只负责连接事件的处理,它把读写事件全部交给了子Reactor线程。这样即使在数据准备阶段子线程被阻塞,主Reactor还是可以处理连接事件。
四:Netty的零拷贝是怎么实现的?
Netty的零拷贝模型和操作系统中的零拷贝模型并不完全一样。他主要指的是不需要将数据buffer从一个内存区域拷贝到另一个内存区域。少了一次内存的拷贝,CPU 效率就得到的提升。
- 直接使用堆外内存,避免 JVM 堆内存到堆外内存的数据拷贝。
- CompositeByteBuf 类,可以组合多个 Buffer 对象合并成一个逻辑上的对象,避免通过传统内存拷贝的方式将几个 Buffer 合并成一个大的 Buffer。
- 通过 Unpooled.wrappedBuffer 可以将 byte 数组包装成 ByteBuf 对象,包装过程中不会产生内存拷贝。
- ByteBuf.slice 可以将一个 ByteBuf 对象切分成多个ByteBuf 对象,切分过程中不会产生内存拷贝,底层共享一个 byte 数组的存储空间。
五:说说 Netty 的对象池技术?
当我们使用Netty编写一个网络应用程序时,可能需要频繁地创建和释放ByteBuf对象来处理输入和输出数据。如果我们每次需要时都创建新的ByteBuf对象,会导致频繁的垃圾回收和内存分配,降低性能。为了避免这种情况,Netty提供了对象池技术,通过对象池来重用ByteBuf对象,从而减少垃圾回收和内存分配
六:Netty的Buffer为什么好用?
在网络编程中,基本都是基于TCP报文的字节流的操作,所以Java的NIO又新增了ByteBuffer,只不过Java 原生的ByteBuffer,非常难操作,也不能扩缩容,所以Netty又重新封装了自己的Bytebuf,除了性能上的优势之外,Netty的Buffer在使用上相对于NIO也非常简洁,有如下特点:
- 动态扩缩容
- 读写指针代替#filp
七:能不能说一说Netty的无锁化设计?
- Netty基于Reactor线程模式实现并发请求处理,避免了线程阻塞与锁的竞争。
- Netty实现了对象池,用来减少对象的创建和销毁,从而也能避免了锁的竞争。
- 在Netty中,还有许多组件都被设计为线程安全的,例如,每个Channel都有一个唯一的EventLoop,用于处理所有事件。这样可以避免锁竞争和线程切换带来的开销。
八:Netty如何解决TCP粘包、拆包的问题的?
- 短链接,发一个包建立一次连接,这样连接建立到连接断开之间就是消息的边界,缺点:半包还是不好解决,因为接收方的缓冲区大小是有限的
- 每一条消息采用固定长度,缺点:数据包的大小不好把握
- 每一条消息采用分隔符,例如 \n,缺点:处理字符数据比较合适,但如果内容本身包含了分隔符,那么就会解析错误
- 每一条消息分为 head 和 body,head 中包含 body 的长度
九:Netty有哪些序列化协议?
- Java原生序列化:Java原生的序列化协议,可以序列化所有实现了Serializable接口的对象。
- JSON序列化:JSON是一种轻量级的数据交换格式
- XML序列化:XML也是一种常用的数据交换格式
- Protobuf序列化:Protobuf是Google开源的一种高效、灵活的二进制序列化协议,具有良好的跨语言能力和高效的序列化性能