Taxa de transferência muito baixa usando o HornetQ Core Bridge
-
13-12-2019 - |
Pergunta
Estamos tentando usar o mecanismo de armazenamento e encaminhamento do HornetQ...entretanto, o encaminhamento de mensagens de uma instância autônoma do HornetQ para outra usando a ponte principal é muito lento.Não conseguimos aumentar a taxa de transferência acima de 200 mensagens por segundo.
O fato surpreendente é que se apontarmos o mesmo cliente (que estava publicando mensagens para a instância de encaminhamento do HornetQ) diretamente para a instância do HornetQ de destino, começaremos a observar uma taxa de transferência de mais de 1000 mensagens por segundo (este cliente é baseado em JMS).Isso basicamente significa que a ponte central configurada entre a instância Forwarding HornetQ e a instância Destination HornetQ é problemática.
A seguir estão as seções relevantes para configurar a ponte central no Forwarding HornetQ:
<connectors>
<connector name="netty-bridge">
<factory-class>org.hornetq.core.remoting.impl.netty.NettyConnectorFactory</factory-class>
<param key="host" value="destination.xxx.com"/>
<param key="port" value="5445"/>
<param key="batch-delay" value="50"/>
<param key="tcp-send-buffer-size" value="1048576"/>
<param key="tcp-receive-buffer-size" value="1048576"/>
<param key="use-nio" value="true"/>
</connector>
</connectors>
<address-settings>
<address-setting match="jms.queue.Record">
<dead-letter-address>jms.queue.RecordDLQ</dead-letter-address>
<max-size-bytes>262144000</max-size-bytes>
<page-size-bytes>10485760</page-size-bytes>
<address-full-policy>PAGE</address-full-policy>
</address-setting>
</address-settings>
<queues>
<queue name="jms.queue.Record">
<address>jms.queue.Record</address>
</queue>
</queues>
<bridges>
<bridge name="core-bridge">
<queue-name>jms.queue.Record</queue-name>
<forwarding-address>jms.queue.Record</forwarding-address>
<retry-interval>1000</retry-interval>
<retry-interval-multiplier>1.0</retry-interval-multiplier>
<reconnect-attempts>-1</reconnect-attempts>
<confirmation-window-size>10485760</confirmation-window-size>
<static-connectors>
<connector-ref>netty-bridge</connector-ref>
</static-connectors>
</bridge>
</bridges>
A seguir estão as seções relevantes para configurar a ponte principal no Destination HornetQ:
<acceptors>
<acceptor name="netty">
<factory-class>org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class>
<param key="host" value="${hornetq.remoting.netty.host:192.168.2.xxx}"/>
<param key="port" value="${hornetq.remoting.netty.port:xxxx}"/>
<param key="tcp-send-buffer-size" value="1048576"/>
<param key="tcp-receive-buffer-size" value="1048576"/>
<param key="use-nio" value="true"/>
<param key="batch-delay" value="50"/>
<param key="use-nio" value="true"/>
</acceptor>
<acceptors>
<address-settings>
<address-setting match="jms.queue.Record">
<dead-letter-address>jms.queue.RecordDLQ</dead-letter-address>
<max-size-bytes>262144000</max-size-bytes>
<page-size-bytes>10485760</page-size-bytes>
<address-full-policy>PAGE</address-full-policy>
</address-setting>
</address-settings>
<queues>
<queue name="jms.queue.Record">
<address>jms.queue.Record</address>
</queue>
</queues>
Todas as variáveis do sistema (CPU/Memória/E/S de disco/Rede/etc.) são subutilizadas e não há erros nos logs.
Observação:Tentamos tanto com o NIO quanto com o IO legado/antigo.Isso foi tentado com HornetQ-2.2.5-Final e HornetQ-2.2.8-GA (2.2.8-GA foi construído a partir do código-fonte)
Alguma ideia do que pode estar causando esse problema e qual pode ser a resolução?
Outras observações:Parece que as mensagens enviadas pela ponte principal são transacionais...então é possível agrupar essas transações em lote e fazer com que a comunicação entre as duas instâncias do HornetQ aconteça de forma assíncrona?
Solução
OK ..Eu descobri isso sozinho.
Quando o Forwarding HornetQ cria uma bridge, ele utiliza internamente apenas um thread para enviar as mensagens pela bridge e abre apenas uma conexão com o Destination HornetQ.Como tal, não é capaz de tirar partido de múltiplos processadores e também é limitado pela rede (latência/largura de banda/rtt) e não é capaz de paralelizar eficazmente o envio de mensagens.Dessa forma, se você tiver um alto rendimento, começará a atingir um limite (no nosso caso, cerca de 200 mensagens por segundo).Você pode aumentar isso ajustando os parâmetros do conector HornetQ e do aceitador (como os tamanhos do buffer de envio e recebimento do TCP) e as configurações da ponte (tamanho da janela de confirmação), mas isso só pode levar algum tempo (obtivemos a taxa de transferência de até cerca de 300 mensagens por segundo ).
A solução - criar múltiplas pontes entre o mesmo par de instâncias de encaminhamento e destino HornetQ (envolvendo as mesmas filas).Isso paraleliza efetivamente a transferência de mensagens e, assim, aumenta o rendimento.A criação de três pontes quase triplicou o rendimento para 870 mensagens por segundo.
Idealmente, o JBoss precisa tornar essa paralelização configurável na ponte central.
Outras dicas
Acredito que você estava usando o 2.2.5 (não está claro na sua postagem qual versão você estava usando), que tinha um bug nas pontes que causava o problema que você estava dizendo.
Em alguma versão, a ponte enviava mensagens de forma síncrona em vez de contar com confirmações assíncronas.
Dê uma olhada em como ele se comportaria na versão mais recente.