我们在某些RabbitMQ队列上有一个使用者,它读取消息,然后在Elasticsearch中对这些数据编制索引。使用spring-amqp完成实现。为了提高性能,我们计划在消费者级别聚合消息,并在Elasticsearch中进行批量插入(这样可以提高性能)。
你对如何实现这个有什么消息吗?另外,另一个敏感问题是如何处理响应。每条消息都有一个" reply_to"我们使用带有回复通道的入站网关,因此对于每条消息都应该传递一个响应。
我正在考虑使用Spring集成中的聚合器,以及基于批量大小和MessageGroupStore过期时间(当然还有收割者)的发布策略。入站网关的任务执行程序为20,并且预取计数也为20。每当请求到来时,该消息将被添加到组存储中,并且当canRelease()条件正常时,该请求附带的其中一个线程的收割者将执行批量操作。但是我对其他线程做了什么,它将不得不等待永远不会发生的响应。此外,我不知道如何打破大型聚合消息的响应,因此每个小请求都会有响应。
另一个问题,我该如何确认消息?从我读到的事务中,会降低RabbitMQ方面的性能,所以我对使用" tx-size"属性。如果超时太小,此属性也可能执行错误计数。
答案 0 :(得分:1)
关于消费者和聚合者的问题的答案:
使用来自AMQP和聚合的消息的配置。 聚合策略基于Transction提交:
<amqp:inbound-channel-adapter queue-names="myQueue"
transaction-manager="transactionManager"
channel-transacted="true"
channel="aggregateChannel"
advice-chain="aggregatorReaperAdvice"
concurrent-consumers="4"
tx-size="100"/>
<aggregator input-channel="aggregateChannel" output-channel="storeChannel"
expire-groups-upon-completion="true"
correlation-strategy-expression="T(Thread).currentThread().id"
release-strategy-expression="^[payload.equals(@AGGREGATOR_RELEASE_MARK)] != null"
expression="?[!payload.equals(@AGGREGATOR_RELEASE_MARK)].![payload]"/>
ReaperAdvice
(Groovy代码):
@Service
class AggregatorReaperAdvice implements MethodBeforeAdvice, InitializingBean {
private static final TRANSACTION_RESOURCE_MARK = 'TRANSACTION_RESOURCE_MARK'
public static final AGGREGATOR_RELEASE_MARK = 'AGGREGATOR_RELEASE_MARK'
MessagingTemplate messagingTemplate
@Autowired
MessageChannel aggregateChannel
@Override
void afterPropertiesSet() throws Exception {
Assert.notNull aggregateChannel, "aggregateChannel must not be null"
messagingTemplate = new MessagingTemplate(aggregateChannel)
}
@Override
void before(Method method, Object[] args, Object target) {
if (!TransactionSynchronizationManager.hasResource(AggregatorReaperAdvice)) {
TransactionSynchronizationManager.bindResource(AggregatorReaperAdvice, TRANSACTION_RESOURCE_MARK)
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
void beforeCommit(boolean readOnly) {
messagingTemplate.send(MessageBuilder.withPayload(AGGREGATOR_RELEASE_MARK).build())
}
@Override
void afterCompletion(int status) {
TransactionSynchronizationManager.unbindResource(AggregatorReaperAdvice)
}
})
}
}
}
如果不清楚,请告诉我。
所有其他问题,很快就会得到解决。
对于manual ack
,您可以在channel.basicAck(deliveryTag, true);
上使用ack
- deliveryTag
用于所有之前的消息。
对于headers["reply_to"]
案例......我认为您应该为AbstractAggregatingMessageGroupProcessor
提供自定义aggregator
并杀死两只鸟:聚合器的累积结果和MessageGroup.getMessages()
上的迭代将每个人的回复流程发送到提供的MessageChannel
。它是您案例的快速解决方案。
类似但松散耦合的解决方案可能基于聚合器及其MessageGroupStore
的结果,您可以在其中提取correlationKey
以检索组及其消息以执行所需的reply
逻辑。在这种情况下,您不应该使用聚合器从商店中删除组,而是在该组检索后手动删除。