我有以下情况: 生产者有3个rabbitmq队列,根据消息的优先级向其发送消息。(myqueue_high,myqueue_medium,myqueue_low) 我希望有一个单一的消费者,它可以按顺序或优先级从这些队列中提取,即只要消息存在,它就会一直从高位队列中拉出来。 o / w它从媒介中拉出来。如果介质也是空的,则从低位拉出。
我如何实现这一目标?我需要编写自定义组件吗?
答案 0 :(得分:4)
将所有消息放入一个队列但具有不同优先级会更容易。这样,优先级排序将在代理中完成,Camel使用者将获得已按优先级排序的消息。但是,RabbitMQ实现了FIFO原则,并且还不支持优先级处理。
解决方案1
Camel允许您使用Resequencer基于某个比较器重新组织消息:https://camel.apache.org/resequencer.html:
from("rabbitmq://hostname[:port]/myqueue_high")
.setHeader("priority", constant(9))
.to("direct:messageProcessing");
from("rabbitmq://hostname[:port]/myqueue_medium")
.setHeader("priority", constant(5))
.to("direct:messageProcessing");
from("rabbitmq://hostname[:port]/myqueue_low")
.setHeader("priority", constant(1))
.to("direct:messageProcessing");
// sort by priority by allowing duplicates (message can have same priority)
// and use reverse ordering so 9 is first output (most important), and 0 is last
// (of course we could have set the priority the other way around, but this way
// we keep align with the JMS specification...)
// use batch mode and fire every 3th second
from("direct:messageProcessing")
.resequence(header("priority")).batch().timeout(3000).allowDuplicates().reverse()
.to("mock:result");
这样,所有传入的消息都被路由到相同的子路由(direct:messageProcessing
),其中消息根据传入路由设置的priority
报头重新排序。
解决方案2
将SEDA与优先排序队列一起使用:
final PriorityBlockingQueueFactory<Exchange> priorityQueueFactory = new PriorityBlockingQueueFactory<Exchange>();
priorityQueueFactory.setComparator(new Comparator<Exchange>() {
@Override
public int compare(final Exchange exchange1, final Exchange exchange2) {
final Integer prio1 = (Integer) exchange1.getIn().getHeader("priority");
final Integer prio2 = (Integer) exchange2.getIn().getHeader("priority");
return -prio1.compareTo(prio2); // 9 has higher priority then 0
}
});
final SimpleRegistry registry = new SimpleRegistry();
registry.put("priorityQueueFactory", priorityQueueFactory);
final ModelCamelContext context = new DefaultCamelContext(registry);
// configure and start your context here...
路线定义:
from("rabbitmq://hostname[:port]/myqueue_high")
.setHeader("priority", constant(9))
.to("seda:priority?queueFactory=#priorityQueueFactory"); // reference queue in registry
from("rabbitmq://hostname[:port]/myqueue_medium")
.setHeader("priority", constant(5))
.to("seda:priority?queueFactory=#priorityQueueFactory");
from("rabbitmq://hostname[:port]/myqueue_low")
.setHeader("priority", constant(1))
.to("seda:priority?queueFactory=#priorityQueueFactory");
from("seda:priority")
.to("direct:messageProcessing");
解决方案3
如果在出现故障时需要持久性,请使用JMS,例如Camel的ActiveMQ组件而不是SEDA。只需将传入的消息从RabbitMQ转发到JMS目标,并设置JMSPriority
标题。
解决方案4
完全跳过RabbitMQ,只需使用支持优先级的ActiveMQ等JMS代理。