1.解析RocketMQ的client客户端
参考:http://www.cnblogs.com/atliwen/p/5216849.html
1.2个核心接口,3个默认实现
interface MQProducer
--- DefaultMQProducer
interface MQConsumer
--- DefaultMQPushConsumer
--- DefaultMQPullConsumer
解析:
DefaultMQProducer是MQProducer的唯一默认实现,
其实现 MQProducer 接口的时候 还继承了 ClientConfig类 (客户端配置类),可以配置如 sendMsgTimeout超时时间,producerGroup 生产者组 最大消息容量和是否启用压缩等
关系
两个接口
interface MQProducer //生产者接口
{
实现该接口的只有一个 默认的 DefaultMQProducer
DefaultMQProducer 实现 MQProducer 接口的时候 还继承了 ClientConfig类 (客户端配置类)
可以配置如 sendMsgTimeout 超时时间 producerGroup 消息最大多少 超过多少压缩等等
关键方法 :
send(Message) 发送一个消息到MQ
这个方法其实是调用 DefaultMQProducer构造方法 创建的 defaultMQProducerImpl 类对象的 send(..)方法
defaultMQProducerImpl 类 才是真正发送消息的核心类
defaultMQProducerImpl.send 方法 --》 sendDefaultImpl方法
sendDefaultImpl --》 tryToFindTopicPublishInfo 来检测映射 队列是否存在 是否正常
{
final Segment<K,V>[] segments; 这个 键值
不存在 不正常 :
创建一个 TopicPublishInfo 到 segments 映射文件 同时 将 Topic (队列) 信息 更新到NameServer中
}
sendDefaultImpl --》 通过设置是失败重复次数 和 超时时间 来从新发送消息
详细 for (; times < 失败重复次数 && (结束时间 - 开始时间) < 配置的超时时间; times++)
sendDefaultImpl --》sendKernelImpl 装载 配置 信息
--》sendKernelImpl --》this.mQClientFactory.getMQClientAPIImpl().sendMessage()
MQClientInstance mQClientFactory 对象 是在 DefaultMQProducer start启动方式时候初始化的
MQClientManager.getInstance().getAndCreateMQClientInstance(this.defaultMQProducer,rpcHook);
--》 --》sendMessage
{
MQClientInstance --》 MQClientAPIImpl mQClientAPIImpl
MQClientAPIImpl.sendMessage() --> sendMessageSync
switch (communicationMode) 同步 异步 单向 处理 默认是 同步
}
后续返回 SendResult sendResult 改类型描述当时 发送MQ 的最终状态
Message 消息的 Topic 不能为空
producer.shutdown(); 关闭 shutdown来清理资源,关闭网络连接,从MetaQ服务器上注销自己
}
发送消息负载的问题
{
看源码 是通过循环从 namesrv 获取的到 Topic 路由消息 (也就是有几个broker 每个 broker 有几个队列)
然后 记录当前发送过的 +1
备注 : 队列数量 小于 消费者数量 多余的消费者将不起做用
}
关于顺序消息发送 的问题
{
环境: 1 下单 2 付款 3 收货 3个状态 , 普通模式下 发送到队列中的 是轮询队列 将3个消息分别发送到多个队列中。
很可能会照成出现 先消费 2 在消费 1 流程错乱的情况 当然可以业务层处理 但是业务层处理比较麻烦
顺序消费的发送的原理 :
我们自己指定 消息将要添加的队列
SendResult sendResult = producer.send(msg,
new MessageQueueSelector()
{
@Override
public MessageQueue select(List<MessageQueue> mqs,
Message msg, Object arg)
{
Integer id = (Integer) arg;
int index = id % mqs.size(); // 通过取于来 讲 同一个订单号 访入同一个队列中
// 前提是 队列数量没有变动
return mqs.get(index);
}
}, “10001”); // orderID “10001”是传递给回调方法的 自定义数据
List<MessageQueue> mqs 就是从namesrv 获取的所有队列
}
备注
// 订单 Id
String orderId = "20034568923546";
message.setKeys(orderId);
// Keys
每个消息在业务局面的唯一标识码 通过 topic,key 来查询返条消息内容,以及消息被谁消费
查询的时候 非常重要
消费者
interface MQConsumer
{
// 回溯消费
{
mqadmin resetOffsetByTime 命令
改方式 是通过消费的日志来恢复的 但是只能通过 消费的组来恢复 恢复消息后 也只能用改组来从新消费
-s : 时间戳的问题 可以是 毫秒 或者是从什么时候开始
}
//拉取模式
interface MQPullConsumer:
{
}
// 接收模式
长轮询模式 一次