目录
DDS丢包原因
今天的物联网系统通常需要数十万个并发数据点,在数千个端点之间以不同的配置进行通信。数据分发服务®(DDS)使这种复杂通信成为可能,诸如火箭发射、自动驾驶车辆、复杂机器人等应用都成为可能。在处理这些成千上万的数据点时,消息可能会被丢弃。那
么为什么会发生这种情况呢?DDS消息丢失的原因和解决方法是什么?
DDS实际上并不是“丢失”消息。可以将DDS有意地配置为在某些情况下不向数据订阅端发送消息。为了充分理解消息样本被丢弃的原因,我们首先区分涉及的不同情况。
首先,消息完全有可能是由网络或操作系统丢失的,而不是由DDS丢失的。在这种情况下,当使用DDS可靠性时,DDS订阅端将请求发布端重新发送消息。DDS自动纠正由网络丢弃的消息。
那么,为什么DDS有时会丢失一条消息呢?在这里,我们必须对“被拒绝的”样品和“丢失的”样品进行单独的区分。
当DataReader接收到一条消息,但没有足够的资源来接受它时,该消息将被DDS中间件丢弃。该消息可能仍然在DataWriter处排队,在这种情况下,根据可靠性设置,稍后可以重新传输它。因为消息可以被修复,所以该消息被认为是“被拒绝的”而不是“丢失的”。但是数据发布端对其资源也有限制,如果数据发布端继续发布数据,新的消息可能会覆盖尚未被数据写入器接收到的旧消息。在这种情况下,旧消息被认为是“丢失”的,也就是说:DataWriter无法为DataReader修复丢失的消息。
因此,有必要重申,DDS实际上并没有“丢失”消息。DDS被有意地配置为在某些条件下不向数据订阅端发送消息。用户可以通过许多不同的方式配置DDS,从而导致消息丢失(消息没有被传递)。
DDS(主动)删除消息的十大原因
以下是十大最常见的原因,从最常见到最不常见(也包括参考,如果可以,供进一步阅读):
1 .Best Effort
DDS可能丢失消息的最常见原因是,DataReader配置为最佳通信。最好的可靠性,通常有两种方式你可以发送消息:
无序示例:尽最大努力阅读的读者会丢弃任何比最近收到的消息更旧的消息。因此,在一个竭尽全力的阅读器接收消息7,然后是消息6和5的情况下,只有7将被发送到应用程序,消息5和消息6将被DDS丢弃。如果订单或到达是5、7、6,消息5和7将被传递到应用程序,而消息6将被删除,因为它比之前传递的消息7更老。但是,如果使用可靠的通信设置,就不会出现这种情况。不会丢弃任何消息——它们都将按照正确的顺序传递到应用程序。
读取器队列溢出:通过最大的努力进行通信,当数据读取器的队列满了并且接收到更多的消息时,旧的消息会被丢弃并丢失。它们不会被修复。
2 .KEEP_LAST
如果使用KEEP_LAST而不是严格可靠的服务质量(QoS), DDS可能会丢失消息。严格可靠性意味着启用可靠性QoS,历史类型设置为KEEP_ALL。如果可靠性是开启的,但历史类型是KEEP_LAST,那么消息可以被删除:
如果运行在同一种CPU/计算机上,数据写入器的写入速度通常比数据阅读器的处理速度快。
当DataReader的队列满时,新消息将替换队列中最老的消息。覆盖的消息将丢失。
在严格可靠模式下,如果读取器队列满了,数据写入器就会阻塞。消息将被拒绝,但不会被覆盖或删除,它们仍然可以被修复。
有关KEEP_ALL和KEEP_LAST history QoS的更多信息,请阅读本文:为什么DDS数据分发服务无法接收到所有数据样本。
3. 基于时间的过滤器或内容过滤的主题
如果使用了基于时间或基于内容的筛选器,DDS可能会删除消息,因为落入筛选器参数之外的消息将被删除。这些消息可能看起来是丢失的,但是不是数据写入器故意不发送的,就是被数据写入器丢弃的。
4 . Durability QoS未设置
当发送应用程序在接收应用程序准备就绪之前开始发送DDS消息时,消息将在启动时丢失。如果发送方(DataWriter)在接收方(DataReader)准备接收消息之前就开始了,那么DataReader可能会错过前几条消息。要避免这种情况,只需打开持久性QoS设置。当使用持久性时,DataWriter在其队列中保存N条消息(根据历史记录大小指定)。迟到者将会收到一些信息,因为他们的历史背景决定了他们错过了这些信息,但又被作者的历史所限制。
5. 发送队列已满
当到达DataWriter的max_blocking_time时,具有严格的可靠性,消息将不会被传递,并且看起来可能被删除。写操作将返回错误代码DDS_RETCODE_TIMEOUT,消息甚至不会传递到写队列。因此,被“丢弃”的消息永远不会被视为消息。它没有序列号,因此即使使用严格的可靠性,也不会被修复。还要注意,可以监视由于超过max_blocking_time而丢失的消息。这样用户就可以再次写消息了。因此,幸运的是这条消息没有“永远丢失”。
6. listener(侦听器)
在DDS中,由于使用侦听器而不是等待集来处理入站数据,消息可能会丢失。通常,侦听器将从仅有的几个中间件线程中的一个调用回调,这意味着一定要注意不要阻塞或执行任何长时间的处理。如果一个块在这个线程中发生,会有许多潜在的负面后果:
丢失安装侦听器的DataReader的数据,因为接收线程没有从套接字缓冲区中删除它,它被覆盖了;
接收严格可靠的数据有延迟,因为接收线程没有从套接字缓冲区中删除数据,如果数据被覆盖,就必须重新发送;
丢失或延迟其他数据查询器的数据,因为默认情况下,使用相同DomainParticipant创建的所有数据查询器共享相同的线程;
7 . 控制心跳并重发频率
控制心跳和重发指的是在不使用严格可靠性时达到max_heartbeat_retries的特定情况,在此期间,数据写入器将认为DataReader处于不活动状态,消息可能会丢失。此外,如果您的心跳速度太慢,而您正在使用KEEP_LAST,您可能没有时间在新样本到达前修复样本,在这种情况下,旧的将会丢失。
8 . 元素太多
通常,当序列或字符串定义为不同的长度时,它们是不可分配的。这意味着DDS将确定存在类型不匹配,这两种类型的dataReader和dataWriter将不允许通信。但是在ignore_sequence_bounds和ignore_string_bounds设置为TRUE后,这两种类型将成为可赋值的;但是,DataReader会删除已发布的大于最大长度的实际序列或字符串长度的样本。
9. 当使用IDL文件注释时
如果在IDL文件中使用了@range、@min或@max注释来限制消息值,那么由DataWriter发布的超出这些范围的消息将不会被DataReader接收。例如,DataReader在使用以下注释时将删除消息{x=170}: @range(min=100, max=150) long x。
读取器不会向应用程序提供该消息,因为x超出了有效范围[100,150]。
当DataReader删除一条消息时,Connext DDS会记录一个警告,但不会更新SAMPLE_ LOST或SAMPLE_REJECTED状态。
10. 使用destination_order QoS
当使用“由源时间戳”配置的destination_order QoS时,数据将由DataReader按照它被发送的顺序交付。如果一个实例的数据到达网络时源时间戳比上次交付数据的源时间戳早,那么新数据将被删除(如果时间戳差异大于source_timestamp_tolerance)。因此,当系统时钟在写入机器之间相对同步时,这种顺序工作得最好。
结论
在DDS通信期间,有很多原因导致消息被丢弃,或者看起来被丢弃。在所有情况下,无论是网络删除消息还是DDS删除消息,都可以配置DDS来解决这个问题。关键在于确定系统为什么会丢弃消息。