与Netty一起使用时,骆驼ServicePool背后的逻辑

时间:2012-10-12 20:11:41

标签: java multithreading netty apache-camel

我有一个带有Netty端点的camel实例,它整合了许多传入请求以发送到单个接收器。更具体地说,这是一个Web服务,每个传入的SOAP请求都会导致Producer.sendBody()进入camel子系统。每个请求的处理涉及不同的路由,但它们都将在单个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]

这来自Netty组件使用的DefaultServicePoolDefaultServicePool使用ArrayBlockingQueue作为队列的后端,并将其设置为默认容量100 Producers。它出于性能原因使用服务池,以避免不得不继续创建和销毁经常重用的生产者。很公平。不幸的是,我没有弄清楚它是如何实现的。

这一切都从ProducerCache::doInAsyncProducer开始,通过调用doGetProducer开始。所述方法尝试从池中acquire生成器,如果失败,则使用endpoint.getProducer()创建新的生产者。然后使用pool.addAndAcquire确保服务池存在。完成后,它返回到调用函数。 doInAsyncProducer会完成它,直到它完成,在这种情况下它会调用done处理器。此时,我们完全处理了交换,因此它使用pool.release

将Producer释放回池中

这是橡胶在路上行驶的地方。 DefaultServicePool::release方法使用ArrayBlockingQueue将Producer插入add后端。这是我的java.lan.IllegalStateException来自的地方。

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

是吗?如果我正确读取,那么每当有超过100个同时请求时,此代码将始终失败。我的服务需要支持超过10,000个同时请求,因此不会飞。

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

  1. 在初始化时预分配所有100个制作人
  2. acquire期间阻止,直到制作人可用
  3. 如果使用ServicePool
  4. ,绝对不要创建自己的非池生产者

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

    我希望这个问题是要了解我是否正确地阅读了这个逻辑,看看它是否可以改变。或者,我使用它错了吗?有没有更好的方法来处理这类事情?

1 个答案:

答案 0 :(得分:0)

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