相对于读操作而言,Netty在处理写操作上更复杂一些.在之前的文章我们介绍了Netty空闲检测之读空闲,为了介绍Netty空闲检测之写空闲,我们有必要对Netty的写操作做一个整体上的介绍.有助于我们接下来介绍写空闲.

在之前的文章我们也说过,在Netty中有两类线程,一类是IO线程,负责读写操作,一类是业务线程,就是处理业务的线程.我们以RocketMQ为例,看下它的源码中,如何分配这两类线程的.

// 源码位置: org.apache.rocketmq.remoting.netty.NettyRemotingServer

Netty写操作的一点概括_写操作
我们通过画图的方式,看下这几类线程的位置

Netty写操作的一点概括_Netty_02

客户端连接服务端,服务端有固定的IO线程进行监听客户端的连接请求.当连接完成之后,会将这个连接注册到另一类IO线程上.一个IO线程可以被注册多个连接.​

Netty写操作的一点概括_Netty_03
如果这个时候,服务端的5个通道都要向客户端写数据.因为业务线程是不能直接向客户端写数据的,只能由IO线程执行写操作.那么应该如何做呢?

Netty写操作的一点概括_Netty_04
IO线程有一个关联的队列,这个队列是线程安全的,是多个生产者一个消费者类型的队列,业务线程只需要将写操作封装成一个写任务,放入到队列中,然后IO线程会从队列中读取任务,执行任务,将数据写到客户端.

关于这个队列,能说的东西也有很多,比如都说Netty是异步串行无锁化执行的,那么它是怎么做到异步的呢? 当队列的任务非常多,是否会发生OOM? Netty提供的高水位线我们该如何使用它?等等,这些都和写操作有关,而且一般情况,我们向selector注册的事件都是监听客户端连接事件和读事件,很少监听写事件,因为要向对端写数据直接写就可以,什么情况会发生不能写,不能写的时候我们该如何做? 这些都是和写操作有关,在Netty中写操作是最复杂最难理解的地方之一.后面的文章我们都会一一讲到.

假如服务端channel-1需要向客户端写一个HelloWorld,业务线程将它封装成一个任务放入到队列中,IO线程拿到这个任务之后,首先IO线程会将HelloWorld写入到Netty的缓冲区中.

Netty写操作的一点概括_写操作_05
每个通道都有自己的Netty缓冲区,数据先写入Netty缓冲区,最后再会刷入到它们各自的TCP缓冲区中.有可能会存在我们只是把HelloWorld中的Hello刷入了TCP缓冲区,而World还在Netty缓冲区,这样就会出现粘包拆包现象,因此编解码也是Netty中相当重要的组件.

Netty写操作的一点概括_java_06
当HelloWorld数据都刷到TCP缓冲区之后,Netty会设置写成功.


个人站点
语雀

公众号

Netty写操作的一点概括_Netty_07