简体   繁体   English

将消息从本地经纪人传递到不连贯的中央经纪人

[英]Deliver message from a local broker to a disconected central broker

I have a specific requirement where i need to send message to a server which won't always be available. 我有一个特殊的要求,我需要向服务器发送消息,但该消息并不总是可用。

For this i used a network of brokers, specific to ActiveMQ. 为此,我使用了特定于ActiveMQ的经纪人网络。

The goal is to have a local application A (producer only) which will push message to another central application B (consumer only). 目的是拥有一个本地应用程序A(仅生产者),它将消息推送到另一个中央应用程序B(仅消费者)。 However network won't always be available. 但是,网络并不总是可用。 So application's A broker have to store messages and wait for connection before it can send message to application B. SO basically A is a proxy which need to forward message to B when it is available 因此,应用程序的A代理必须存储消息并等待连接,然后才能向应用程序B发送消息。因此,基本上,A是代理,当可用时,需要将消息转发给B

Broker's B configuration includes a durable topic which is listening on in order to consume message. Broker的B配置包括一个持久主题,该主题正在侦听以使用消息。

As said in ActiveMQ's documentation i have to use a static network bridge to do that, which is what i did. 如ActiveMQ的文档所述,我必须使用静态网桥来执行此操作,这就是我所做的。

Note : i can't have B subscribe to A, because there will be multiple instance of A and i can't configure all of them in B. 注意:我不能让B订阅A,因为将有A的多个实例,而我不能在B中配置所有它们。

So here is my configuration (raw spring) for local application : 这是本地应用程序的配置(原始弹簧):

<!--As said in http://activemq.apache.org/spring-support.html use 
    a pooled conntection along with JMSTemplate -->
 <amq:connectionFactory id="jmsFactory" brokerURL="${jms.broker.local.url}" />
<!--SpringJMSTemplate -->
<bean id="myJmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="jmsFactory" />
</bean>
<!-- local broker with embedded -->
<bean id="localbroker" class="org.apache.activemq.broker.BrokerService"
    init-method="start" destroy-method="stop">
    <property name="brokerName" value="localBroker" />
    <property name="transportConnectorURIs">
        <list>
            <value>${jms.broker.local.url}</value>
        </list>
    </property>
    <property name="networkConnectors">
        <list>
            <ref bean="networkConnector" />
        </list>
    </property>
</bean>

<amq:connectionFactory id="remoteJmsFactory"
    brokerURL="${jms.broker.remote.url}" clientIDPrefix="BRIDGED-TEST" />

<bean id="networkConnector" class="org.apache.activemq.network.DiscoveryNetworkConnector">
    <property name="uri" value="static:(${jms.broker.remote.url})"></property>
    <property name="staticallyIncludedDestinations">
        <list>
            <bean class="org.apache.activemq.command.ActiveMQTopic">
                <constructor-arg type="java.lang.String" value="${jms.topic.sample}"/>
            </bean>
        </list>
    </property>
    <property name="staticBridge" value="true"></property><!-- will deliver content even if no consumer, usefull for durable topic only -->
</bean>

The localbroker is an embedded broker connecting to a remote broker (the application you can download from apacheMQ page). localbroker是连接到远程代理(可以从apacheMQ页下载的应用程序)的嵌入式代理。

Here is the central configuration 这是中央配置

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <value>file:${activemq.conf}/credentials.properties</value>
    </property>
</bean>


<bean id="logQuery" class="io.fabric8.insight.log.log4j.Log4jLogQuery"
      lazy-init="false" scope="singleton"
      init-method="start" destroy-method="stop">
</bean>

<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}" useVirtualDestSubs="true">

    <destinationPolicy>
        <policyMap>
          <policyEntries>
            <policyEntry topic=">" >
              <pendingMessageLimitStrategy>
                <constantPendingMessageLimitStrategy limit="1000"/>
              </pendingMessageLimitStrategy>
            </policyEntry>
          </policyEntries>
        </policyMap>
    </destinationPolicy>
    <managementContext>
        <managementContext createConnector="false"/>
    </managementContext>
    <persistenceAdapter>
        <kahaDB directory="${activemq.data}/kahadb"/>
    </persistenceAdapter>
      <systemUsage>
        <systemUsage>
            <memoryUsage>
                <memoryUsage percentOfJvmHeap="70" />
            </memoryUsage>
            <storeUsage>
                <storeUsage limit="100 gb"/>
            </storeUsage>
            <tempUsage>
                <tempUsage limit="50 gb"/>
            </tempUsage>
        </systemUsage>
    </systemUsage>
    <transportConnectors>
        <transportConnector name="http" uri="http://0.0.0.0:61612?maximumConnections=1000&amp;wireFormat.maxFrameSize=10485760"/>
    </transportConnectors>
    <shutdownHooks>
        <bean xmlns="http://www.springframework.org/schema/beans" class="org.apache.activemq.hooks.SpringContextHook" />
    </shutdownHooks>

</broker>
<import resource="jetty.xml"/>

So what is happening when i try to send/receive messages : 所以当我尝试发送/接收消息时发生了什么:

  • If the producer (A) is connected and consumer (B) is connected to their respective broker, and the broker are connected together it works fine. 如果生产者(A)已连接且消费者(B)已连接至其各自的经纪人,并且经纪人已连接在一起,则可以正常工作。
  • If the consumer (B) is connected to his broker and there is message pending, while producer A's broker is disconnected, it works fine. 如果消费者(B)已连接到其经纪人,并且有待处理的消息,而生产者A的经纪人已断开连接,则它可以正常工作。
  • If the producer (A) is disconnected from network, A's broker won't deliver the message to B's broker when B is available again. 如果生产者(A)与网络断开连接,则当B再次可用时,A的代理不会将消息传递给B的代理。

Before network connectors i tried jmsbridgeConnector using outboundTopicBridge in local broker configuration without any luck. 在使用网络连接器之前,我在本地代理配置中使用outboundTopicBridge尝试了jmsbridgeConnector,没有任何运气。

Here is the question : how do i get local's broker A send message to central's broker B on reconnect. 这是一个问题:重新连接时,我如何让本地的经纪人A向中央的经纪人B发送消息。 And while it is not available, be sure that he won't lost any message. 并且尽管它不可​​用,请确保他不会丢失任何消息。

Note : 注意 :

  • The network which i work on is not alaways available (can be for days !), and i can rely only on http port, this is why it is the only one openned. 我正在工作的网络不可用(可能要几天 !),而且我只能依靠http端口,这就是为什么它是唯一打开的。 This means that no multicast discovery is possible. 这意味着不可能进行多播发现。
  • Message must be deliver only once. 消息只能传递一次。
  • The reason why i use local broker is to not manage what i have to send myself. 我使用本地经纪人的原因是为了不管理自己必须发送的内容。 They're only, at the moment, used to store and forward to the central. 目前,它们仅用于存储并转发到中央。

EDIT : i have been able to make it working using a JMS Bridge, however i have a last problem, if the connection os lost at application booting or during application lifecycle, i need to restart my broker to be able to send messages. 编辑:我已经能够使用JMS Bridge使其工作,但是我有最后一个问题,如果在应用程序启动或应用程序生命周期中失去连接os,我需要重新启动代理才能发送消息。

I've been using this "store and forward" pattern with success using bridge. 我一直在使用桥成功地使用这种“存储并转发”模式。

I can not comment for network connector but for bridge, you have to : 对于网络连接器,我无法评论,但对于网桥,您必须:

  • use a recent version of jmeter due to Bug AMQ-5859 由于错误AMQ-5859而使用最新版本的jmeter
  • add a org.apache.activemq.network.jms.ReconnectionPolicy on the bridge 在网桥上添加org.apache.activemq.network.jms.ReconnectionPolicy
  • make sure you set the reconnectOnException on the remote broker connection factory 确保您在远程代理连接工厂上设置了reconnectOnException

I have try all the way around and can't get it works using only configuration so i end up doing that myself : 我已经尝试了所有方法,但仅使用配置无法使其正常工作,所以我最终自己做了:

<jms:listener-container container-type="default" factory-id="proxyFactory"
    acknowledge="transacted" destination-type="topic" connection-factory="jmsFactory">

<bean id="remoteJmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="remoteJmsFactory" />
    <property name="pubSubDomain" value="true"/>
</bean>
<bean id="simpleMessageProxyListener"
    class="com.xxx.jms.test.SimpleMessageProxyListener">
    <property name="jmsTemplate" ref="remoteJmsTemplate" />
    <property name="queueName" value="${jms.topic.sample}" />
</bean>

Basically i just have a class that subscribe to the local broker with a durable subscription, and send message to the remote, if it fails, session is rollbacked. 基本上我只有一个类,该类通过持久订阅来订阅本地代理,然后将消息发送到远程,如果失败,则回滚会话。

That simple proxy rely on Spring Listener's container, so it may be ably to work even if he listen on a remote broker, in my case, it's listening on a local embedded broker, so i won't have any problem. 这个简单的代理依赖于Spring Listener的容器,因此即使他侦听远程代理,它也可以正常工作,在我的情况下,它侦听本地嵌入式代理,所以我不会有任何问题。

If someone else have a only-configuration answer that works when stopping/starting the remote broker while local application live and don't need a restart to send the messages, feel free to post it, i will upvote and check. 如果在本地应用程序处于活动状态时停止/启动远程代理时其他人具有唯一配置的答案,并且不需要重新启动即可发送消息,请随时发布,我将投票并检查。

Note : you must set jms.redeliveryPolicy.maximumDeliveries to -1 to have it working. 注意:必须将jms.redeliveryPolicy.maximumDeliveries设置为-1才能使其正常工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM