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 ...
随机推荐
- SR-IOV简介
转载:http://docs.oracle.com/cd/E38902_01/html/E38873/glbzi.html SR-IOV 技术是一种基于硬件的虚拟化解决方案,可提高性能和可伸缩性.SR ...
- kafka删除topic的方法及我在kafka上边的一些经验
我在本地做kafka的producer调试,每隔一段时间后,所使用的topic管道就会堆积数据,而且我这边使用的是 kafka bin 下的consumer命令单独消费的,每次都是 --fro ...
- buildroot 重新编译 package
/************************************************************************* * buildroot 重新编译 package ...
- Linux网络常用头文件说明
sys/types.h:数据类型定义 sys/socket.h:提供socket函数及数据结构 netinet/in.h:定义数据结构sockaddr_in arpa/inet.h:提供IP地址转换函 ...
- sublime 2中Package control安装和使用
安装: 安装时,如果想查看安装进度,可打开console(View->Show Console) 安装Package control有两中方法: 方法1:通过代码安装 import urllib ...
- Zookeeper单机版安装(CentOS 7环境下)
一.环境操作系统和软件版本介绍 1.环境操作系统为CentOS Linux release 7.2.1511 (Core) 可用cat /etc/redhat-release查询 2.软件版本 Zoo ...
- web字体图标的使用
今天给大家介绍一些web字体图标的下载和使用 一.WEB字体 1. 下载外部的字体图标的网站 font-awesome.com 2.CSS文件和font文件 3.html文档中使用外部字体 4.下载字 ...
- Attempt to write to field 'android.support.v4.app.FragmentManagerImpl android.support.v4.app.Fragment.mFragmentManager' on a null object reference
E/AndroidRuntime﹕ FATAL EXCEPTION: mainProcess: org.example.magnusluca.drawertestapp, PID: 3624java. ...
- 1951: [Sdoi2010]古代猪文
1951: [Sdoi2010]古代猪文 Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 2171 Solved: 904[Submit][Status] ...
- IOS 加载网络图片2
//1. NSData dataWithContentsOfURL // [self.icon setImage:[UIImage imageWithData:[NSData dataWithCont ...