1

我有一个带有 Netty 端点的骆驼实例,它整合了许多传入请求以发送到单个接收器。更具体地说,这是一个 Web 服务,其中每个传入的 SOAP 请求都会导致Producer.sendBody()进入骆驼子系统。每个请求的处理涉及不同的路由,但它们都将最终在单个 Netty 端点中发送到下一级服务器。一切都很好,只要我在任何时候只有少数传入请求。但是,如果我开始有超过 100 个同时请求,我会收到以下异常:

java.lang.IllegalStateException: Queue full
    at java.util.AbstractQueue.add(AbstractQueue.java:71) ~[na:1.6.0_24]
    at java.util.concurrent.ArrayBlockingQueue.add(ArrayBlockingQueue.java:209) [na:1.6.0_24]
    at org.apache.camel.impl.DefaultServicePool.release(DefaultServicePool.java:95) [camel-core-2.9.2.jar:2.9.2]
    at org.apache.camel.impl.ProducerCache$1.done(ProducerCache.java:297) ~[camel-core-2.9.2.jar:2.9.2]
    at org.apache.camel.processor.SendProcessor$2$1.done(SendProcessor.java:120) ~[camel-core-2.9.2.jar:2.9.2]
    at org.apache.camel.component.netty.handlers.ClientChannelHandler.messageReceived(ClientChannelHandler.java:162) ~[camel-netty-2.9.2.jar:2.9.2]
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:296) ~[netty-3.3.1.Final.jar:na]

这来自DefaultServicePoolNetty 组件使用的那个。使用DefaultServicePoolanArrayBlockingQueue作为队列的后端,并将其设置为 100 个生产者的默认容量。出于性能原因,它使用服务池,以避免必须不断创建和销毁经常重用的生产者。很公平。不幸的是,我没有得到它是如何实现的逻辑。

这一切都始于ProducerCache::doInAsyncProducer,始于调用doGetProducer。所述方法尝试acquire从池中创建一个 Producer,如果失败,它会使用endpoint.getProducer(). 然后它确保服务池存在使用pool.addAndAcquire. 完成后,它返回到调用函数。在doInAsyncProducer它完成之前它会做它的事情,在这种情况下它会调用done处理器。至此,我们完全完成了交换的处理,所以它使用 Producer 将 Producer 释放回池中pool.release

这是橡胶上路的地方。该DefaultServicePool::release方法ArrayBlockingQueue使用add. 这就是我java.lan.IllegalStateException的来源。

为什么?好吧,让我们看一个用例。我有 101 个同时传入的请求。它们中的每一个都在大致相同的时间到达 Netty 端点。第一个创建容量为 100 的服务池,但启动时它是空的。事实上,这 101 个请求中的每一个都会从endpoint.getProducer;创建一个新的 Producer。每个都将验证它们不超过服务池的容量(为空);并且每个都将继续发送到服务器。每次完成后,它都会尝试执行pool.release. 前 100 个将成功,因为尚未达到池容量。第 101 个请求将尝试添加到队列中并且会失败,因为队列已满!

那正确吗?如果我没看错,那么只要有超过 100 个同时请求,这段代码就会失败。我的服务需要支持超过 10,000 个并发请求,所以这不会成功。

似乎更稳定的解决方案可能是:

  1. 在初始化时预分配所有 100 个生产者
  2. acquire在生产者可用之前阻塞
  3. 如果使用 ServicePool,绝对不要创建自己的非池生产者

与此同时,我正在考虑限制传入的请求。

我对这个问题的期望是了解我是否正确阅读了该逻辑并查看它是否可以更改。或者,我用错了吗?有没有更好的方法来处理这种类型的事情?

4

1 回答 1

0

是的,应该改进恕我直言的逻辑。我已经记录了一张票来改进这一点。 https://issues.apache.org/jira/browse/CAMEL-5703

于 2012-10-14T12:25:43.353 回答