2011-02-23 159 views
5

我開發了一些基於JBoss + EJB的企業應用程序的一部分。我的模塊需要處理大量的傳入UDP數據包。我已經做了一些負載測試,看起來如果以11ms的間隔發送數據包,一切都很好,但是如果間隔爲10ms,一些數據包將丟失。這在我看來很奇怪,但是我多次進行10/11ms間隔負載測試比較,結果總是相同的(10毫秒 - 一些「丟失」數據包,11毫秒 - 一切正常)。「Lost」UDP數據包(JBoss + DatagramSocket)

如果出現同步問題,我希望在11ms測試(至少丟失一個包或者至少有一個錯誤的計數器值)的情況下也可以看到它。 所以,如果它不是因爲同步,那麼可能DatagramSocket通過我接收數據包不能按預期方式工作。

我發現接收緩衝區大小(SO_RCVBUF)具有默認的57344值(可能是底層IO網絡緩衝區相關)。我懷疑,也許當這個緩衝區滿了,然後新的傳入UDP數據報被拒絕。我試着將這個值設置得更高一些,但是我注意到如果誇大,緩衝區會返回到它的默認大小。如果它依賴於底層,我如何從JBoss級別找出某個OS /網卡的最大緩衝區大小?

它可能是由接收緩衝區大小引起的,或者可能是57344的值足夠大以處理大多數情況?你有這種問題的經驗嗎?

DatagramSocket沒有超時設置。我的UDP數據報包含大約70個字節的數據(沒有包含數據報頭的值)。

[編輯] 我必須使用UDP,因爲我收到Cisco Netflow數據 - 它是網絡設備用來發送一些流量統計信息的協議。另外,我對發送的字節格式沒有影響(例如,我不能爲數據包添加計數器等等)。預計不會處理所有數據包(有些數據報可能會丟失),但我希望我會處理大部分數據包。在10ms間隔測試期間,大約30%的數據包丟失。

緩慢的處理不太可能導致此問題。目前singleton組件在一個循環中持有對DatagramSocket調用接收方法的引用。收到數據包後,它將被傳遞到隊列,並通過從池無狀態組件中挑選出來進行處理。 「Facade」Singleton只負責接收數據包並將其傳遞給處理(它不會等待處理完成事件)。

由於提前, 彼得

+0

爲什麼你需要UDP?我會使用TCP,直到你有一個分析表明一個需要去UDP的飽和層。另外,我使用UDP的經驗是數據通常是重複的。 「這是目前的狀態。」所以不要擔心,如果你錯過了這個數據包,因爲另一個數據包即將推出! – corsiKa 2011-02-23 18:44:49

+0

「緩慢的處理不太可能導致此問題。」 - 我認爲是這樣,因爲10毫秒很小,與螺紋量程相同。 – ChrisW 2011-02-23 19:22:00

+0

10ms在不同的操作系統/處理器上可能會有所不同。你可以發送較少的數據,比如100ms嗎? – 2011-02-23 19:29:00

回答

3

UDP本質上是不可靠的。

數據報可以在發送者和接收者之間的任何點丟棄,即使是在低於你的代碼級別的接收者內。將recv緩衝區設置爲更大的大小很可能會幫助您的機器中的網絡代碼緩衝更多的數據報,但是您應該預料到某些數據報將會丟失。

如果您的recv邏輯花費的時間太長(即比新的數據報到達所需的時間更長),那麼您總是會落後,最終總是會錯過數據報。你所能做的就是確保你的recv代碼儘可能快地運行,也許把入站的數據報移動到一個隊列中,然後'稍後'或者在另一個線程上處理它,但是那樣會把你的問題轉移到你有一個問題的地方隊列不斷增長。

[重新編輯...]什麼是處理你的隊列以及生產者和消費者之間的鎖定工作是如何進行的?改變你的代碼,以便recv邏輯簡單地增加一個計數並丟棄數據並循環回去,看看你是否丟失了更少的數據報;無論哪種方式,UDP是不可靠的,你將有丟棄的數據報,你應該只是期待和處理它。擔心它意味着你專注於錯誤的問題;利用你得到的數據,並假設你不會得到太多的數據,然後你的程序將工作,即使網絡擁塞和你的數據報的大部分被丟棄。

綜上所述,這就是UDP如何。

+0

感謝您的回答。生產者持有對DatagramSocket的引用,生產者是JBossEJB3ext @Service bean(單例)。它調用while(true)循環阻塞接收方法。當它收到數據包時,通過AsyncUtils(異步調用)將DatagramSocket傳遞到合併的無狀態bean之一中。我將嘗試禁用處理並僅對傳入數據包進行計數,然後我會提供反饋。 – 2011-02-24 15:44:37

5

UDP不保證發送,所以你可以調整參數,但你不能保證該消息將被傳遞,特別是在非常大的數據傳輸的情況下。

如果您需要保證交付,您應該使用TCP代替。

如果您需要(或想要)使用UDP,您可以使用數字編碼每個數據包,併發送預期的數據包數量。例如,如果發送了10個大數據包,則可以包含以下信息:數據包1/10,數據包2/10等。這樣至少可以告訴您是否未收到所有數據包。如果你還沒有收到它們,你可以發送一個請求重新發送那些丟失的數據包。

+0

是的,只要您有大量傳輸,數據包將通過MTU。在這種情況下,數據包變得分散。使用UDP,不保證片段甚至可以按順序接收,但如果不是這種情況,底層協議(IP)將丟棄數據包,所以UDP永遠不會自己接收數據包。這就是爲什麼使用UDP的大數據包遠不如可靠 - 因爲UDP保留了邊界,所以在幕後會有更多的丟棄:) – 2011-02-23 18:45:01

+0

感謝您的回答,不幸的是,我對數據包的生成方式沒有影響(我也無法切換到TCP) - 請看看我編輯的帖子。 – 2011-02-23 18:58:09

2

它出現在你的測試中,最多隻有兩個數據包可以在緩衝區中,所以如果每個數據包小於28KB,這應該沒問題。

如您所知,UDP是有損的,但您應該能夠每10毫秒發送一個以上的數據包。我建議你寫一個簡單的接收器,它只是監聽數據包,以確定它的應用程序或網絡/操作系統級別的應用程序。 (我懷疑以後)

+0

是否有任何知道緩衝區溢出的方法。因爲我正在連續接收數據包,並且在長時間的運行過程中停止接收。這是因爲bufferoverflow。 – 2016-09-02 07:14:50

+0

@GeorgeThomas接收者不知道是否或爲什麼丟包。你只能通過實驗來確定。例如與包之間的大小或距離一起玩。 – 2016-09-02 07:16:18

+0

我不知道!我已經在android中實現了一個udp監聽器,並且我每1秒收到一個包。 Everthing工作正常,但工作一段時間後,它完全停止。我會嘗試更改大小和距離並嘗試 – 2016-09-02 07:20:17

1

我不知道Java,但......這個API允許你調用一個非同步監聽/接收數據報:

  • 使用O/S API做接收(通過你的應用程序級緩存爲paremeter)
  • (請稍候,沒有什麼接受...)
  • (O/S接收來自網絡的東西...)
  • O/S放收到數據包到緩衝區並完成/返回您的API調用

如果這是真的,那麼我建議你做幾個併發的API調用實例,以便有多個併發的應用程序級緩衝區可以接收多個數據包。

+0

感謝您的答案。目前,使用單身外觀 - 它擁有對DatagramSocket的引用。它在循環中調用receive()方法 - 它是阻塞操作。如果接收到數據報,則將其傳遞給處理組件(共用無狀態bean)。容器管理同步。我認爲這種方法可以防止同步問題,並且具有可擴展性。只有一個DatagramSocket實例被允許(綁定每個IP和端口)。 – 2011-02-23 19:07:31

+0

@Piotrek我建議你嘗試改變它:而不是一個同步/阻塞操作,嘗試做多個異步/非阻塞操作......以便O/S具有多個併發應用程序級緩衝區,可以接收多個數據包。 – ChrisW 2011-02-23 19:11:36