rocketmq底层通信模块解析

🔥🔥 SegmentFault D-Day Online 开源开放与新技术创新,快来报名 >>>

rocketMQ通信模块

Rocketmq的通信层是基于通信框架netty 4.0.21.Final之上做了简单的协议封装,基本的类图如下:

 

 

通讯模块是怎么进行的消息传输的

先来看看服务器端启动做了什么:

  • netty服务器启动,监听在8888;netty设置了一个心跳检测器IdleStateHandler,读写超时时间为120s,在120s后都没有读写操作将会触发相应事件。
  • 启动一个线程,获取阻塞队列eventQueue的元素,当netty channel通道发生CONNECT, CLOSE,IDLE,EXCEPTION事件时,队列会被放入事件对象
  • 启动一个定时器Timer,每个1s执行一次,扫描ResponseFuture,超时没有获取结果的会被移除掉

客户端跟服务器端差不多。

rocketmq提供了三种通信方式:

一、invokeSyncImpl 同步调用(主要实现参见NettyRemotingAbstract.invokeSyncImpl

同步调用是指客户端发起远程调用后,当前线程会被阻塞,直到服务器端返回结果或发生超时异常,我们在发送消息时需要同步知道消息发送成功还是失败,一般使用这种方式。

我们知道,netty是异步基于事件驱动的,当我们使用netty向远程服务器发送消息是通过channel.writeAndFlush方法,此方法是异步的,那我们如何同步的获取服务器的返回结果呢?这里的做法是在向服务器发送消息时设置一个唯一的序列号,本地会通过上下文保存一个ResponseFuture对象在Map中,key就是这个唯一的序列号,value就是这个ResponseFuture对象,ResponseFuture对象会设置一个CountDownLatch,每当发送完消息后,就会调用CountDownLatchawait方法挂起当前线程;当服务器返回结果时也会携带之前客户端传递过去的唯一序列号,这样就可以找到ResponseFuture对象,再调用CountDownLatchcountDown方法,此时客户端之前挂起的线程就会苏醒过来,完成一次同步调用。

二、invokeAsyncImpl异步调用(主要实现参见NettyRemotingAbstract.invokeAsyncImpl

客户端发起远程调用前会先设置一个InvokeCallback类,当然也是设置在ResponseFuture对象中,调用结束后不会等待结果,当服务器返回时也是跟同步调用一样会在新的线程里面先找到ResponseFuture,然后执行回调接口也就是InvokeCallbackoperationComplete方法。如果服务器返回结果超时,也会进行回调,客户端可以根据相关的状态来执行相关逻辑。

异步调用不会阻塞线程,调用后会立即返回,调用结果会在异步线程里面执行回调来获取,使用Async需要控制好节奏,不能发送的太快以防止压垮服务器端。所以在invokeAsyncImpl方法里面设置了一个信号量,默认是64个,只有获取到许可的请求才能真正发起远程调用。

三、invokeOnewayImpl 单向调用(主要实现参见NettyRemotingAbstract.invokeOnewayImpl

客户端发送请求后不会等待服务端返回的结果,并且会忽略服务端的处理结果;当前线程调用完毕,调用方并不关心服务器端的处理结果,也不会被阻塞,跟异步调用一样需要控制好节奏以防压垮服务器端。在invokeOnewayImpl方法里面也设置了一个信号量,默认是256个,只有获取到许可的请求才能真正发起远程调用。

三种通信方式的对比

调用方式特点使用场景
Sync同步阻塞需要同步获取结果的场景
Async异步不阻塞当前不需要结果,但是当服务器处理完后,需要做一些其他事情
Oneway异步不阻塞不要需要结果,不保证消息一定发送成功

传输中的协议

RemotingCommand是rocketMQ消息传输的媒介,所有的消息都会包装成RemotingCommand来进行传输。而这个对象会在netty传输之前进行编码,消息接收到进行解码。

RemotingCommand是由头部(header)和消息体(body)组成,消息发送的时候,头部和消息体会分开进行编码。那么RemotingCommand是如何组成的呢?

RemotingCommand的核心字段:

public class RemotingCommand{
    private int code;
    private LanguageCode language = LanguageCode.JAVA;
    private int version = 0;
    private int opaque = requestId.getAndIncrement();
    private int flag = 0;
    private String remark;
    private HashMap<String, String> extFields;
    private transient CommandCustomHeader customHeader;
    private SerializeType serializeTypeCurrentRPC = serializeTypeConfigInThisServer;
    private transient byte[] body;
}

头部(header)

请求头接收方和发起方的含义略有不同,下面的表格详细的说明:

字段名类型RequestResposne
codeint请求操作代码,接收方根据不同的代码做不同的操作应答结果代码,0表示成功,非0表示各种错误代码
language枚举请求方实现的语言,默认Java接收方实现的语言
versionint请求方版本接收方版本
opaqueint请求方在同一连接上不同的请求标识代码,多线程连接服用使用接收方不做修改,直接返回
flagint通信层的标志位通信层的标志位
remarkString传输自定义文本信息错误详细描述
extFieldsMap自定义字段自定义字段

头信息里面还包括了CommandCustomHeader的自定义的一些头信息,会被通过反射的方式放在extFields字段里面

消息体

消息体是直接变为byte数组,由客户端自己序列化,这两部分后一起放入netty传输的ByteBuffer中,一起传输到接收端

报文格式与序列化

lengthheader lengthheaderDatabodyData
4个字节4个字节(高一位字节表示序列化类型,低三位字节表示长度)
  • length:表示整个数据包的长度 占4个字节
  • header length:表示header的长度(高一位字节表示序列化类型,低三位字节表示长度)

headerData的序列化有两种方式:

  • json:使用fastjson进行序列化
  • 自定义:使用bytebuffer自定义序列化

Netty服务器端在启动时设置了TCP参数的含义

  • SO_BACKLOG:1024

    指定全连接队列数,linux系统在文件/proc/sys/net/core/somaxconn指定,默认128;

    还有一个半连接队列数,linux在文件/proc/sys/net/ipv4/tcp_max_syn_backlog指定

  • SO_REUSEADDR:true

    重用处于time_wait状态下的连接

  • SO_KEEPALIVE:false

    保活机制

  • TCP_NODELAY:true

    关闭Nagle算法,Nagle算法可以降低网络里小包的数量,从而提升网络性能,关闭可以提高实时性

  • SO_SNDBUF:65535

    发送缓存区大小

  • SO_RCVBUF:65535

    接受缓存区大小

  • SO_RCVLOWAT:接收缓存水位线

    SO_SNDLOWAT:发送缓存水位线

    它们一般被I/O复用系统调用用来判断socket是否可读或可写。当TCP接收缓冲区中可读数据的总数大于其低水位标记时,I/O复用系统调用将通知应用程序可以从对应的socket上读取数据;当TCP发送缓冲区中的空闲空间(可以写入数据的空间)大于其低水位标记时,I/O复用系统调用将通知应用程序可以往对应的socket上写入数据

    在netty中好像没有看到有设置这两个参数

  • CONNECT_TIMEOUT_MILLIS:3000

    连接超时时间

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值