pull类型消息中间件-消息发布者(一)
消息集群架构

对于发送方来说的关键几要素
- topic
消息的主题,由用户定义。类似于知乎的话题,Producer发送消息的时候需要指定发送到某一个topic下面,Consumer从某一个topic下面消费消息。
- tag
每次发送一条消息的时候,给消息加一个Tag,方便Consumer过滤消息
- message
消息,负载发送的消息的信息。在生产者,服务端和 消费者之间传输
- queue
queue就是metaq中具体用来存数消息的数据结构,每一个topic下面对应多个queue,以目录的形式分开存储在磁盘上。我们在最初的网络结构中就描述了brokerserver集群,然而对应到具体某一个brokerserver的存储,就是queue+commitlog
之前介绍brokerserver的时候有简单提过DefaultMessageStore类,这是metaq消息存储的默认实现类,里面存储的具体配置,也包含了commitlog,consumequeue,关于消息加载,刷盘,恢复,清理等存储设计都在这里。
- Group
消费者可以是多个消费者共同消费一个 topic 下的消息,每个消费者消费部分消息。这些消费者就组成一个分组,拥有同一个分组名称,通常也称为消费者集群。
集群消费,一条消息只会被同一个group里一个消费者消费。 不同group之间相互不影响。
广播消费,一条消息会被同一个group里每一个消费端消费
消息发送者实例化
Producer 消息生产者,负责产生消息,一般由业务系统负责产生消息。
一般一个应用创建一个Producer,由应用来维护此对象,可以设置为全局对象或者单例。
消息子类型用 tags 来标识,tags 可以由应用自由设置。只有发送消息设置了 tags, 消费方在订阅消息时,才可以利用 tags 在 broker 做消息过滤。
我们可以看出start()方法主要做这么几件事:
- 检查配置是否正确,checkConfig();
- 注册produce,registerProducer();
- mQClientFactory.start();
- 向所有的broker发送的Heartbeat。
发送方的核心服务:
//Start request-response channel
this.mQClientAPIImpl.start();
//Start various schedule tasks
this.startScheduledTask();
//Start pull service
this.pullMessageService.start();
//Start rebalance service
this.rebalanceService.start();
//Start push service
this.defaultMQProducer.getDefaultMQProducerImpl().start(false);
消息发送流程

metaQ的底层通信还是基于netty的。
消息载体
private String topic;
private int flag;
private Map<String, String> properties;
private byte[] body;
private int queueId;
private int storeSize;
private long queueOffset;
private int sysFlag;
private long bornTimestamp;
private SocketAddress bornHost;
private long storeTimestamp;
private SocketAddress storeHost;
private String msgId;
private long commitLogOffset;
private int bodyCRC;
private int reconsumeTimes;
private long preparedTransactionOffset;
这里需要强调的是,Message是为了便于metaq逻辑操作而定义的偏向于业务逻辑的类,实际上的网络传输类是RemotingCommand,结构如下

public ByteBuffer encode() {
int length = 4;
byte[] headerData = this.buildHeader();
length += headerData.length;
if (this.body != null) {
length += body.length;
}
ByteBuffer result = ByteBuffer.allocate(4 + length);
result.putInt(length);
result.putInt(headerData.length);
result.put(headerData);
if (this.body != null) {
result.put(this.body);
}
result.flip();
return result;
}
producer的send()方法:
客户端从zookeeper上获取publish的topic对应的broker和分区列表(按照brokerId和partition的顺序排列组织成一个有序的分区列表),生产者在发送消息的时候必须选择一个分区来发送消息,发送的时候按照从头到尾循环往复的方式选择来发送消息。
默认调用的是同步发送方法。
调用netty中的 com.alibaba.rocketmq.remoting.netty.NettyRemotingClient#invokeSync
public RemotingCommand invokeSync(String addr, final RemotingCommand request, long timeoutMillis)
throws InterruptedException, RemotingConnectException, RemotingSendRequestException,
RemotingTimeoutException {
final Channel channel = this.getAndCreateChannel(addr);
if (channel != null && channel.isActive()) {
try {
if (this.rpcHook != null) {
this.rpcHook.doBeforeRequest(addr, request);
}
RemotingCommand response = this.invokeSyncImpl(channel, request, timeoutMillis);
if (this.rpcHook != null) {
this.rpcHook.doAfterResponse(RemotingHelper.parseChannelRemoteAddr(channel),
request, response);
}
return response;
}
catch (RemotingSendRequestException e) {
log.warn("invokeSync: send request exception, so close the channel[{}]", addr);
this.closeChannel(addr, channel);
throw e;
}
catch (RemotingTimeoutException e) {
log.warn("invokeSync: wait response timeout exception, the channel[{}]", addr);
throw e;
}
}
else {
this.closeChannel(addr, channel);
throw new RemotingConnectException(addr);
}
}
同时可以设置调用异步发送方法。
调用com.alibaba.rocketmq.remoting.netty.NettyRemotingClient#invokeAsync
public void invokeAsync(String addr, RemotingCommand request, long timeoutMillis,
InvokeCallback invokeCallback) throws InterruptedException, RemotingConnectException,
RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException {
final Channel channel = this.getAndCreateChannel(addr);
if (channel != null && channel.isActive()) {
try {
if (this.rpcHook != null) {
this.rpcHook.doBeforeRequest(addr, request);
}
this.invokeAsyncImpl(channel, request, timeoutMillis, invokeCallback);
}
catch (RemotingSendRequestException e) {
log.warn("invokeAsync: send request exception, so close the channel[{}]", addr);
this.closeChannel(addr, channel);
throw e;
}
}
else {
this.closeChannel(addr, channel);
throw new RemotingConnectException(addr);
}
}
这两个方法一个为同步,一个为异步。而同步与异步的主要实现则来自于ResponseFuture类。通过countDownLatch的使用,完成了同步操作(详情参看此类的putResponse方法及waitResponse方法);通过传递invokeCallback完成异步操作
pull类型消息中间件-消息发布者(一)的更多相关文章
- push类型消息中间件-消息发布者(二)
1.消息发布者声明 我们以spring的方式来声明一个消息发布者: <bean id="operateLogsMessageManager" class="com. ...
- pull类型消息中间件-消息消费者(二)
消费者的实例化 关于consumer的默认实现,metaq有两种: DefaultMQPullConsumer:由业务方主动拉取消息 DefaultMQPushConsumer:通过业务方注册回调方法 ...
- pull类型消息中间件-消息服务端(三)
部署架构 消息存储 存储结构 MetaQ的存储结构是一种物理队列+逻辑队列的结构.如下图所示: Producer生产消息,根据消息的topic选择topic对应某一个分区,然后发送到这个分区对应的Br ...
- push类型消息中间件-消息订阅者(一)
1.订阅者的声明方式 我们以spring组件化的方式,声明一个消息订阅者,对于消息订阅者关心的主要有: topic: 一级消息类型(又名消息主题).如TRADE 消息类型:二级消息类型,区别同一Top ...
- push类型消息中间件-消息服务端(三)
1.连接管理 网络架构原来是使用是自己开发的网络框架Gecko,Gecko默认为每个网络连接分配64KB的内存,支持1000个网络连接,就需要大概64MB的内存.后来采用Netty重构了网络服务层. ...
- AspNetWebApi管线中如果定义两种类型的消息处理程序(全局/路由)
AspNetWebApi管线中如果定义两种类型的消息处理程序(全局/路由) 在AspNetWebApi管线中存在两种类型的消息处理程序(Message Handler) 1.全局消息处理程序,所有的请 ...
- SIP消息类型和消息格式
转自:http://blog.chinaunix.net/uid-1797566-id-2840904.html sip消息类型和消息格式 SIP是一个基于文本的协议,使用的是UTF-8字符集. SI ...
- Python操作rabbitmq系列(四):根据类型订阅消息
在上一章中,所有的接收端获取的所有的消息.这一章,我们将讨论,一些消息,仍然发送给所有接收端.其中,某个接收端,只对其中某些消息感兴趣,它只想接收这一部分消息.如下图:C1,只对error感兴趣,C2 ...
- ActiveMQ 处理不同类型的消息
ActiveMQ 中的消息都继承自 org.apache.activemq.command.BaseCommand 类. broker 处理消息的调用栈如下: TransportConnection ...
随机推荐
- 使用 IDEA 创建 Maven Web 项目 (一)- 使用IEAD创建Maven项目
创建IDEA项目 单击 Create New Project 按钮,弹出 New Project 对话框. 选择 Maven 选项,单击 Next 按钮. 输入 GroupId.ArtifactId. ...
- Cocos2d-x 截图功能
2.x-3.x版本 //获取屏幕尺寸 CCSize size = CCDirector::sharedDirector()->getWinSize ...
- 【JS学习笔记】提取行间事件
行间提取事件第一种方法: function 名字() { ... } oBtn.onclick=名字: 第二种方法: oBtn.onclick=function () { ... } 其实在JS当中, ...
- java中的ArrayList 、List、LinkedList、Collection关系详解
一.基础介绍(Set.List.Map) Set(集):集合中的元素不按特定方式排序,并且没有重复对象.他的有些实现类能对集合中的对象按特定方式排序. List(列表):集合中的元素按索引位置排序,可 ...
- Ubuntu16.04 server下配置MySQL,并开启远程连接
背景 最近正在学nodejs,想到曾经有台云服务器,但是很久不用了,由于怕麻烦,一股脑的把云主机重装了个Ubuntu系统,于是配置MySQL成了配置服务中的一个环节(node用不用MySQL不管,主要 ...
- cocoaPods第三方库使用详解
终端上安装了cocoapods后,打开终端输入下面命令: cd /Users/Sivek_lin/Desktop/AFNTest/AFNTest touch podfile pod search af ...
- OSI模型第一层物理层
纪念我曾今热爱的数通(^o^). 物理层 一句话概述: OSI的第一层,它虽然处于最底层,却是整个开放系统的基础.物理层为设备之间的数据通信提供传输媒体及互连设备,为数据传输提供可靠的环境. 常见设备 ...
- netty高级篇(3)-HTTP协议开发
一.HTTP协议简介 应用层协议http,发展至今已经是http2.0了,拥有以下特点: (1) CS模式的协议 (2) 简单 - 只需要服务URL,携带必要的请求参数或者消息体 (3) 灵活 - 任 ...
- 在Windows上创建同样的Linux操作环境
在之前的文章中,介绍了我在GNU/Linux图形界面环境下所使用的工具集合.其基本目的是在保证占用最少系统资源的条件下,将电脑操作效率推向极致.这样的工具组合尤如瑞士军刀一般,简洁.高效.功能全面.与 ...
- 反编译与调试APK
0×01前言 这年头,apk全都是加密啊,加壳啊,反调试啊,小伙伴们表示已经不能愉快的玩耍了.静态分析越来越不靠谱了,apktool.ApkIDE.jd GUI.dex2jar等已经无法满足大家的需求 ...