2011-02-23 64 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