activemq broker topic消息收发处理过程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/YAOQINGGG/article/details/79912913

首先看一下activemq的网络模型(获取自网络)。
这里写图片描述
可以看到,TcpTransportServer是一个监听网络的类,如果有socket连接,便会放入阻塞队列,然后创建一个TransportConnection类,该类接收socket的消息,进行逻辑处理;

先看看TransportConnector在干啥
这里写图片描述
第一步:设置server处理类
第二步:接收到连接socket加入线程池
第三步:创建一个连接
第四步:连接启动
最终会调用到getServer().start();在看看TcpTransportServer在干啥

    /**
     * pull Sockets from the ServerSocket
     */
    @Override
    public void run() {
        if (!isStopped() && !isStopping()) {
            final ServerSocket serverSocket = this.serverSocket;
            if (serverSocket == null) {
                onAcceptError(new IOException("Server started without a valid ServerSocket"));
            }

            final ServerSocketChannel channel = serverSocket.getChannel();
            if (channel != null) {
                doRunWithServerSocketChannel(channel);
            } else {
                doRunWithServerSocket(serverSocket);
            }
        }
    }

会调用到
doRunWithServerSocketChannel(channel);

    private void doRunWithServerSocketChannel(final ServerSocketChannel channel) {
        try {
            channel.configureBlocking(false);
            final Selector selector = Selector.open();

            try {
                channel.register(selector, SelectionKey.OP_ACCEPT); // 接受连接事件
            } catch (ClosedChannelException ex) {
                try {
                    selector.close();
                } catch (IOException ignore) {}

                throw ex;
            }

            // Update object instance for later cleanup.
            this.selector = selector;

            while (!isStopped()) {                // while循环一直等待连接
                int count = selector.select(10);

                if (count == 0) {
                    continue;
                }

                Set<SelectionKey> keys = selector.selectedKeys();

                for (Iterator<SelectionKey> i = keys.iterator(); i.hasNext(); ) {   // 遍历通道事件
                    final SelectionKey key = i.next();
                    if (key.isAcceptable()) {        // 如果有连接事件
                        try {
                            SocketChannel sc = channel.accept();
                            if (sc != null) {
                                if (isStopped() || getAcceptListener() == null) {
                                    sc.close();
                                } else {
                                    if (useQueueForAccept) {
                                        socketQueue.put(sc.socket());          // 放入阻塞队列
                                    } else {
                                        handleSocket(sc.socket());             // 直接获取
                                    }
                                }
                            }

                        } catch (SocketTimeoutException ste) {
                            // expect this to happen
                        } catch (Exception e) {
                            e.printStackTrace();
                            if (!isStopping()) {
                                onAcceptError(e);
                            } else if (!isStopped()) {
                                LOG.warn("run()", e);
                                onAcceptError(e);
                            }
                        }
                    }
                    i.remove();
                }
            }
        } catch (IOException ex) {
            if (!isStopping()) {
                onAcceptError(ex);
            } else if (!isStopped()) {
                LOG.warn("run()", ex);
                onAcceptError(ex);
            }
        }
    }

如果是直接处理

    final protected void doHandleSocket(Socket socket) {
        boolean closeSocket = true;
        boolean countIncremented = false;
        try {
            int currentCount;
            do {
                currentCount = currentTransportCount.get();
                if (currentCount >= this.maximumConnections) {
                     throw new ExceededMaximumConnectionsException(
                         "Exceeded the maximum number of allowed client connections. See the '" +
                         "maximumConnections' property on the TCP transport configuration URI " +
                         "in the ActiveMQ configuration file (e.g., activemq.xml)");
                 }

            //Increment this value before configuring the transport
            //This is necessary because some of the transport servers must read from the
            //socket during configureTransport() so we want to make sure this value is
            //accurate as the transport server could pause here waiting for data to be sent from a client
            } while(!currentTransportCount.compareAndSet(currentCount, currentCount + 1));
            countIncremented = true;

            HashMap<String, Object> options = new HashMap<String, Object>();
            options.put("maxInactivityDuration", Long.valueOf(maxInactivityDuration));
            options.put("maxInactivityDurationInitalDelay", Long.valueOf(maxInactivityDurationInitalDelay));
            options.put("minmumWireFormatVersion", Integer.valueOf(minmumWireFormatVersion));
            options.put("trace", Boolean.valueOf(trace));
            options.put("soTimeout", Integer.valueOf(soTimeout));
            options.put("socketBufferSize", Integer.valueOf(socketBufferSize));
            options.put("connectionTimeout", Integer.valueOf(connectionTimeout));
            options.put("logWriterName", logWriterName);
            options.put("dynamicManagement", Boolean.valueOf(dynamicManagement));
            options.put("startLogging", Boolean.valueOf(startLogging));
            options.putAll(transportOptions);

            TransportInfo transportInfo = configureTransport(this, socket);
            closeSocket = false;

            if (transportInfo.transport instanceof ServiceSupport) {
                ((ServiceSupport) transportInfo.transport).addServiceListener(this);
            }

            Transport configuredTransport = transportInfo.transportFactory.serverConfigure(
                    transportInfo.transport, transportInfo.format, options);

            getAcceptListener().onAccept(configuredTransport);          // 调用上面置入的TransportAcceptListener的onAccept方法

        } catch (SocketTimeoutException ste) {
            // expect this to happen
        } catch (Exception e) {
            if (closeSocket) {
                try {
                    //if closing the socket, only decrement the count it was actually incremented
                    //where it was incremented
                    if (countIncremented) {
                        currentTransportCount.decrementAndGet();
                    }
                    socket.close();
                } catch (Exception ignore) {
                }
            }

            if (!isStopping()) {
                onAcceptError(e);
            } else if (!isStopped()) {
                LOG.warn("run()", e);
                onAcceptError(e);
            }
        }
    }
    @Override
    public void start() throws Exception {
        broker = brokerService.getBroker();
        brokerInfo.setBrokerName(broker.getBrokerName());
        brokerInfo.setBrokerId(broker.getBrokerId());
        brokerInfo.setPeerBrokerInfos(broker.getPeerBrokerInfos());
        brokerInfo.setFaultTolerantConfiguration(broker.isFaultTolerantConfiguration());
        brokerInfo.setBrokerURL(broker.getBrokerService().getDefaultSocketURIString());
        getServer().setAcceptListener(new TransportAcceptListener() {
            @Override
            // 调用到这个方法
            public void onAccept(final Transport transport) {
                try {
                    brokerService.getTaskRunnerFactory().execute(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                if (!brokerService.isStopping()) {
                                    Connection connection = createConnection(transport);
                                    connection.start();
                                } else {
                                    throw new BrokerStoppedException("Broker " + brokerService + " is being stopped");
                                }
                            } catch (Exception e) {
                                String remoteHost = transport.getRemoteAddress();
                                ServiceSupport.dispose(transport);
                                onAcceptError(e, remoteHost);
                            }
                        }
                    });
                } catch (Exception e) {
                    String remoteHost = transport.getRemoteAddress();
                    ServiceSupport.dispose(transport);
                    onAcceptError(e, remoteHost);
                }
            }

            @Override
            public void onAcceptError(Exception error) {
                onAcceptError(error, null);
            }

            private void onAcceptError(Exception error, String remoteHost) {
                if (brokerService != null && brokerService.isStopping()) {
                    LOG.info("Could not accept connection during shutdown {} : {}", (remoteHost == null ? "" : "from " + remoteHost), error);
                } else {
                    LOG.error("Could not accept connection {} : {}", (remoteHost == null ? "" : "from " + remoteHost), error);
                    LOG.debug("Reason: " + error, error);
                }
            }
        });
        getServer().setBrokerInfo(brokerInfo);
        getServer().start();

        DiscoveryAgent da = getDiscoveryAgent();
        if (da != null) {
            da.registerService(getPublishableConnectString());
            da.start();
        }
        if (enableStatusMonitor) {
            this.statusDector = new TransportStatusDetector(this);
            this.statusDector.start();
        }

        LOG.info("Connector {} started", getName());
    }

看看TcpTransportConnection的start方法

    @Override
    public void start() throws Exception {
        try {
            synchronized (this) {
                starting.set(true);
                if (taskRunnerFactory != null) {
                    taskRunner = taskRunnerFactory.createTaskRunner(this, "ActiveMQ Connection Dispatcher: "
                            + getRemoteAddress());
                } else {
                    taskRunner = null;
                }
                // 从下面的截图看看真实的实现类
                transport.start();
                active = true;
                BrokerInfo info = connector.getBrokerInfo().copy();
                if (connector.isUpdateClusterClients()) {
                    info.setPeerBrokerInfos(this.broker.getPeerBrokerInfos());
                } else {
                    info.setPeerBrokerInfos(null);
                }
                dispatchAsync(info);

                connector.onStarted(this);
            }
        } catch (Exception e) {
            // Force clean up on an error starting up.
            pendingStop.set(true);
            throw e;
        } finally {
            // stop() can be called from within the above block,
            // but we want to be sure start() completes before
            // stop() runs, so queue the stop until right now:
            setStarting(false);
            if (isPendingStop()) {
                LOG.debug("Calling the delayed stop() after start() {}", this);
                stop();
            }
        }
    }

这里写图片描述

会调用到TcpTransport的这个方法

    @Override
    protected void doStart() throws Exception {
        connect();
        stoppedLatch.set(new CountDownLatch(1));
        super.doStart();
    }
    protected void connect() throws Exception {

        if (socket == null && socketFactory == null) {
            throw new IllegalStateException("Cannot connect if the socket or socketFactory have not been set");
        }

        InetSocketAddress localAddress = null;
        InetSocketAddress remoteAddress = null;

        if (localLocation != null) {
            localAddress = new InetSocketAddress(InetAddress.getByName(localLocation.getHost()),
                                                 localLocation.getPort());
        }

        if (remoteLocation != null) {
            String host = resolveHostName(remoteLocation.getHost());
            remoteAddress = new InetSocketAddress(host, remoteLocation.getPort());
        }
        // Set the traffic class before the socket is connected when possible so
        // that the connection packets are given the correct traffic class.
        this.trafficClassSet = setTrafficClass(socket);

        if (socket != null) {

            if (localAddress != null) {
                socket.bind(localAddress);
            }

            // If it's a server accepted socket.. we don't need to connect it
            // to a remote address.
            if (remoteAddress != null) {
                if (connectionTimeout >= 0) {
                    socket.connect(remoteAddress, connectionTimeout);
                } else {
                    socket.connect(remoteAddress);
                }
            }

        } else {
            // For SSL sockets.. you can't create an unconnected socket :(
            // This means the timout option are not supported either.
            if (localAddress != null) {
                socket = socketFactory.createSocket(remoteAddress.getAddress(), remoteAddress.getPort(),
                                                    localAddress.getAddress(), localAddress.getPort());
            } else {
                socket = socketFactory.createSocket(remoteAddress.getAddress(), remoteAddress.getPort());
            }
        }

        initialiseSocket(socket);
        initializeStreams();
    }

启动TcpTransport的start方法

    protected void doStart() throws Exception {
        runner = new Thread(null, this, "ActiveMQ Transport: " + toString(), stackSize);
        runner.setDaemon(daemon);
        runner.start();
    }
    /**
     * reads packets from a Socket
     */
    @Override
    public void run() {
        LOG.trace("TCP consumer thread for " + this + " starting");
        this.runnerThread=Thread.currentThread();
        try {
            while (!isStopped()) {
                doRun();
            }
        } catch (IOException e) {
            stoppedLatch.get().countDown();
            onException(e);
        } catch (Throwable e){
            stoppedLatch.get().countDown();
            IOException ioe=new IOException("Unexpected error occurred: " + e);
            ioe.initCause(e);
            onException(ioe);
        }finally {
            stoppedLatch.get().countDown();
        }
    }

接收客户端的传过来的消息


    protected void doRun() throws IOException {
        try {
            Object command = readCommand();
            doConsume(command);
        } catch (SocketTimeoutException e) {
        } catch (InterruptedIOException e) {
        }
    }

连上之后,以下是broker从producter接收到的消息

WireFormatInfo { version=12, properties={MaxFrameSize=9223372036854775807, CacheSize=1024, ProviderVersion=5.14.6-SNAPSHOT, CacheEnabled=true, Host=localhost, ProviderName=ActiveMQ, SizePrefixDisabled=false, TcpNoDelayEnabled=true, PlatformDetails=JVM: 1.7.0_79, 24.79-b02, Oracle Corporation, OS: Windows 7, 6.1, amd64, MaxInactivityDurationInitalDelay=10000, MaxInactivityDuration=30000, TightEncodingEnabled=true, StackTraceEnabled=true}, magic=[A,c,t,i,v,e,M,Q]}
ConnectionInfo {commandId = 1, responseRequired = true, connectionId = ID:, clientId = ID:, clientIp = null, userName = null, password = , brokerPath = null, brokerMasterConnector = false, manageable = true, clientMaster = true, faultTolerant = false, failoverReconnect = false}
ConsumerInfo {commandId = 2, responseRequired = true, consumerId = ID:, destination = ActiveMQ.Advisory.TempQueue,ActiveMQ.Advisory.TempTopic, prefetchSize = 1000, maximumPendingMessageLimit = 0, browser = false, dispatchAsync = true, selector = null, clientId = null, subscriptionName = null, noLocal = true, exclusive = false, retroactive = false, priority = 0, brokerPath = null, optimizedAcknowledge = false, noRangeAcks = false, additionalPredicate = null}
KeepAliveInfo {}
SessionInfo {commandId = 3, responseRequired = false, sessionId = ID:}
ProducerInfo {commandId = 4, responseRequired = true, producerId = ID:, destination = topic://FirstTopic, brokerPath = null, dispatchAsync = false, windowSize = 0, sentCount = 0}
TransactionInfo {commandId = 5, responseRequired = false, type = 0, connectionId = ID:, transactionId = TX:ID:}
ActiveMQTextMessage {commandId = 6, responseRequired = false, messageId = ID:, originalDestination = null, originalTransactionId = null, producerId = , destination = topic://FirstTopic, transactionId = TX:ID:, expiration = 0, timestamp = 1524029198022, arrival = 0, brokerInTime = 0, brokerOutTime = 0, correlationId = null, replyTo = null, persistent = true, type = null, priority = 4, groupID = null, groupSequence = 0, targetConsumerId = null, compressed = false, userID = null, content = org.apache.activemq.util.ByteSequence@c80e39e, marshalledProperties = null, dataStructure = null, redeliveryCounter = 0, size = 0, properties = null, readOnlyProperties = false, readOnlyBody = false, droppable = false, jmsXGroupFirstForConsumer = false, text = ActiveMq 发送的消息}
RemoveInfo {commandId = 9, responseRequired = false, objectId = ID:, lastDeliveredSequenceId = -2}

消费消息时,进入transportsupport类的该方法, 然后会调用到TransportConnection上的设置的监听器transportListener。

    /**
     * Process the inbound command
     */
    public void doConsume(Object command) {
        if (command != null) {
        //transportListener是innactivitymonitor的实例
            if (transportListener != null) {
                transportListener.onCommand(command);
            } else {
                LOG.error("No transportListener available to process inbound command: " + command);
            }
        }
    }

看看Topic类的dispatch方法:

    protected void dispatch(final ConnectionContext context, Message message) throws Exception {
        // AMQ-2586: Better to leave this stat at zero than to give the user
        // misleading metrics.
        // destinationStatistics.getMessages().increment();
        destinationStatistics.getEnqueues().increment();
        destinationStatistics.getMessageSize().addSize(message.getSize());
        MessageEvaluationContext msgContext = null;

        dispatchLock.readLock().lock();
        try {
            if (!subscriptionRecoveryPolicy.add(context, message)) {
                return;
            }
            synchronized (consumers) {
                if (consumers.isEmpty()) {
                    onMessageWithNoConsumers(context, message);
                    return;
                }
            }

            // Clear memory before dispatch - need to clear here because the call to
            //subscriptionRecoveryPolicy.add() will unmarshall the state
            if (isReduceMemoryFootprint() && message.isMarshalled()) {
                message.clearUnMarshalledState();
            }

            msgContext = context.getMessageEvaluationContext();
            msgContext.setDestination(destination);
            msgContext.setMessageReference(message);
            if (!dispatchPolicy.dispatch(message, msgContext, consumers)) {
                onMessageWithNoConsumers(context, message);
            }

        } finally {
            dispatchLock.readLock().unlock();
            if (msgContext != null) {
                msgContext.clear();
            }
        }
    }

看看发送给订阅者的一个策略,轮询算法

/**
 * Simple dispatch policy that sends a message to every subscription that
 * matches the message.
 * 
 * @org.apache.xbean.XBean
 * 
 */
public class RoundRobinDispatchPolicy implements DispatchPolicy {

    /**
     * @param node
     * @param msgContext
     * @param consumers
     * @return true if dispatched
     * @throws Exception
     * @see org.apache.activemq.broker.region.policy.DispatchPolicy#dispatch(org.apache.activemq.broker.region.MessageReference,
     *      org.apache.activemq.filter.MessageEvaluationContext, java.util.List)
     */
    public boolean dispatch(MessageReference node,
            MessageEvaluationContext msgContext, List<Subscription> consumers)
            throws Exception {
        int count = 0;

        Subscription firstMatchingConsumer = null;
        synchronized (consumers) {
            for (Iterator<Subscription> iter = consumers.iterator(); iter
                    .hasNext();) {
                Subscription sub = iter.next();

                // Only dispatch to interested subscriptions
                if (!sub.matches(node, msgContext)) {
                    sub.unmatched(node);
                    continue;
                }

                if (firstMatchingConsumer == null) {
                    firstMatchingConsumer = sub;
                }

                sub.add(node);
                count++;
            }

            if (firstMatchingConsumer != null) {
                // Rotate the consumer list.
                try {
                    consumers.remove(firstMatchingConsumer);
                    consumers.add(firstMatchingConsumer);
                } catch (Throwable bestEffort) {
                }
            }
        }
        return count > 0;
    }
}

默认是SimpleDispatchPolicy

/**
 * Simple dispatch policy that sends a message to every subscription that
 * matches the message.
 * 
 * @org.apache.xbean.XBean
 * 
 */
public class SimpleDispatchPolicy implements DispatchPolicy {

    public boolean dispatch(MessageReference node, MessageEvaluationContext msgContext, List<Subscription> consumers)
            throws Exception {

        int count = 0;
        for (Subscription sub : consumers) {
            // Don't deliver to browsers
            if (sub.getConsumerInfo().isBrowser()) {
                continue;
            }
            // Only dispatch to interested subscriptions
            if (!sub.matches(node, msgContext)) {
                sub.unmatched(node);
                continue;
            }

            sub.add(node);
            count++;
        }

        return count > 0;
    }

}

看下面这行代码

sub.add(node);

执行到TopicSubscription类的add方法

执行到TransportConnection的dispatchAsync方法,可以看到其实是加到了dispatchQueue这个阻塞列表里,有一个专门的线程去执行。由上可知,对于topic而言,对于每条消息,会加入到所有的在线订阅者的队列上。如果订阅者不在线,是消费不到该消息的。


    @Override
    public void dispatchAsync(Command message) {
        if (!stopping.get()) {
            if (taskRunner == null) {
                dispatchSync(message);
            } else {
                synchronized (dispatchQueue) {
                    dispatchQueue.add(message);
                }
                try {
                    taskRunner.wakeup();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        } else {
            if (message.isMessageDispatch()) {
                MessageDispatch md = (MessageDispatch) message;
                TransmitCallback sub = md.getTransmitCallback();
                broker.postProcessDispatch(md);
                if (sub != null) {
                    sub.onFailure();
                }
            }
        }
    }

TaskRunner是一个线程池

    public TaskRunner createTaskRunner(Task task, String name) {
        init();
        ExecutorService executor = executorRef.get();
        if (executor != null) {
            return new PooledTaskRunner(executor, task, maxIterationsPerRun);
        } else {
            return new DedicatedTaskRunner(task, name, priority, daemon);
        }
    }

跑的任务实际上是下面的迭代器方法

    @Override
    public boolean iterate() {
        try {
            if (pendingStop.get() || stopping.get()) {
                if (dispatchStopped.compareAndSet(false, true)) {
                    if (transportException.get() == null) {
                        try {
                            dispatch(new ShutdownInfo());
                        } catch (Throwable ignore) {
                        }
                    }
                    dispatchStoppedLatch.countDown();
                }
                return false;
            }
            if (!dispatchStopped.get()) {
                Command command = null;
                synchronized (dispatchQueue) {
                    if (dispatchQueue.isEmpty()) {
                        return false;
                    }
                    command = dispatchQueue.remove(0);
                }
                processDispatch(command);
                return true;
            }
            return false;
        } catch (IOException e) {
            if (dispatchStopped.compareAndSet(false, true)) {
                dispatchStoppedLatch.countDown();
            }
            serviceExceptionAsync(e);
            return false;
        }
    }

猜你喜欢

转载自blog.csdn.net/YAOQINGGG/article/details/79912913
今日推荐