我使用redis作为队列(使用spring queue-in / outbound-channel-adapter)来分配任务(消息进入队列等)
由于吞吐量非常高,我们观察到,尽管消息被发送到redis队列,但很多消息都丢失了,并且在入站(头路由器)之后没有消息到达组件
频道配置附在下方;关键是我们虽然问题是在入站addapter之后的这个头路由器中,但是无法管理从队列中读取的消息的速率,所以它们丢失了。
我们在入站适配器和此组件(即标头路由器)之间使用了一个中间元素,并添加了一个队列来解决此问题。
这很好,但实际上我们并不完全理解解决方案,如果这是正确的解决方案。
有关此配置的专家观点和意见将会很好!
由于
<!-- a Queue Inbound Channel Adapter is available to 'right pop' messages
from a Redis List. -->
<redis:queue-inbound-channel-adapter
id="fromRedis" channel="in" queue="${name}"
receive-timeout="1000" recovery-interval="3000" expect-message="true"
auto-startup="true"/>
<!-- a queue to avoid lost messages before the header router -->
<int:channel id="in">
<int:queue capacity="1000"/>
</int:channel>
<!-- a bridge to connect channels and have a poller -->
<int:bridge input-channel="in" output-channel="out">
<int:poller fixed-delay="500" />
</int:bridge>
<int:header-value-router id="router" timeout="15000"
input-channel="out" header-name="decision"
resolution-required="false" default-output-channel="defaultChannel" />
---于2002年2月新增
要将消息插入redis,我们有一个Web服务,但实际上就像你说的那样,只需将消息写入redis(
for... channel.send(msg)
没有更多
关于你的回答我现在正在考虑删除in通道及其队列,并直接使用header-value-router;但我还有更多问题:
我认为正确的解决方案是header-value-router中的超时值较低,因此如果我们没有可用的消费者,我会更快地获得错误通知。如果我不使用值作为超时,它将无限期地阻止,这是一个坏主意,不是吗?
我不知道如何管理MesssageDeliveryException,因为路由器没有错误通道配置,???
我认为如果我可以管理此错误并收到消息,我可以再次将其重新发送给redis。还有其他服务器从redis获取消息,幸运的是他们可以参加。
我添加了我提出的解决方案,但还没有完成,我们不确定错误管理,如上所述
<!-- a Queue Inbound Channel Adapter is available to 'right pop' messages
from a Redis List. -->
<redis:queue-inbound-channel-adapter
id="fromRedis" channel="in" queue="${name}"
receive-timeout="1000" recovery-interval="3000" expect-message="true"
auto-startup="true"/>
<!-- a header-value-router with quite low timeout -->
<int:header-value-router id="router" timeout="150"
input-channel="in" header-name="decision"
resolution-required="false" default-output-channel="defaultChannel" />
<!-- ¿if MessageDeliveryException???? what to do??? -->
<int:channel id="someConsumerHeaderValue">
<int:dispatcher task-executor="ConsumerExecutor" />
</int:channel>
<!-- If 5 threads are busy we queue messages up to 5; if queue is full we can increase to 5 more working threads; if no more threads we have a... ¿¿MessageDeliveryException?? -->
<task:executor id="ConsumerExecutor" pool-size="5-5"
queue-capacity="5" />
答案 0 :(得分:1)
嗯,很高兴看到这样的观察。这可能会以某种方式改进框架。
所以,我想看看:
从Framework透视图重现的一些测试用例。 虽然我猜有足够的信息可以向Redis发送大量消息并使用你的配置来消费。 (如果有其他需要,请纠正我)
<int:header-value-router>
之后的下游流程。你看,你使用的timeout="15000"
是send-timeout
的同义词:
指定等待的最长时间(以毫秒为单位) 在阻止时将消息发送到目标MessageChannels 是可能的(例如当前已满的有界队列信道)。 默认情况下,发送将无限期阻止。 &#39; timeout&#39;的同义词 - 只能提供一个。
从这里我可以说,如果您的下游消费者在某些QueueChannel
上足够慢,那么您最终会得到:
/**
* Inserts the specified element at the tail of this queue, waiting if
* necessary up to the specified wait time for space to become available.
*
* @return {@code true} if successful, or {@code false} if
* the specified waiting time elapses before space is available
* @throws InterruptedException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public boolean offer(E e, long timeout, TimeUnit unit)
....
while (count.get() == capacity) {
if (nanos <= 0)
return false;
nanos = notFull.awaitNanos(nanos);
}
注意return false;
完全表示message lost
。
这也像back-pressure drop
策略一样。
如果你有不同的照片,请告诉我。
您可以考虑删除timeout="15000"
以满足相同的in
队列通道行为。
<强>更新强>
嗯,错误处理的工作方式有点不同。 &#34;有罪&#34;组件只是抛出异常,就像使用原始Java一样,这个组件对于由调用者负责的异常捕获负责是可以的。
在我们的案例中,调用者是上游组件 - <redis:queue-inbound-channel-adapter>
。
任何入站通道适配器都有error-channel
选项。通过<poller>
MessageSource
或直接MessageProducer
。
我相信你能够处理:
if (!sent) {
throw new MessageDeliveryException(message,
"failed to send message to channel '" + channel + "' within timeout: " + timeout);
}
在error-channel
子流程中,实现您的恢复要求。