大概的流程参考
快速学习-RocketMQ-“Request-Reply”特性_cwl_java的博客-CSDN博客_rocketmq 请求应答
解读RocketMQ对RPC的设计实现原理_林风自在的博客-CSDN博客_rocketmq rpc
使用此特性可以达到同步调用的效果
本文主要是源码讲述,以及reqest/reply模式调优调优。分析jar的版本基于4.7.1
优劣势
优势
- mq达到同步调用效果
- 消费者可重试处理
劣势
- 相比rpc接口直接调用,耗时会增加
- 生产端重启不能接受到返回结果
总结:可以达到同步效果的作用,利用mq可以作为存储消息的队列。如果用做大流量削峰的模式不是很合适,本身功能是同步。可作为一定量的流量削峰。
源码分析
初始化MQClientInstance
org.apache.rocketmq.client.impl.factory.MQClientInstance#MQClientInstance(org.apache.rocketmq.client.ClientConfig, int, java.lang.String, org.apache.rocketmq.remoting.RPCHook)
NettyRemotingClient是rocketmq服务端交互类
初始化MQClientAPIImpl
org.apache.rocketmq.client.impl.MQClientAPIImpl#MQClientAPIImpl
NettyRemotingClient交互时注册处理的命令有哪些的。
RequestCode.PUSH_REPLY_MESSAGE_TO_CLIENT是request/reply模式下,处理回复的命令
初始化NettyRemotingClient交互命令的线程池
org.apache.rocketmq.remoting.netty.NettyRemotingClient#NettyRemotingClient(org.apache.rocketmq.remoting.netty.NettyClientConfig, org.apache.rocketmq.remoting.ChannelEventListener)
启动上述初始化对象
org.apache.rocketmq.client.impl.factory.MQClientInstance#start
NettyRemotingClient启动过程
org.apache.rocketmq.remoting.netty.NettyRemotingClient#start
NettyClientHandler实例化及处理过程分析
读取rocketmq交互中的命令内容
org.apache.rocketmq.remoting.netty.NettyRemotingClient.NettyClientHandler
org.apache.rocketmq.remoting.netty.NettyRemotingAbstract#processRequestCommand
看到这里,了解,获取的是空的,走的就是defaultRequestProcessor,因为在注册命令的是否,线程池填写的为空。把命令处理过程中放到线程池
org.apache.rocketmq.client.impl.ClientRemotingProcessor#processRequest
MessageConst.PROPERTY_CORRELATION_ID放到头部中,消费者进行消费时,回复时需要把这个信息给返回过来,才能找到对应是生产者的等待线程。
实践
1 项目中用此模式,尽量让代码通用,减少后续工作量
本质上对于服务提供方来说,mq消费只是多一条调用的渠道而已。所以生产者把接口,调用方法,请求参数进行序列化,通过mq传到消费者。消费者反序列化,调用。这里可以通过反射进行调用,可以做到通用
2 超时处理
2.1 生产者等待消费者消息回复超时,会报RequestTimeoutException,针对此异常,可根据业务的异常,进行包装处理
2.2 消费者处理超时
2.2.1 消息在rocketmq积压太久,接受到消息,就已超过业务自己定义超时时间。
2.2.2 消息经过业务逻辑处理后,已超过业务自己定义超时时间。
3 发送时间,超时时间定义
发送时间:生产消息时,将发送时间的时间戳,发送过来
超时时间定义:发送时间的request就已定义,放到头部已发送过来requestMessage.getProperty(MessageConst.PROPERTY_MESSAGE_TTL);
注意:
回复的消息的一定用rocketmq的工具类方法,会组装必须的回复头部数据,具体的例子可以参考rocketmq提供的dome
MessageUtil.createReplyMessage(messageExt, replyContent);
调优
通过上述,已知道机制
同步调用请求很多,生产者接受到回复的消息也很多,如果线程池线程少肯定会造成拥堵,造成不必要的超时
1 调整生者者接受回复请求的线程池数组的线程数。
默认是cpu的数量
//#producer的client接受rockemq推送请求并发量,处理请求.request/repaly模式很重要,默认是cpu核心的数量 producer.setClientCallbackExecutorThreads(clientCallbackExecutorThreads);
2 netty和服务端的交互的工作线程数
目前nettty工作线程数量固定4个,代码已写死,目前是调不了的。如果1的数量足够合理,这个过程是异步的,加到线程池处理,速度是很快的。调优优先机不高,要调,需要改源码