消息集群架构

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

  • 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. SR-IOV简介

    转载:http://docs.oracle.com/cd/E38902_01/html/E38873/glbzi.html SR-IOV 技术是一种基于硬件的虚拟化解决方案,可提高性能和可伸缩性.SR ...

  2. kafka删除topic的方法及我在kafka上边的一些经验

    我在本地做kafka的producer调试,每隔一段时间后,所使用的topic管道就会堆积数据,而且我这边使用的是  kafka   bin 下的consumer命令单独消费的,每次都是  --fro ...

  3. buildroot 重新编译 package

    /************************************************************************* * buildroot 重新编译 package ...

  4. Linux网络常用头文件说明

    sys/types.h:数据类型定义 sys/socket.h:提供socket函数及数据结构 netinet/in.h:定义数据结构sockaddr_in arpa/inet.h:提供IP地址转换函 ...

  5. sublime 2中Package control安装和使用

    安装: 安装时,如果想查看安装进度,可打开console(View->Show Console) 安装Package control有两中方法: 方法1:通过代码安装 import urllib ...

  6. Zookeeper单机版安装(CentOS 7环境下)

    一.环境操作系统和软件版本介绍 1.环境操作系统为CentOS Linux release 7.2.1511 (Core) 可用cat /etc/redhat-release查询 2.软件版本 Zoo ...

  7. web字体图标的使用

    今天给大家介绍一些web字体图标的下载和使用 一.WEB字体 1. 下载外部的字体图标的网站 font-awesome.com 2.CSS文件和font文件 3.html文档中使用外部字体 4.下载字 ...

  8. 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. ...

  9. 1951: [Sdoi2010]古代猪文

    1951: [Sdoi2010]古代猪文 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 2171  Solved: 904[Submit][Status] ...

  10. IOS 加载网络图片2

    //1. NSData dataWithContentsOfURL // [self.icon setImage:[UIImage imageWithData:[NSData dataWithCont ...