抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

摘要

本文整理了同步/异步、阻塞/非阻塞、IO、BIO/NIO 等前置概念,并用类比帮助快速理解 Netty 的核心组件与工作机制。

前置概念

同步和异步

同步:多个事物不能同时进行
异步:多个事物可以同时进行

阻塞和非阻塞

阻塞:遇到障碍从而无法继续运行,等待是阻塞的副作用,等待指的是等待某些相关事物,而不是整个线程都在等待。
非阻塞:没有障碍畅行无阻

同步/异步:指的是能不能同时进行
阻塞/非阻塞:指的是能不能进行

同步阻塞:不能同时进行且等待,相当于单线程等待

同步非阻塞:单线程运行

异步阻塞:同时进行且等待,相当于多线程都在等待

异步非阻塞:同时进行且正常运行,相当于多线程运行

IO

IO指的是读/写数据的过程,和等待读入/写出的过程。一旦拿到数据就变成数据操作了,不是IO。
拿网络IO举例子:等待的过程就是数据从网络到网卡再到内核空间,读写的过程就是内核空间和用户空间相互拷贝。

Netty IO示意图

阻塞IO和非阻塞IO

应用程序都是运行在用户空间的,数据没有到用户空间时应用程序是操作不了的。
阻塞IO:数据没有到达用户空间时,用户线程会阻塞并等待
非阻塞IO:不阻塞用户线程,而是数据到达后才通知用户线程

同步IO和同步阻塞IO

同步IO:发起请求的IO线程,必须等待IO操作完成后才能继续执行该线程的后续代码
有一点需要注意:在等待数据的过程中,线程采用死循环的方式轮询,在读写数据的过程中,线程在堵塞,这依然是同步阻塞IO。
所以,同步IO就是同步阻塞IO

异步IO和异步非阻塞IO

异步IO:发起IO请求的线程无需等待IO完成仍可继续运行
只有异步非阻塞IO

BIO

阻塞IO(Blocking IO)
一个线程管理一个连接

NIO

非阻塞IO(New IO)
单线程可以管理大量连接

一段简单的类比

想象一个很大的快递中心:

1
2
3
4
5
Socket/连接 = 每个包裹的收发窗口(channel)
Eventloop = 一个工作人员(单线程),负责检查窗口有没有新的包裹以及处理包裹(IO事件)
Eventloop Group = 工作人员的队伍(线程池), 有的负责接收新客户( boss 线程),有的负责处理包裹(worker 线程)
Pipeline = 处理流程的传送带, 包裹依次经过打包、分拣、编码、发货
ByteBuf = 专用的 可复用的搬运箱,比普通箱子更灵活

Netty 将网络编程的复杂性,全都封装到这些角色里面,开发者只需要专注写“处理逻辑”,即收到包裹后需要做什么。
最重要的一点就是:一个线程监听多个channel,一个channel 只属于一个线程

核心组件

channel:

  • 表示一个IO对象,比如一条TCP连接

Eventloop & Eventloop Group

  • Eventloop : 单线程+selector 循环。一个Eventloop(线程)管理一组channel的IO事件并执行对应的handler
  • Eventloop Group:一组Eventloop。常见 bossGroup (accept,即接收连接) 和 workerGroup(读写)
什么是selector?

其实就相当于一个叫号系统,哪个桌子有事件,屏幕就响起对应号码。

  1. 调用select阻塞等待事件
  2. 有事件后遍历处理
  3. 执行普通任务
  4. 再次select
    selector带来了多路复用,一个线程处理大量连接,避免线程上下文切换,事件驱动,无需轮询。
    总结
    selector是NIO中的多路复用器,使得一个线程同时监听多个Channel的就绪状态。允许一个线程管理大量连接,通过select返回所有就绪事件,从而实现多路复用。

为什么要分boss 和 worker?

首先类比一下:
想象你开了一家餐厅
进门接待员 = boss,负责安排客人进门、座位
服务员 = worker, 负责点单、上菜
如果你让一个人同时:接待、点菜、送菜
一旦桌子很多,新的连接无法建立,系统会卡死

网络事件分两类:
一是建立连接,属于轻量操作;二是处理业务IO(read/write),属于重量操作;如果让一个线程组去处理者两个业务,会导致accept被阻塞,无法接受新的连接,导致服务器吞吐量急剧下降。

ChannelPipeline & ChannelHandler

  • Pipeline:每个 Channel 有一个 pipeline(责任链),把入站/出站事件串联处理。
  • Handler : 实现具体逻辑(编码/解码/业务)。分入站(Inbound)和出站(Outbound)。

ByteBuf

  • Netty自己的缓冲区

Channel Future

  • 承载绑定端口的的异步执行状态:成功、失败等,阻塞当前线程直到绑定成功

总结

Netty就是用事件驱动 + 单线程监听循环 + 高效的内存管理 + 可组合的Pipeline, 把高并发网络编的复杂性封装起来,用极少的线程处理海量的连接。

评论