目录
(事件循环,工人)(默认内部eventloop个数是cpu线程数*2)执行任务,io事件
2:netty的ByteBuf和nio的ByteBuffer的区别:
一,Netty重要组件:
1:eventloop
(事件循环,工人)(默认内部eventloop个数是cpu线程数*2)执行任务,io事件
2:eventloopgroup(事件循环组)
3:channel(通道)
4:pipeline(管道,工序)
5:handler(每道工序)
6:Bytebuf(区别于nio的Bytebuffer)
Netty4的ByteBuf分为池化的和非池化的,池化的优点包含如下两点:
- 对于DirectByteBuffer的分配和释放是比较低效的,使用池化技术能快速分配内存。
- 池化技术使对象可以复用,从而降低gc频率。
- 默认是开启的池化。
- Bytebuf:可以选择直接内存或者堆内存,直接内存分配效率低但是读写效率高,减少了一次拷贝,因为从系统内存缓冲区到Java内存中。堆内存 分配效率高但是读写效率低 因为频繁gc 会导致数据复制 搬迁。因此 直接内存适合和池化搭配使用。(Netty4.X提供了基于内存池的缓冲区重用机制。性能测试表明,采用内存池的ByteBuf相比于朝生夕灭的ByteBuf,性能高23倍左右(性能数据与使用场景强相关)。)
- 垃圾回收 :引用计数 release 减一 retain加一
注:同一个客户端channel和同一个eventloop绑定,但是如果handler耗时 可以交给DefaultEventloopGroup内的eventloop线程去处理
二,netty的优点:
(1):reactor线程模型支持高并发,海量连接。
(2):异步事件驱动,提高性能。
(3):自带编解码器解决Tcp拆包粘包问题。
(4):串行化处理读写。
(串行化处理读写 :避免使用锁带来的性能开销。即消息的处理尽可能再同一个线程内完成,期间不进行线程切换,这样就避免了多线程竞争和同步锁。表面上看,串行化设计似乎CPU利用率不高,并发程度不够。但是,通过调整NIO线程池的线程参数,可以同时启动多个串行化的线程并行运行,这种局部无锁化的串行线程设计相比一个队里-多个工作线程模型性能更优。)
(5):内存零拷贝 :
尽量减少不必要的内存拷贝,实现了更高效率的传输。
(Netty的接收和发送ByteBuffer采用DIRECT BUFFERS,使用堆外直接内存进行Socket读写,不需要进行字节缓冲区的二次拷贝。如果使用传统的堆内存(HEAP BUFFERS)进行Socket读写,JVM会将堆内存Buffer拷贝一份到直接内存中,然后才写入Socket中。相比于堆外直接内存,消息在发送过程中多了一次缓冲区的内存拷贝。)
三 ,netty的io模型vs BIO:
四 ,netty的线程模型:
netty线程模型主要是基于reactor实现。
基于reactor可以实现3种线程模型:reactor单线程模型,reactor多线程模型、主从reactor多线程模型
在使用时主要是靠NioEventLoopGroup来实现上诉的3种线程模型
一般使用netty实现服务端时,一般会初始化两个线程组:
bossEventLoopGroup:监听接受客户端连接
workEventLoopGroup:负责具体的IO事件,交由handler处理
4.1 reactor单线程模型
一个线程需要处理所有的accept、recieve、decode、procces、encode、send事件。对于高负载、高并发、并且性能要求比较高的系统并不适用
4.2 reactor多线程模型
主线程仍然负责accept、recieve、send等事件,将业务的处理派由一个线程池去处理。高并发时也会出现性能瓶颈
4.3 主从reactor多线程模型
主reactor线程监听accept事件,并派发给从reactor线程,从reactor负责监听IO的recieve、send事件,并且将监听到的事件交由从reactor线程池处理业务
五 ,面试常见问题:
0:为什么不用AIO而是NIO?
- Netty不看重Windows上的使用,在Linux系统上,AIO的底层实现仍使用EPOLL,没有很好实现AIO,因此在性能上没有明显的优势,而且被JDK封装了一层不容易深度优化。
- Linux上AIO不够成熟,处理回调结果速度跟不上处理需求,比如外卖员太少(reactor),顾客太多(请求),供不应求,造成处理速度有瓶颈(待验证)。
1:为什么netty使用异步处理读写事件?
答:通过服务器的吞吐量,而不是多线程就一定效率高!
2:netty3和netty4的区别?答:
(1)我们知道当系统在运行过程中,如果频繁的进行线程上下文切换,会带来额外的性能损耗。多线程并发执行某个业务流程,业务开发者还需要时刻对线程安全保持警惕,哪些数据可能会被并发修改,如何保护?这不仅降低了开发效率,也会带来额外的性能损耗。为了解决上述问题,Netty 4采用了串行化设计理念,从消息的读取、编码以及后续Handler的执行,始终都由I/O线程NioEventLoop负责,这就意外着整个流程不会进行线程上下文的切换,数据也不会面临被并发修改的风险,对于用户而言,甚至不需要了解Netty的线程细节,这确实是个非常好的设计理念,
(2)随着JVM虚拟机和JIT即时编译技术的发展,对象的分配和回收是个非常轻量级的工作。但是对于缓冲区Buffer,情况却稍有不同,特别是对于堆外直接内存的分配和回收,是一件耗时的操作。为了尽量重用缓冲区,Netty4.X提供了基于内存池的缓冲区重用机制。性能测试表明,采用内存池的ByteBuf相比于朝生夕灭的ByteBuf,性能高23倍左右。
2:netty的ByteBuf和nio的ByteBuffer的区别:
ByteBuf容量可以自动扩容的(当数据大小大于初始容量(256)大小 就会自动扩容(翻倍))而ByteBuffer不能。