Reliable Data writer dropping messages due to slow Best Effort reader

2 posts / 0 new
Last post
Offline
Last seen: 1 day 9 hours ago
Joined: 09/07/2018
Posts: 11
Reliable Data writer dropping messages due to slow Best Effort reader

Hi all,

I have a reliable writer connected to a reliable reader and everything works fine.
However, when I add a slow Best Effort reader to the mix, the reliable reader starts losing messages.

I can see that the writer's write buffer (200) is full and the best effort reader's receive buffer (500) is also full and the writer is dropping messages because there is no room left in the write buffer.
But the reason I used best effort reliability on the slow reader is so that wouldn't happen.  Am I missing something?
Does the fact that there is a reliable reader present prevent the best effort reader from using best effort reliability and forcing a reliable connection?
Also, they are all using KEEP_LAST_HISTORY_QOS

Is there a way to make the best effort reader not block the reliable writer in this scenario?

PK_RTI's picture
Offline
Last seen: 20 hours 31 min ago
Joined: 07/01/2021
Posts: 32

I fed your question into our Connext Chatbot verbatim. Here's what it replied with:

No—the presence of a reliable reader does not turn the Best Effort reader into a reliable one. A reliable DataWriter can match both kinds of readers, but it runs the reliability protocol only for its reliable matches. The slow Best Effort reader does not ACK samples or cause retransmissions.

What you are seeing is instead a consequence of the reliable writer’s shared writer-side resources, especially its RTPS reliable-writer send window.

With a RELIABLE DataWriter and KEEP_LAST history:

  • The writer may overwrite old history samples when its history depth/resource limits are reached—even if they have not been acknowledged.
  • However, if data_writer_protocol.rtps_reliable_writer.max_send_window_size is finite and that send window becomes full, write() can block until samples are protocol-ACKed by the reliable reader(s), or until reliability.max_blocking_time expires.
  • Once that timeout expires under KEEP_LAST, Connext can replace older samples in the writer history. If the reliable reader has not received those samples yet, it will observe loss.

So the slow Best Effort reader’s full receive queue should cause that reader to drop data; it should not directly hold up reliable delivery. But its traffic can still consume shared transport/network capacity, CPU, or writer scheduling capacity enough that the reliable reader falls behind. Then the writer’s finite send window/history limits cause the reliable reader to lose older samples.

1. Keep the slow reader Best Effort

That is correct. Do not expect it to participate in reliable ACK/NACK behavior.

2. Prevent the reliable writer’s send window from throttling write()

For a RELIABLE + KEEP_LAST writer, configure the reliable-writer send window as unlimited if your design accepts bounded loss of older samples under overload:

<dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://community.rti.com/schema/7.7.0/rti_dds_qos_profiles.xsd" version="7.7.0"> <qos_library name="MyQosLibrary"> <qos_profile name="ReliableKeepLastNoSendWindowBlock"> <datawriter_qos> <reliability> <kind>RELIABLE_RELIABILITY_QOS</kind> <max_blocking_time> <sec>0</sec> <nanosec>0</nanosec> </max_blocking_time> </reliability> <history> <kind>KEEP_LAST_HISTORY_QOS</kind> <depth>200</depth> </history> <data_writer_protocol> <rtps_reliable_writer> <min_send_window_size> <value>LENGTH_UNLIMITED</value> </min_send_window_size> <max_send_window_size> <value>LENGTH_UNLIMITED</value> </max_send_window_size> </rtps_reliable_writer> </data_writer_protocol> </datawriter_qos> </qos_profile> </qos_library> </dds>
 

With the send window disabled, a RELIABLE + KEEP_LAST writer does not block because of a full send window. It can still overwrite old samples once its configured history/resource limits are reached—so this protects the publisher’s timing, not every historical sample.

3. Size the writer history for the reliable reader’s worst-case lag

If the reliable reader must receive every sample during a burst, KEEP_LAST depth 200 must cover its maximum backlog:

[ \text{required depth} \ge \text{publish rate} \times \text{maximum reliable-reader delay} ]

Also check RESOURCE_LIMITS.max_samples and max_samples_per_instance; those can cap the effective writer cache independently of HISTORY.depth.

4. Isolate the slow Best Effort consumer if it competes for bandwidth

If the slow reader is on a constrained link, consider one of these architectures:

  • Publish a separate Best Effort topic/DataWriter for that consumer.
  • Use a separate transport/interface, multicast group, or traffic class for the Best Effort stream.
  • Reduce the Best Effort reader’s requested rate using TIME_BASED_FILTER.
  • Use a bridge/Routing Service to decouple the slow consumer from the primary reliable path.

This avoids the Best Effort stream consuming enough shared network or host resources to make the reliable reader fall behind.

Important distinction

You cannot simultaneously guarantee every sample to the reliable reader and guarantee that the writer will never be delayed or constrained by that reader. If the reliable reader cannot keep up indefinitely, you must choose between:

  • Strict delivery: RELIABLE + KEEP_ALL, sufficient resources, and possible writer blocking; or
  • Bounded/latest-value delivery: RELIABLE + KEEP_LAST, sufficiently large depth, and acceptance that older samples may be overwritten during overload.

For your stated goal—do not let the slow Best Effort reader interfere—the Best Effort reader is already configured correctly. Focus on the reliable writer’s send-window configuration, writer-history sizing, and isolation of shared bandwidth/resources.

Sources: