问:BIO、NIO和AIO的区别
答:1)BIO:一个连接一个线程,客户端有连接请求时服务器端就需要启动一个线程进行处理,线程开销大伪异步IO:将请求连接放入线程池,一对多,但线程还是很宝贵的资源
2)NIO:一个请求一个线程,但客户端发送的连接请求都会注册到多路复用器上多路复用器轮询到连接有I/O请求时才启动一个线程进行处理
3)AIO:一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理BIO是面向流的,NIO是面向缓冲区的,BIO的各种流是阻塞的
而NIO是非阻塞的,BIO的Stream是单向的,而NIO的channel是双向的
问:Reactor模型
答:在Reactor模式中,事件分发器等待某个事件或者可应用或个操作的状态发生事件分发器就把这个事件传给事先注册的事件处理函数或者回调函数,
由后者来做实际的读写操作如在Reactor中实现读:注册读就绪事件和相应的事件处理器、事件分发器等待事件、事件到来激活分发器,分发器调
用事件对应的处理器、事件处理器完成实际的读操作处理读到的数据,注册新的事件,然后返还控制权
问:NIO的组成
答:Buffer,Channel,Selector
问:Netty的特点
答:一个高性能、异步事件驱动的NIO框架,它提供了对TCP、UDP和文件传输的支持使用更高效的socket底层,对epoll空轮询引起的cpu占用飙升在内部
进行了处理避免了直接使用NIO的陷阱,简化了NIO的处理方式。采用多种decoder/encoder支持,对TCP粘包/分包进行自动化处理可使用接受/处理线
程池,提高连接效率,对重连,心跳检测的简单支持可配置IO线程数、TCP参数,TCP接收和发送缓冲区使用直接内存代替堆内存通过引用计数器及时申
请释放不再引用的对象,降低了GC频率使用单线程串行化的方式,高效的Reactor线程模型大量使用了volitale使用了CAS和原子类、线程安全类的使
用、读写锁的使用。
问:Netty的线程模型
答:Netty通过Reactor模型基于多路复用器接收并处理用户请求内部实现了两个线程池,boss线程池和work线程池其中boss线程池的线程负责处理请求
的accept事件当接收到accept事件的请求时把对应的socket封装到一个NioSocketChannel中并交给work线程池,其中work线程池负责请求的read和
write事件,由对应的Handler处理。单线程模型:所有I/O操作都由一个线程完成,即多路复用、事件分发和处理都是在一个Reactor线程上完成的
既要接收客户端的连接请求,向服务端发起连接,又要发送/读取请求或应答/响应消息一个NIO 线程同时处理成百上千的链路,性能上无法支撑,速
度慢,若线程进入死循环,整个程序不可用对于高负载、大并发的应用场景不合适多线程模型:有一个NIO 线程(Acceptor)只负责监听服务端接收
客户端的TCP连接请求;NIO 线程池负责网络IO 的操作,即消息的读取、解码、编码和发送1个NIO线程可以同时处理N条链路,但是1个链路只对应1
个NIO线程这是为了防止发生并发操作问题但在并发百万客户端连接或需要安全认证时,一个Acceptor 线程可能会存在性能不足问题。主从多线程
模型:Acceptor 线程用于绑定监听端口,接收客户端连接,将SocketChannel从主线程池的Reactor线程的多路复用器上移除,重新注册到Sub 线程
池的线程上,用于处理I/O 的读写等操作从而保证mainReactor只负责接入认证、握手等操作。
问:TCP粘包/拆包的原因及解决方法
答:1)TCP是以流的方式来处理数据一个完整的包可能会被TCP拆分成多个包进行发送也可能把小的封装成一个大的数据包发送
2)TCP粘包/分包的原因:应用程序写入的字节大小大于套接字发送缓冲区的大小,会发生拆包现象而应用程序写入数据小于套接字缓冲区大小
网卡将应用多次写入的数据发送到网络上这将会发生粘包现象
3)解决方法消息定长:FixedLengthFrameDecoder类包尾增加特殊字符分割:行分隔符类:LineBasedFrameDecoder或自定义分隔符类:
DelimiterBasedFrameDecoder将消息分为消息头和消息体:LengthFieldBasedFrameDecoder类分为有头部的拆包与粘包、长度字段在前且有
头部的拆包与粘包、多扩展头部的拆包与粘包。
问:了解哪几种序列化协议
答:Java默认提供的序列化,XML,JSON,Fastjson,Thrift,Avro,Protobuf
问:Netty的零拷贝实现
答:Netty的接收和发送ByteBuffer采用DIRECT BUFFERS,使用堆外直接内存进行Socket读写,不需要进行字节缓冲区的二次拷贝,堆内存多了一次内存拷贝
JVM会将堆内存Buffer拷贝一份到直接内存中,然后才写入Socket中。
问:Netty的高性能表现在哪些方面
答:1)心跳
对服务端会定时清除闲置会话inactive(netty5)
对客户端用来检测会话是否断开,是否重来,检测网络延迟
2)串行无锁化设计
即消息的处理尽可能在同一个线程内完成
期间不进行线程切换这样就避免了多线程竞争和同步锁
3)可靠性链路有效性检测
链路空闲检测机制,读/写空闲超时机制
4)内存保护机制
通过内存池重用ByteBuf;ByteBuf的解码保护
5)优雅停机
不再接收新消息、退出前的预处理操作、资源的释放操作。
6)Netty安全性
支持的安全协议SSL V2和V3,TLS,SSL单向认证、双向认证和第三方CA认证
7)高效并发编程的体现
volatile的大量、正确使用
CAS和原子类的广泛使用
线程安全容器的使用
通过读写锁提升并发性能
IO通信性能三原则:传输AIO,协议Http,线程主从多线程
8)流量整型的作用
防止由于上下游网元性能不均衡导致下游网元被压垮,业务流中断
防止由于通信模块接受消息过快,后端业务线程处理不及时导致撑死问题
9)TCP参数配置:
SO_RCVBUF和SO_SNDBUF:通常建议值为128K或者256K
SO_TCPNODELAY:NAGLE算法通过将缓冲区内的小封包自动相连组成较大的封包