我有一个Spring应用程序,它消耗特定端口上的消息(比如9001),重新构造它们然后转发到Rabbit MQ服务器。代码段是:
private void send(String routingKey, String message) throws Exception {
String exchange = applicationConfiguration.getAMQPExchange();
String exchangeType = applicationConfiguration.getAMQPExchangeType();
Connection connection = myConnection.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(exchange, exchangeType);
channel.basicPublish(exchange, routingKey, null, message.getBytes());
log.debug(" [CORE: AMQP] Sent message with key {} : {}",routingKey, message);
}
如果Rabbit MQ服务器出现故障(崩溃,RAM耗尽,关闭等),则上面的代码会阻塞,阻止上游服务接收消息(这是一件坏事)。我正在寻找一种方法来防止这种行为,同时不会丢失消息,以便在将来的某个时候它们可以被重新发送。
我不确定如何最好地解决这个问题。一个选项可能是将消息排队到磁盘文件,然后使用单独的线程读取并转发到Rabbit MQ服务器?
答案 0 :(得分:1)
如果我理解正确,那么您所描述的问题是在写入中断连接时已知的JDK套接字行为。请参阅此邮件列表主题:http://markmail.org/thread/3vw6qshxsmu7fv6n。
请注意,如果关闭RabbitMQ,则应以客户端可以快速观察的方式关闭TCP连接。但是,过时的TCP连接确实可以采用 有一段时间需要检测,这就是为什么RabbitMQ的核心协议有心跳。设置心跳 间隔为低值(例如,6-8),客户端本身会注意到无响应的对等体 在这段时间内。
您需要使用发布商确认[1],但也要考虑应用程序本身的事实 可以在发送消息之前向下发送。正如你正确指出的那样,拥有一个基于磁盘的 WAL(预写日志)是此问题的常见解决方案。请注意,它是完全相同的 棘手的做法仍然离开一些时间窗口,你的应用程序进程关闭可能会导致未发布和未记录的消息。
在时间框架上没有任何承诺,但已经讨论了将WAL添加到Java客户端的想法。