Транзакционный компонент JMS и верблюжий маршрут - PullRequest
1 голос
/ 16 февраля 2020

Пройдя книгу «Верблюд в действии», я обнаружил следующие сомнения:

У меня есть 2 маршрута ниже

A.
from("file:/home/src") //(A.1) .transacted("required") //(A.2) .bean("dbReader", "readFromDB()") //(A.3) only read from DB .bean("dbReader", "readFromDB()") //(A.4) only read from DB .to("jms:queue:DEST_QUEUE") //(A.5)

Вопросы:
Aa Действительно ли здесь требуется транзакция в (A.2)?

Ab Если ответ на #a - «да», то каким должен быть связанный диспетчер транзакций «требуемой» политики? Должно ли это быть JmsTransactionManager или JpaTransactionManager?

A. c. Так как DEST_QUEUE находится на стороне производителя, необходимо ли выполнять транзакции с компонентом JMS в (A.5)?

B. from("jms:queue:SRC_QUEUE") //(B.1) transactional jms endpoint .transacted("required") //(B.2) .bean("someBean", "someMethod()") //(B.3) simple arithmetic computation .to("jms1:queue:DEST_QUEUE") //(B.4)

SRC_QUEUE и DEST_QUEUE - очереди различных брокеров jms

Вопросы:

Ba Компонент JMS в (B.1) помечен как обработанный, поэтому в этом В случае, если маршрут должен быть обработан, как указано в (B.2)?

Bb Так как DEST_QUEUE находится на стороне производителя, то нужно ли выполнять транзакцию для компонента JMS в (B.4)?

Ответы [ 2 ]

0 голосов
/ 10 марта 2020

Добрый день,

Я бы хотел уделить минуту, чтобы ответить на ваши вопросы. Я отвечу на вопросы со стороны «B».

WRT:

Ba Компонент JMS в (B.1) помечен как обработанный, поэтому в этом случае необходимо выполнить маршрутизацию как упомянуто в (B.2)?

Да. И исходный, и целевой компоненты должны быть помечены как транзакционные. Если пометить компоненты как транзакционные, начнутся локальные транзакции JMS в исходном и целевом сеансах. Обратите внимание, что это две отдельные локальные JMS-транзакции, которые управляются двумя отдельными JmsTransactionManager.

Пометка маршрута как «транзакционного» запустит контекст транзакции JTA. Обратите внимание, что PlatformTransactionManager должен быть JtaTransactionManager. Когда вызывается компонент «to», локальная транзакция JMS для отправки сообщения будет синхронизирована с локальной транзакцией для получения сообщения. (JTA синхронизировал транзакции). Это означает, что отправка получит обратный вызов, когда удаленный посредник подтвердит принятие для отправки. В этот момент полученное сообщение будет зафиксировано. Это транзакционное поведение 'dups OK' (не XA). У вас есть окно, в которое было отправлено сообщение, но получение не было подтверждено.

На самом деле получить эту работу сложно. Вот пример:

<!-- ******************** Camel route definition ********************* -->
<camelContext allowUseOriginalMessage="false"
    id="camelContext-Bridge-Local" streamCache="true" trace="true" xmlns="http://camel.apache.org/schema/blueprint">
    <route id="amq-to-amq">
        <from id="from" uri="amqLoc:queue:IN"/>
        <transacted id="trans"/>
        <to id="to" uri="amqRem:queue:OUT"/>
    </route>
</camelContext>
<!-- ********************* Local AMQ configuration ************************** -->
<bean class="org.apache.activemq.camel.component.ActiveMQComponent" id="amqLoc">
    <property name="configuration">
        <bean class="org.apache.camel.component.jms.JmsConfiguration">
            <property name="connectionFactory" ref="AmqCFLocalPool"/>
            <property name="receiveTimeout" value="100000"/>
            <property name="maxConcurrentConsumers" value="3"/>
            <property name="cacheLevelName" value="CACHE_NONE"/>
            <property name="transacted" value="true"/>
        </bean>
    </property>
</bean>
<bean class="org.apache.activemq.jms.pool.PooledConnectionFactory" id="AmqCFLocalPool">
    <property name="maxConnections" value="1"/>
    <property name="idleTimeout" value="0"/>
    <property name="connectionFactory" ref="AmqCFLocal"/>
</bean>
<bean class="org.apache.activemq.ActiveMQConnectionFactory" id="AmqCFLocal">
    <property name="brokerURL" value="tcp://10.0.0.170:61616?jms.prefetchPolicy.all=0"/>
    <property name="userName" value="admin"/>
    <property name="password" value="admin"/>
</bean>
<!-- ********************* Remote AMQ configuration ************************** -->
<bean class="org.apache.activemq.camel.component.ActiveMQComponent" id="amqRem">
    <property name="configuration">
        <bean class="org.apache.camel.component.jms.JmsConfiguration">
            <property name="connectionFactory" ref="AmqCFRemotePool"/>
            <property name="transacted" value="true"/>
        </bean>
    </property>
</bean>
<bean class="org.apache.activemq.jms.pool.PooledConnectionFactory"
    destroy-method="stop" id="AmqCFRemotePool" init-method="start">
    <property name="maxConnections" value="1"/>
    <property name="idleTimeout" value="0"/>
    <property name="connectionFactory" ref="AmqCFRemote"/>
</bean>
<bean class="org.apache.activemq.ActiveMQConnectionFactory" id="AmqCFRemote">
    <property name="brokerURL" value="tcp://10.0.0.171:61616"/>
    <property name="userName" value="admin"/>
    <property name="password" value="admin"/>
</bean>

Включить ведение журнала DEBUG для org.springframework.jms.connection.JmsTransactionManager и ведение журнала уровня DEBUG / TRACE для используемого вами менеджера транзакций JTA.

0 голосов
/ 20 февраля 2020

Очень хорошие вопросы, чтобы поговорить об обработке транзакций Camel.

Общее замечание: когда речь идет о транзакциях Camel, это означает потребление транзакций из системы с поддержкой транзакций , такой как база данных или JMS-брокер. Оператор transacted в маршруте должен следовать сразу за оператором from, поскольку он всегда связан с потреблением .

Aa. Транзакция выполняется в (A.2) действительно требуется здесь?

Нет, это не так. Поскольку файловая система не поддерживает транзакции , она не может помочь в этом маршруте.

Ab Если ответом на #a является "да", то ...?

Нет "менеджера транзакций файловой системы"

A . c. Так как DEST_QUEUE находится на стороне производителя, то нужно ли выполнять транзакции с компонентом JMS в (A.5)?

Не уверен, но я так не думаю. Производитель пытается передать сообщение брокеру. Транзакции используются для включения отката , но если посредник не получил данные, что может сделать откат?

Ba Компонент JMS в (B.1) помечен как транзакционный, поэтому в этом случае необходимо ли выполнять маршрут, как указано в (В.2)?

Это зависит , поскольку SR C и DEST находятся на разных брокерах .

  • Если вы хотите сквозную транзакцию между брокерами, вам нужно использовать менеджер XA-транзакций, а затем вы должны пометить маршрут как transacted.
  • Если вы в порядке с потребительской транзакцией , вы можете настроить для него компонент JMS и опустить диспетчер Spring Tx и оператор Camel transacted.

Чтобы прояснить последний момент: если вы используете транзакцию с локальным брокером, Camel не фиксирует сообщение, пока маршрут не будет успешно обработан . Поэтому, если произойдет какая-либо ошибка, произойдет откат, и сообщение будет доставлено.

В большинстве случаев это совершенно нормально, однако, что еще может произойти с двумя разными брокерами, это то, что маршрут успешно обработан, сообщение доставлено брокеру DEST, но Camel больше не может коммитить против SR C брокер. Затем происходит повторная доставка, маршрут обрабатывается еще раз, и сообщение доставляется несколько раз брокеру DEST .

По моему мнению, сложность транзакций XA сложнее, чем очень редкие крайние случаи с транзакциями локальных брокеров. Но это очень субъективное мнение и, возможно, также зависит от контекста или данных, с которыми вы работаете.

И важно отметить: , если SR C и DEST-брокер совпадают, транзакции локального брокера на 100%! Абсолютно нет необходимости в Spring Tx manager и Camel transacted.

Bb Поскольку DEST_QUEUE находится на стороне производителя, то же самое нужно для компонента JMS в (B.4) быть сделанным?

То же, что и ответ Ba

...