7、Producer发送单向、同步、异步消息源码

本文介绍了RocketMQ的三种发送模式:单向、同步和异步。单向发送不关心结果,利用Semaphore控制并发;同步发送使用ResponseFuture阻塞等待响应,超时或异常会触发重试;异步发送也基于Semaphore,有回调处理结果,失败可重试。NettyClientHandler处理服务端响应,执行回调逻辑。
摘要由CSDN通过智能技术生成

单向发送模式:

该方法首先将请求标记为单向发送,然后基于Semaphore信号量尝试获取单向发送的资源,通过信号量控制单向消息并发发送的消息数,从而保护系统内存占用。客户端单向发送的Semaphore信号量默认为65535,即单向消息最大并发为65535,可通过配置"com.rocketmq.remoting.clientOnewaySemaphoreValue"系统变量更改。

获取到了信号量资源之后。构建SemaphoreReleaseOnlyOnce对象,保证信号量本次只被释放一次,防止并发操作引起线程安全问题,然后就通过channel发送请求即可。

在其监听器ChannelFutureListener中,会释放信号量,如果发送失败了,仅仅是打印一行warn日志,然后就不管了。如果没有获取到信号量资源,那么直接抛出异常即可,并且不再发送。

只管发送不管结果,不会进行任何重试,这就是单向发送消息的真正含义。

同步发送模式:

首先创建一个ResponseFuture,然后将本次请求id和respone存入responseTable缓存。

随后执行调用,并添加一个ChannelFutureListener,消息发送完毕会进行回调。然后responseFuture通过waitResponse方法阻塞当前线程,直到得到响应结果或者到达超时时间。

当ChannelFutureListener回调的时候会判断如果消息发送成功,那么设置发送成功并返回,否则设置发送失败标志和失败原因,并且设置响应结果为null,唤醒阻塞的responseFuture。

responseFuture被唤醒后会进行一系列判断。如果响应结果为null,那么会根据不同情况抛出不同的异常,如果响应结果不为null,那么返回响应结果。

最后在finaly块中从responseTable中移除响应结果缓存。

异步发送模式:

invokeAsyncImpl方法发起异步调用。该方法和单向发送的方法一样,都会基于Semaphore信号量尝试获取异步发送的资源,通过信号量控制异步消息并发发送的消息数,从而保护系统内存占用。客户端单向发送的Semaphore信号量默认为65535,即异步消息最大并发为65535,可通过配置"com.rocketmq.remoting.clientAsyncSemaphoreValue"系统变量更改。

创建一个ResponseFuture,设置超时时间、回调函数。然后将本次请求id和respone存入responseTable缓存。

随后执行调用,并添加一个ChannelFutureListener,消息发送完毕会进行回调。当ChannelFutureListener回调的时候会判断如果消息发送成功,那么设置发送成功并返回,否则如果发送失败了,则移除缓存、设置false、并且执行InvokeCallback#operationComplete回调。

如果发送成功了,那么InvokeCallback#operationComplete回调会执行吗,当让会了,当请求正常处理完毕的时候,在processResponseCommand方法中会将执行InvokeCallback#operationComplete回调。

onExceptionImpl异常处理

       重试之前,首先会判断本次重试的次数是否大于重试总次数,参数为retryTimesWhenSendFailed,默认2次。如果超过了最大重试次数,那么便不会重试

NettyClientHandler处理服务端消息(主要用来回调各种发送成功、失败后的逻辑):

生产者发送-》broker响应=》生产者NettyClientHandler处理服务端消息

processResponseCommand处理响应

客户端发送消息之后服务端的响应会被processResponseCommand方法处理。消息发送请求的响应处理也是该方法完成的。其大概流程为:

       先根据请求id找到之前放到responseTable的ResponseFuture,然后从responseTable中移除ResponseFuture缓存。

       判断如果存在回调函数,即异步请求,那么调用executeInvokeCallback方法,该方法会执行回调函数的方法。

       如果没有回调函数,则调用putResponse方法。该方法将响应数据设置到responseCommand,然后调用countDownLatch.countDown,即倒计数减去1,唤醒等待的线程。

总结

本次我们讲解了重要的发送消息的内部方法MQClientAPIImpl#sendMessage的源码,该方法内部又会根据发送模式执行不同的发送逻辑。单向发送模式调用RemotingClient#invokeOneway方法;异步发送模式调用MQClientAPIImpl#sendMessageAsync方法;同步发送模式调用MQClientAPIImpl#sendMessageSync方法。在异步和同步模式发送方法的调用前还会再检查是否超时,如果超时则不再调用。

同步发送模式内部采用CountDownLatch工具实现线程的阻塞和唤醒,当发送了同步消息之后,当前线程阻塞,当服务端响应返回之后,将会通过CountDownLatch减少倒计数来唤醒阻塞的线程。发送请求和响应怎么对应上的呢?发送请求的时候会生成并带上本次请求的请求Id,客户端返回响应中带有对应的请求的请求Id,这样就能对应上了。

同步发送和异步发送模式都会有消息重试,消息发送过程中如果抛出了RemotingException、MQClientException、以及部分MQBrokerException异常时,那么会进行重试,默认重试2次。如果抛出了InterruptedException,或者因为超时则不再重试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值