![](/img/trans.png)
[英]Spring Integration TCP connection refused under multithreaded load/stress testing
[英]Spring Integration DSL Tcp: How to prevent excessive logging of Connection refused on the client side
我使客戶端和服務器都能夠等待彼此連接,因此它們可以以任何順序獨立啟動。 此處描述的解決方案確實做到了這一點,即開箱即用,BUT客戶端始終使用java.net.ConnectException: Connection refused: connect
將大量的堆棧跟蹤打印到我們的日志中java.net.ConnectException: Connection refused: connect
,然后是46行長的堆棧跟蹤,直到服務器啟動並連接發生。 這是不理想的。
我的問題是:如何應用我的自定義邏輯來微調要記錄的內容和時間。
到目前為止,我發現日志是由org.springframework.integration.handler.LoggingHandler
打印的。 這充當一種錯誤通道,錯誤總是在此分發。 我找不到這套設備在哪里,因此可以用自己的實現替換它。 我設法配置了自己的默認錯誤通道,但是該通道是與預配置的LoggingHandler通道一起添加的,而不是替換它。
另一種方法是在發送第一條消息時設置更長的超時時間。 我也在為此而苦苦掙扎。 我試圖將它設置為outboundGateway
,作為.handle(Tcp.outboundGateway(clientConnectionFactory).remoteTimeout(1_000_000L))
但是沒有任何效果。
好,解決了
問題實際上不是LoggingHandler
或任何錯誤通道中的問題,但是如果服務器尚未立即准備就緒,則org.springframework.integration.ip.tcp.connection.TcpNetClientConnectionFactory.createSocket()
會引發異常,然后TcpOutboundGateway
將其記錄為老式的異常方式; 只有這樣,錯誤才會被分發到errorChannel
,在此可以對其作出反應; 並且默認的SI反應是再次打印它:)那是我最初沒有注意到的,該異常記錄了兩次。 可以通過使用自定義錯誤消息處理程序來防止第二個日志,但不能使用第一個。
TcpNetClientConnectionFactory.createSocket()
調用默認Java的createSocket(),並且沒有設置超時的選項。 如果接收者尚未准備好,則方法調用幾乎立即失敗。 請參閱JDK的增強請求JDK-4414843 。
可能的解決方案是重寫TcpNetClientConnectionFactory.createSocket()
以重復到服務器的連接嘗試,直到成功為止。
WaitingTcpNetClientConnectionFactory
public class WaitingTcpNetClientConnectionFactory extends TcpNetClientConnectionFactory {
private final SocketConnectionListener socketConnectionListener;
private final int waitBetweenAttemptsInMs;
private final Logger log = LogManager.getLogger();
public WaitingTcpNetClientConnectionFactory(
String host, int port,
int waitBetweenAttemptsInMs,
SocketConnectionListener socketConnectionListener) {
super(host, port);
this.waitBetweenAttemptsInMs = waitBetweenAttemptsInMs;
this.socketConnectionListener = socketConnectionListener;
}
@Override
protected Socket createSocket(String host, int port) throws IOException {
Socket socket = null;
while (socket == null) {
try {
socket = super.createSocket(host, port);
socketConnectionListener.onConnectionOpen();
} catch (ConnectException ce) {
socketConnectionListener.onConnectionFailure();
log.warn("server " + host + ":" + port + " is not ready yet ..waiting");
try {
Thread.sleep(waitBetweenAttemptsInMs);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new IOException("interrupted while wating between connection attempts", ie);
}
}
}
return socket;
}
}
作為額外的獎勵,我還設置了我自己的自定義接口SocketConnectionListener
成功或失敗,因此應用程序的其他部分可以與其同步; 例如,等待流傳輸,直到服務器/對等節點准備就緒。
使用WaitingTcpNetClientConnectionFactory
方式與TcpNetClientConnectionFactory
相同。
HeartbeatClientConfig (僅相關位):
@Bean
public TcpNetClientConnectionFactory clientConnectionFactory(
ConnectionStatus connectionStatus) {
TcpNetClientConnectionFactory connectionFactory = new WaitingTcpNetClientConnectionFactory("localhost", 7777, 2000, connectionStatus);
connectionFactory.setSerializer(new ByteArrayLengthHeaderSerializer());
connectionFactory.setDeserializer(new ByteArrayLengthHeaderSerializer());
return connectionFactory;
}
現在它只打印:
INFO [ main] o.b.e.d.s.h.client.HeartbeatClientRun : Started HeartbeatClientRun in 1.042 seconds (JVM running for 1.44)
WARN [ask-scheduler-1] h.c.WaitingTcpNetClientConnectionFactory : server localhost:7777 is not ready yet ..waiting
WARN [ask-scheduler-1] h.c.WaitingTcpNetClientConnectionFactory : server localhost:7777 is not ready yet ..waiting
WARN [ask-scheduler-1] h.c.WaitingTcpNetClientConnectionFactory : server localhost:7777 is not ready yet ..waiting
WARN [ask-scheduler-1] h.c.WaitingTcpNetClientConnectionFactory : server localhost:7777 is not ready yet ..waiting
和往常一樣,完整的項目資源都可以在我的git上找到, 這是相關的commit 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.