我在春季启动中有一个兔子 amqp 侦听器,它在不关闭应用程序的情况下保持不变

Posted

技术标签:

【中文标题】我在春季启动中有一个兔子 amqp 侦听器,它在不关闭应用程序的情况下保持不变【英文标题】:I have an rabbit amqp listener in springboot, It stucks without closing the application 【发布时间】:2019-05-31 14:40:04 【问题描述】:

我的实际代码中有以下代码 sn-p。我有多个消费者在听队列。

 @RabbitListener
 private void abc(ETLConfigDTO config)
  try
   log.info("load started");
   loadService.loadData(config);
  
  catch(Exception e)
   log.error("Load failed"):
  
  finally
   log.info("finished processing"):
  
 

loadData() 需要几分钟到几个小时的处理时间。它的一种etl处理。此方法内部有密集的日志记录,因此我知道该过程处于哪个状态。 问题是该过程有点卡在 loadPlans() 方法中。队列中的消息处于未确认状态,因为它仍在处理我需要的那种方式。 没有例外,因为 catch 没有打印任何内容,甚至没有打印 finally 块。 我在同一个班级也有一个 spring cron(5 分钟间隔),它也运行良好并完成了它的任务。

需要注意的是,如果我不使用rabbit amqp,它运行良好。

是否有任何连接/网络中断?或者任何超时?还是主线程挂起/死了?我真的不明白这里发生了什么。

提前致谢。

更新: 谢谢加里, 我在jstack 19 看到这个:

"SimpleAsyncTaskExecutor-1" #25 prio=5 os_prio=0 tid=0x00007f5615b3d800 nid=0x2f runnable [0x00007f56703cd000]
   java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
        at java.net.SocketInputStream.read(SocketInputStream.java:171)
        at java.net.SocketInputStream.read(SocketInputStream.java:141)
        at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
        at sun.security.ssl.InputRecord.read(InputRecord.java:503)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:983)
        - locked <0x000000067a6bada8> (a java.lang.Object)
        at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:940)
        at sun.security.ssl.AppInputStream.read(AppInputStream.java:105)
        - locked <0x000000067a6baea0> (a sun.security.ssl.AppInputStream)
        at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
        at java.io.BufferedInputStream.read1(BufferedInputStream.java:286)
        at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
        - locked <0x000000067a717cb8> (a java.io.BufferedInputStream)
        at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:735)
        at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:678)
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1569)
        - locked <0x000000067a6b4b60> (a sun.net.www.protocol.https.DelegateHttpsURLConnection)
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1474)
        - locked <0x000000067a6b4b60> (a sun.net.www.protocol.https.DelegateHttpsURLConnection)
        at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:338)
        at org.springframework.http.client.SimpleClientHttpResponse.getRawStatusCode(SimpleClientHttpResponse.java:48)
        at org.springframework.http.client.AbstractClientHttpResponse.getStatusCode(AbstractClientHttpResponse.java:33)
        at org.springframework.web.client.DefaultResponseErrorHandler.getHttpStatusCode(DefaultResponseErrorHandler.java:56)
        at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:50)
        at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:602)
        at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:570)
        at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:530)
        at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:448)
..
...
...
...


Please advise.

新更新: 我已经增加内存 -XX:MaxMetaspaceSize=1024M -Xms4096M -Xmx4096M

线程现在卡在oracle连接上。

"SimpleAsyncTaskExecutor-1" #25 prio=5 os_prio=0 tid=0x00007ff6102c8800 nid=0x33 runnable [0x00007ff619ad9000]
   java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
        at java.net.SocketInputStream.read(SocketInputStream.java:171)
        at java.net.SocketInputStream.read(SocketInputStream.java:141)
        at oracle.net.ns.Packet.receive(Packet.java:300)
        at oracle.net.ns.DataPacket.receive(DataPacket.java:106)
        at oracle.net.ns.NetInputStream.getNextPacket(NetInputStream.java:315)
        at oracle.net.ns.NetInputStream.read(NetInputStream.java:260)
        at oracle.net.ns.NetInputStream.read(NetInputStream.java:185)
        at oracle.net.ns.NetInputStream.read(NetInputStream.java:102)
        at oracle.jdbc.driver.T4CSocketInputStreamWrapper.readNextPacket(T4CSocketInputStreamWrapper.java:124)
        at oracle.jdbc.driver.T4CSocketInputStreamWrapper.read(T4CSocketInputStreamWrapper.java:80)
        at oracle.jdbc.driver.T4CMAREngine.unmarshalUB1(T4CMAREngine.java:1137)
        at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:290)
        at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192)
        at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531)
        at oracle.jdbc.driver.T4CStatement.doOall8(T4CStatement.java:193)
        at oracle.jdbc.driver.T4CStatement.executeForRows(T4CStatement.java:1033)
        at oracle.jdbc.driver.OracleStatement.executeBatch(OracleStatement.java:4536)
        - locked <0x00000007b01c6b20> (a oracle.jdbc.driver.T4CConnection)
        at oracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:230)
        at org.springframework.jdbc.core.JdbcTemplate$1BatchUpdateStatementCallback.doInStatement(JdbcTemplate.java:572)
        at org.springframework.jdbc.core.JdbcTemplate$1BatchUpdateStatementCallback.doInStatement(JdbcTemplate.java:559)
        at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:405)
        at org.springframework.jdbc.core.JdbcTemplate.batchUpdate(JdbcTemplate.java:611)
...
...

【问题讨论】:

你能发布属性文件吗? 我已经通过 beans 配置了 rabbit 【参考方案1】:

你的听众很不寻常;在大多数情况下,它是void listen(SomeObject),侦听器处理对象并退出并确认消息。

您似乎忽略了消息的内容,只是利用它的存在来触发loadData()

无论如何,默认情况下,在方法退出之前不会确认消息;容器线程将一直保留在侦听器方法中,直到它退出。

容器的默认确认模式是 AUTO,这意味着容器将在方法退出时自动确认(或拒绝)消息。

您可以将确认模式更改为 NONE,这意味着 RabbitMQ 根本不需要确认,并且会立即删除消息。

但是,容器线程仍然会在方法中运行,直到方法退出。

如果应用程序崩溃,消息将会丢失。

【讨论】:

很抱歉更新了监听器,它正在读取消息并在 loadData() 中处理它 那么问题是什么?正如我所说,在加载完成和侦听器退出之前不确认消息是正常的,除非您将确认模式更改为 NONE。 问题是主线程卡在 loadData() 中,它不应该......它永远留在那里.. 但这是您的代码,与框架无关,因此我们无能为力 - 进行线程转储以查看它在做什么。 我该怎么做?有没有办法记录线程活动?

以上是关于我在春季启动中有一个兔子 amqp 侦听器,它在不关闭应用程序的情况下保持不变的主要内容,如果未能解决你的问题,请参考以下文章

Spring AMQP v1.4.2 - 网络故障时的兔子重新连接问题

AMQP - 兔子 MQ 使用

春季启动运行Angular2

短片《魔术师和兔子》

春季启动部署

Spring AMQP:由于缺少回复属性,从 POJO 侦听器发送回复失败