1. netty的工作原理
想象一下你正在运营一个非常繁忙的快递公司,你需要处理来自各地的大量包裹投递请求。传统的做法可能是一个工作人员对应一个包裹,从接收、登记到派送全程负责到底,这样当包裹多起来时,就需要雇佣很多工作人员(线程),而且每个工作人员在等待包裹到达或填写信息时都不能处理其他包裹,效率低下。
而在Netty的世界里,你的快递中心是这样运作的:
事件驱动:快递中心设立了一个高效的调度系统(EventLoop),它能够同时监控所有包裹收发点(Socket连接)。当有新的包裹到达或者准备发出时,调度系统会立即收到通知(IO事件)。
异步非阻塞:每个工作人员(EventLoop线程)不再一对一服务包裹,而是能够同时处理多个连接上的读写任务。他们不需一直等待某个操作完成,而是在一个包裹的操作(如扫描条形码)进行中就去处理下一个包裹,通过回调机制或Future机制获取之前操作的结果。
多路复用:就像一位工作人员使用先进的扫描枪可以同时关注多个货架上的动态一样,EventLoop线程通过Java NIO中的Selector能够监听多个网络连接的IO状态,只在有实际数据可读或可写时才执行相应的操作。
责任链模式:包裹的处理过程被拆分为多个步骤(Handler),每个步骤专注于特定的任务(如解包、验证、路由等)。当一个事件发生时,调度系统会调用对应的处理程序来执行这个步骤,形成一个有序的责任链。
2.多Reactor多线程模型
多Reactor多线程模型是一种高性能的网络编程架构,用于处理大量并发连接和IO请求。这个模型的设计理念是将事件驱动机制与多线程技术相结合,充分利用现代多核CPU的优势来提升服务器性能。
想象一个繁忙的餐厅,有多个接待员(相当于主Reactor)在门口接待顾客(客户端连接)。接待员的工作是非阻塞模式的,他们能够同时关注很多个门铃(socket连接请求),当有新的顾客到达时,接待员会迅速将其引导至一张空闲的桌子,并且通知服务员(工作线程)去服务这位新顾客。
在这个模型中:
主Reactor:专门负责监听并接受新的客户端连接请求,一旦有新的连接建立,它会立即分配给某个从属的Reactor。
从属Reactor:每个从属Reactor都运行在一个独立的工作线程中,它们各自管理一部分已经建立好的客户连接,通过I/O多路复用技术(如epoll、kqueue等)监控这些连接上的读写事件。
工作线程池:每一个从属Reactor就像一位能同时关注多个餐桌上动静的服务员,当连接上有数据可读或需要写入数据时,相应的从属Reactor会调度对应的工作线程去执行实际的数据读取、业务逻辑处理以及数据发送操作。
并发能力增强:通过多线程,可以同时处理多个客户端的不同请求,避免了单线程中串行处理导致的延迟。
资源高效利用:每个CPU核心可以被分配到不同的线程上执行任务,实现真正的并行计算,提高系统整体吞吐量。
无阻塞IO:使用非阻塞IO,即使在等待数据的过程中,线程也不会被挂起,而是继续处理其他准备就绪的连接。
3.netty的ByteBuf
在现实生活中,我们用信封来封装和传递纸质信息。同样,在网络通信中,数据也需要被包装起来才能进行传输。Netty的ByteBuf就像是一个高级版本的“数据信封”,专门用来存放二进制数据(字节数据)。
传统的Java NIO中的ByteBuffer虽然也能存储字节,但它在操作上存在一些限制,例如读写位置的管理、容量的调整等不够灵活。而Netty的ByteBuf就像一个定制的多功能邮包:
动态容量:ByteBuf可以根据需要动态调整它的容量,就像邮包可以扩容或缩小一样,更有效地利用内存资源。
多索引设计:ByteBuf有读索引(readerIndex)和写索引(writerIndex),分别指示当前读取和写入的位置,这就好比邮包上有两个标签,一个是已读取信息的位置,另一个是待写入信息的位置,这样我们可以清晰地知道哪些数据已经被处理过,哪些还没有。
零拷贝支持:ByteBuf支持直接内存访问和复合缓冲区,能减少数据在操作系统内核空间与用户空间之间复制的次数,就如同邮政系统优化了内部流程,减少不必要的分拣动作,提高整体投递效率。
丰富的API:ByteBuf提供了丰富的方法来进行数据的读取、写入、切片、回收等各种操作,方便开发者以更低的学习成本和更高的编程效率处理网络通信中的字节流。