簡體   English   中英

Spring集成-適用於大批量應用的可靠TCP

[英]Spring Integration - Reliable TCP for high volume application

我正在使用Spring Integration for TCP服務器,該服務器保持與數千個客戶端的連接。 我需要服務器在過多負載的情況下限制客戶端,而不丟失消息。

我的服務器配置:

<task:executor id="myTaskExecutor"
    pool-size="4-8"
    queue-capacity="0"
    rejection-policy="CALLER_RUNS" />

<int-ip:tcp-connection-factory id="serverTcpConFact"
    type="server"
    port="60000"
    using-nio="true"
    single-use="false"
    so-timeout="300000"
    task-executor="myTaskExecutor" />

<int-ip:tcp-inbound-channel-adapter id="tcpInboundAdapter"
    channel="tcpInbound"
    connection-factory="serverTcpConFact" />

<channel id="tcpInbound" />

<service-activator input-channel="tcpInbound"
    ref="myService"
    method="test" />

<beans:bean id="myService" class="org.test.tcpserver.MyService" />

由於連接工廠的默認任務執行程序是無界的,因此我使用池化任務執行程序來防止內存不足錯誤。

一個用於負載測試的簡單客戶端:

public class TCPClientTest {
    static Socket socket;
    static List<Socket> sl = new ArrayList<>();
    static DataOutputStream out;

    public static void main(String[] args) throws Exception {
        for (int i = 0; i < 10000; i++) {
            socket = new Socket("localhost", 60000);
            sl.add(socket);
            out = new DataOutputStream(socket.getOutputStream());
            out.writeBytes("connection " + i + "\r\n");
            System.out.println("Using connection #" + i);
        }
        System.in.read();
    }
}

當我運行它時,服務器僅收到大約10-20條消息,然后客戶端會收到“拒絕連接:連接”異常。 之后,即使連接超時后,服務器也無法再接受任何新連接。 增加池的大小只會幫助獲得更多消息。

編輯

我正在使用Spring Integration 3.0.2.RELEASE。 對於生產環境,我使用的是8-40個線程,但只有經過數百次連接后,它才會使此測試稍后失敗。

MyService.test()做不了什么...

public class MyService {
    public void test(byte[] input) {
        System.out.println("Received: " + new String(input));
    }
}

這是帶有跟蹤級別日志記錄的日志。

來源

我知道問題出在哪里,請打開JIRA問題

問題是執行程序中的CALLER_RUNS拒絕策略的隊列長度為0

有一個線程可以處理所有IO事件(通常是myTaskExecutor-1 ); 當讀取事件觸發時,他將執行排隊以讀取數據; 閱讀器線程將執行的執行排隊以組裝數據(該數據將阻塞,直到收到完整的消息(在您的情況下為CRLF終止)為止)。

在這種情況下,如果沒有可用的線程,則CALLER_RUNS策略意味着IO選擇器線程將進行讀取,並成為匯編器線程,該匯編器線程將阻止等待不會到達的數據,因為他被阻止了,以后會讀取該數據安排另一個線程進行阻塞之后。 因為他被阻止,所以他無法處理新的接受事件。

這是我的測試記錄,顯示了該問題...

TRACE: [May-18 10:43:38,923][myTaskExecutor-1] tcp.connection.TcpNioServerConnectionFactory - Port 60000 SelectionCount: 2
DEBUG: [May-18 10:43:38,923][myTaskExecutor-1] tcp.connection.TcpNioConnection - localhost:58509:60000:bdc36c59-c31b-470e-96c3-6270e7c46a2f Reading...
DEBUG: [May-18 10:43:38,924][myTaskExecutor-1] tcp.connection.TcpNioConnection - localhost:58509:60000:bdc36c59-c31b-470e-96c3-6270e7c46a2f Running an assembler
TRACE: [May-18 10:43:38,924][myTaskExecutor-1] tcp.connection.TcpNioConnection - localhost:58509:60000:bdc36c59-c31b-470e-96c3-6270e7c46a2f Nio message assembler running...
DEBUG: [May-18 10:43:38,926][myTaskExecutor-1] tcp.serializer.ByteArrayCrLfSerializer - Available to read:0

第二行顯示了用於執行讀取操作的選擇器線程。 他檢測到此套接字需要一個匯編程序,並成為匯編程序,阻塞並等待數據。

您是否真的相信使用無限制的任務執行器會出現問題? 這些事件通常壽命很短,因此線程將很快被回收。

將執行程序的隊列容量增加到0以上也應該有所幫助,但不能完全確保不會發生問題(盡管不太可能遇到較大的隊列大小)。

除了為IO選擇器和讀取器線程使用專用的任務執行器之外,我還不確定如何解決此問題,因此它們永遠不會用作匯編程序。

昨天,我確實編寫了一個示例,只是使用spring集成來創建tcp高性能服務器代碼。 我使用JMeter TCP采樣器成功地對1000個並發客戶端請求進行了測試。

這是代碼-https: //github.com/rajeshgheware/spring-integration-samples,其中包括JMeter測試配置文件。

我在具有Intel Core i5 M520 2.4GHz的64位筆記本電腦上成功地測試了1000個並發tcp客戶端請求(服務器代碼和JMeter測試均在此計算機上運行)

我還嘗試了1500個並發客戶端請求,但是發現服務器不能滿足許多​​請求。 我將繼續嘗試增強此代碼以服務10000個並發客戶端請求(我知道我可能需要從亞馬遜那里獲得良好的EC2計算機以進行此測試:))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM