使用多线程和通道,rabbitmq发布时,线程全部被阻止

时间:2018-02-11 05:45:36

标签: java multithreading rabbitmq

我在我的生物环境中发现了一个问题。

我们在一个mq集群中有6个队列,我们​​有200个线程的线程池(实际上它将更多,因为它将在独立的线程池中安排一些特殊任务)来处理来自上游的请求,当处理请求时,我将向rabbitmq经纪人发布消息。

所以我有200个线程将消息发布到这6个队列。

对于每个队列,我将创建一个AMQP连接,并且对于每个线程,我有一个Channel的线程局,因此每个线程可以拥有自己的通道而不同步,因为通道不是线程安全的。

所以,实际上,我将打开1200个频道。请求qps大约是4000 / s,在某个特殊时间会有点大。

但是我发现200个线程都已耗尽,而且大多数都处于阻塞状态,如:

    DubboServerHandler-10.12.26.124:9000-thread-200 - priority:10 - threadId:0x00007f6708030800 - nativeId:0x680d - state:BLOCKED
    stackTrace:
    java.lang.Thread.State: BLOCKED (on object monitor)
    at com.rabbitmq.client.impl.SocketFrameHandler.writeFrame(SocketFrameHandler.java:170)
    - waiting to lock <0x0000000738ad0190> (a java.io.DataOutputStream)
    at com.rabbitmq.client.impl.AMQConnection.writeFrame(AMQConnection.java:542)
    at com.rabbitmq.client.impl.AMQCommand.transmit(AMQCommand.java:104)
    - locked <0x000000074e085338> (a com.rabbitmq.client.impl.CommandAssembler)
    at com.rabbitmq.client.impl.AMQChannel.quiescingTransmit(AMQChannel.java:337)
    - locked <0x000000074656eeb0> (a java.lang.Object)
    at com.rabbitmq.client.impl.AMQChannel.transmit(AMQChannel.java:313)
    - locked <0x000000074656eeb0> (a java.lang.Object)
    at com.rabbitmq.client.impl.ChannelN.basicPublish(ChannelN.java:686)
    at com.rabbitmq.client.impl.ChannelN.basicPublish(ChannelN.java:668)
    at com.rabbitmq.client.impl.ChannelN.basicPublish(ChannelN.java:658)
    at com.rabbitmq.client.impl.recovery.AutorecoveringChannel.basicPublish(AutorecoveringChannel.java:192)

这是我的jstack报告:http://fastthread.io/my-thread-report.jsp?p=c2hhcmVkLzIwMTgvMDIvMTEvLS0yNjE3OS50eHQtLTMtNTMtMzg=

我的问题是:

  1.Why I have different channels to publish but they are all trying acquire the same lock
  2.What will be the cause for this since this only happens tens of times in a day
  3. Do I use a poor implementations for this? How can I improve it.

1 个答案:

答案 0 :(得分:0)

  1. 查看源代码,每个连接都有一个SocketFrameHandler。套接字帧处理程序在这里的writeFrame方法https://github.com/rabbitmq/rabbitmq-java-client/blob/master/src/main/java/com/rabbitmq/client/impl/SocketFrameHandler.java上同步输出流。这基本上意味着如果您有200个通道(每个线程一个)共享一个连接,由于write方法中的同步,只有一个线程能够一次发送数据。
  2. 我不确定。您通常每秒向rabbitmq发送多少条消息?是否有一天中的时间段,您发送的消息很少,而其他时段您发送了许多消息?
  3. 由于SocketFrameHandler中的同步,我认为每个连接有多个线程和通道没有任何好处。尝试重构您的应用程序,以便需要发送的任何数据被送入内存队列,一个线程负责从队列中读取数据并将数据发送到rabbitmq。通过这种方式,您可以让许多线程正在工作并生成数据,而一个线程负责发送它。