ActiveMQ源码分析之Producer与Broker交互

AMQ生产者和Broker交互完整流程如下图。

该图完整的描述了Producer发送消息时和Broker的整个交互流程。

由于该过程交互较多,可以将整个流程分为三个部分。

1、第一部分为Producer和Broker建立连接,包括发送WireFormatInfo,ConnectionInfo,ConsumerInfo,SessionInfo,ProducerInfo等信息。

2、第二部分为发送消息部分,包括发送TransactionInfo开启事务,发送消息内容ActiveMQTextMessage,提交事务TransactionInfo等功能。

3、第三部分为发送消息之后的一些清理工作,包括发送两次RemoveInfo消息和最后的ShutdownInfo消息。

首先来看第一分部建立连接的时候Broker端都做了些什么。Broker端首先接收到Producer发送的WireFormatInfo消息,然后设置Broker端的协议版本。

 public Response processWireFormat(WireFormatInfo info) throws Exception {
        wireFormatInfo = info;
        protocolVersion.set(info.getVersion());
        return null;
 }

客户端接收到服务端的WireFormatInfo响应信息之后,也设置协议版本,并且和服务端一致。

protected void onWireFormatInfo(WireFormatInfo info) {
        protocolVersion.set(info.getVersion());
}

紧接着Broker收到Producer发送的ConnectionInfo信息,然后创建TransportConnectionState对象封装Connection,并将connectionId和TransportConnectionState的关系保存在一个Map中,以供后续使用。同时创建了ConnectionContext对象,该对象将connector,clientId,connectionInfo,wireFormatInfo等对象的值封装了起来。

第一部分的功能都比较简单,接着看第二部分的功能。

首先是Broker端接收到Producer发送的TransactionInfo信息,Broker端创建对应的LocalTransaction对象,并将xid和LocalTransaction关系维护在一个Map,供后续使用。

public void beginTransaction(ConnectionContext context, TransactionId xid) throws Exception {
         。。。。。。省略
            Map<TransactionId, Transaction> transactionMap = context.getTransactions();
            Transaction transaction = transactionMap.get(xid);
            if (transaction != null) {
                throw new JMSException("Transaction '" + xid + "' has already been started.");
            }
            transaction = new LocalTransaction(transactionStore, (LocalTransactionId)xid, context);
            transactionMap.put(xid, transaction);
 }

接着Broker端接收到Producer发送的ActiveMQTextMessage信息,也就是我们平常最为关心的消息内容。Broker端接收到消息之后首先根据xid获取到LocalTransaction对象,然后获取到消息的destination,保存消息的时候会和消息进行关联,接着判断消息是否已过期,内存是否已满。

 if (message.isExpired()) {
           
        。。。。。。省略
 }
 if (memoryUsage.isFull()) {

        。。。。。。省略
 }

最后是将消息内容,事务信息封装成KahaAddMessageCommand对象,转换成对应的byte数组,保存在KahaDB中,关于消息存储这快的逻辑会在KahaDB部分仔细分析,此处不再展开。

public void addMessage(final ConnectionContext context, final Message message) throws IOException {
            final KahaAddMessageCommand command = new KahaAddMessageCommand();
            command.setDestination(dest);
            command.setMessageId(message.getMessageId().toProducerKey());
            command.setTransactionInfo(TransactionIdConversion.convert(transactionIdTransformer.transform(message.getTransactionId())));
            command.setPriority(message.getPriority());
            command.setPrioritySupported(isPrioritizedMessages());
            org.apache.activemq.util.ByteSequence packet = wireFormat.marshal(message);
            command.setMessage(new Buffer(packet.getData(), packet.getOffset(), packet.getLength()));
          。。。。。。保存到KahaDB中

}

消息保存之后Broker会接收到Producer发送的事务提交消息,Broker会构造如下数据结构,并转成对应的字节数组,存入KahaDB中。

transaction_info {
  local_transaction_id {
    connection_id: ID:jiangzhiqiangdeMacBook-Pro.local-51411-1556719361587-1:1
    transaction_id: 1
  }
}

最后更新最后一次保存的索引地址。

metadata.lastUpdate = location;

事务,索引相关的内容也会在KahaDB部分仔细分析。

第三份部分主要是做一些清理工作,我们重点来看为什么Producer为什么要发送两次RemoveInfo信息。

第一次发送RemoveInfo信息,最终调用processRemoveConsumer方法,主要清理本次请求Broker的客户端信息,如清理当前连接的Consumer信息,Destination,断开订阅等。

protected void destroySubscription(Subscription sub) {
        sub.destroy();
}

第二次发送RemoveInfo信息,执行processRemoveConnection方法,主要执行断开session连接,断开connection操作,然后从Broker删除Producer,Session,DestinationInfo,TransportConnection等信息,注意针对的不是本次的连接,而是所有的。Broker会遍历所有的Session对象,逐个断开连接,清除对应的属性值。

public void shutdown() {
        if (shutdown.compareAndSet(false, true)) {
            for (Iterator<SessionState> iter = sessions.values().iterator(); iter.hasNext();) {
                SessionState ss = iter.next();
                ss.shutdown();
            }
        }
 }

本篇的主要介绍了Producer和Broker交互的整个过程,其中跟存储,索引,事务相关的实现原理和细节将在KahaDB部分进行详细的分析,此处暂且略过。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值