消息集群架构

对于发送方来说的关键几要素

  • 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()方法主要做这么几件事:

  1. 检查配置是否正确,checkConfig();
  2. 注册produce,registerProducer();
  3. mQClientFactory.start();
  4. 向所有的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类型消息中间件-消息发布者(一)的更多相关文章

  1. push类型消息中间件-消息发布者(二)

    1.消息发布者声明 我们以spring的方式来声明一个消息发布者: <bean id="operateLogsMessageManager" class="com. ...

  2. pull类型消息中间件-消息消费者(二)

    消费者的实例化 关于consumer的默认实现,metaq有两种: DefaultMQPullConsumer:由业务方主动拉取消息 DefaultMQPushConsumer:通过业务方注册回调方法 ...

  3. pull类型消息中间件-消息服务端(三)

    部署架构 消息存储 存储结构 MetaQ的存储结构是一种物理队列+逻辑队列的结构.如下图所示: Producer生产消息,根据消息的topic选择topic对应某一个分区,然后发送到这个分区对应的Br ...

  4. push类型消息中间件-消息订阅者(一)

    1.订阅者的声明方式 我们以spring组件化的方式,声明一个消息订阅者,对于消息订阅者关心的主要有: topic: 一级消息类型(又名消息主题).如TRADE 消息类型:二级消息类型,区别同一Top ...

  5. push类型消息中间件-消息服务端(三)

    1.连接管理 网络架构原来是使用是自己开发的网络框架Gecko,Gecko默认为每个网络连接分配64KB的内存,支持1000个网络连接,就需要大概64MB的内存.后来采用Netty重构了网络服务层. ...

  6. AspNetWebApi管线中如果定义两种类型的消息处理程序(全局/路由)

    AspNetWebApi管线中如果定义两种类型的消息处理程序(全局/路由) 在AspNetWebApi管线中存在两种类型的消息处理程序(Message Handler) 1.全局消息处理程序,所有的请 ...

  7. SIP消息类型和消息格式

    转自:http://blog.chinaunix.net/uid-1797566-id-2840904.html sip消息类型和消息格式 SIP是一个基于文本的协议,使用的是UTF-8字符集. SI ...

  8. Python操作rabbitmq系列(四):根据类型订阅消息

    在上一章中,所有的接收端获取的所有的消息.这一章,我们将讨论,一些消息,仍然发送给所有接收端.其中,某个接收端,只对其中某些消息感兴趣,它只想接收这一部分消息.如下图:C1,只对error感兴趣,C2 ...

  9. ActiveMQ 处理不同类型的消息

    ActiveMQ 中的消息都继承自 org.apache.activemq.command.BaseCommand 类. broker 处理消息的调用栈如下: TransportConnection ...

随机推荐

  1. LaTeX入门教程

    LaTeX(LATEX,音译"拉泰赫")是一种基于ΤΕΧ的排版系统,由美国计算机学家莱斯利·兰伯特(Leslie Lamport)在20世纪80年代初期开发,利用这种格式,即使使用 ...

  2. UE4新手编程之创建C++项目

    虚幻4中常用的按键和快捷键 虚幻4中有一些按键和快捷键很常用,牢记它们并运动到实际的项目开发中,将会大大地提高你的工作效率和使得工作更简便快捷.下面将列举它们出来: 按键   动作  鼠标左键   选 ...

  3. java编程思想笔记(一)——面向对象导论

    1.1 抽象过程 1.所有编程语言都提供抽象编程机制. 2.人们所能够解决的问题的复杂性直接取决于抽象的类型(所抽象的是什么)和质量. 3."命令式"语言(basic,c等)都是对 ...

  4. charles支持https抓包

    前言 最近发现访问项目的网页偶尔会被插入广告,很有可能是运营商劫持流量插入进去的,我在家里使用的长城宽带打开非加密的网页,时不时会弹个广告窗,这个也算是中国特色了.因此计划项目上线https,抓包分析 ...

  5. SpringMVC实现注解式权限验证(转)

    SpringMVC学习系列(9) 之 实现注解式权限验证   对大部分系统来说都需要权限管理来决定不同用户可以看到哪些内容,那么如何在Spring MVC中实现权限验证呢?当然我们可以继续使用serv ...

  6. 在Freeplane中显示与隐藏层级图标

    如下图所示,当选择了Edit → Icons → Show icons hierarchically时,给子节点Subsection 1.2.1添加的图标也同样会显示在其所有的父节点上,并且,它们并不 ...

  7. webpack + vue最佳实践

    webpack + vue最佳实践 我的原文地址:http://www.xiaoniuzai.cn/2016/10/04/webpack%20+%20vue%E6%9C%80%E4%BD%B3%E5% ...

  8. Passing Reference by value

    今天查bug的时候,遇到一个问题,一个Dictionary<int[],string>数据结构,在使用key取它的value时: var tempVar = _dic[key]; 发生崩溃 ...

  9. linux服务器没网情况下手动安装软件几个方法

    1,找到一个有网的服务器,使用yumdownloader gcc,获取需要的rmp包: 2,在http://pkgs.org 下下载所需要的rpm包

  10. CodeForces 675D Tree Construction

    递归,$RMQ$. 因为$n$较大,可以采用递归建树的策略. 对每一个点标一个$id$.然后按照$v$从小到大排序,每一段$[L,R]$的根节点就是$id$最小的那个. 因为二叉搜索树可能是一条链,所 ...