Topic · Cookbook

Transport-Tuning Cookbook

Sechs konkrete Setup-Rezepte für die fünf Transport-Backends — wie man UDP-Buffer für 1 MHz-Telemetry tuned, TCP für Cloud-Cross-Region einrichtet, Shared-Memory für In-Box-IPC aktiviert, UDS für Container-Sidecars, TSN-DSCP für Hard-Realtime, plus Multi-Transport-Failover. Wer Spec-Anker und alle Knobs braucht, geht in die Transport Reference.

6 Rezepte · 5 Transport-Backends Crates: transport-{udp,tcp,shm,uds,tsn} Status: ✓ RC3 — alle 5 Backends live

Vorab — wie ZeroDDS Transporte wählt

ZeroDDS hält eine Transport-Registry pro DomainParticipant. Per RuntimeConfig::transports übergibst du eine Liste der aktiven Backends; pro Locator (Discovery-Beacon + Endpoint-Discovery) wird ein passender Backend ausgewählt.

Default: nur UDP aktiv. Wenn du SHM, UDS oder TCP brauchst, fügst du sie explizit zur Liste hinzu. Alle Rezepte unten zeigen die RuntimeConfig-Erweiterung.

Reference statt Rezept? Die Transport Reference dokumentiert jede der 5 Backends mit Locator-Form, Tuning-Knobs, MTU, Plattform-Support und Code-Pfaden.

1 · UDP für Hochfrequenz-Telemetry

Wann: ≥10 kHz Sample-Rate, kleine Payloads (<1 kB), Verlust akzeptabel. Klassisches Sensor-Fusion-Pattern.

OS-Tuning (Linux, einmalig pro Host):

# Receive-Buffer auf 16 MB anheben (Default ~200 kB)
sudo sysctl -w net.core.rmem_max=16777216
sudo sysctl -w net.core.rmem_default=16777216
sudo sysctl -w net.core.wmem_max=16777216

# Optional: net.core.netdev_max_backlog für Bursts
sudo sysctl -w net.core.netdev_max_backlog=10000

# Persistent: /etc/sysctl.d/99-zerodds.conf

ZeroDDS-Side: Default-UDP-Transport reicht. HistoryQos::KeepLast(N) klein halten (depth 1-4) damit der Reader-Cache nicht vollläuft.

Trade-Off: Buffer-Vergrösserung kostet RAM (16 MB × N Sockets). Bei Burst-Bedarf eher temporär hochsetzen als permanent.

2 · TCP für NAT-Traversal

Wann: Cross-Region-Setups, Cloud-Office-Verbindung, Firewall blockt UDP-Multicast. SPDP läuft dann über bekannte Static-Peers.

use zerodds_dcps::runtime::{RuntimeConfig, UserTransportKind};

let cfg = RuntimeConfig {
    user_transports: vec![
        UserTransportKind::TcpV4,  // TCP for WAN / firewall traversal
    ],
    ..Default::default()
};

▶ Runnable example: rust-transport-tuning

Firewall-Regel: öffne den TCP-Port (Default 7400) in beide Richtungen. SO_KEEPALIVE ist per Default an (30 s), schützt vor Stale-Connections nach NAT-Timeout.

Trade-Off: TCP-Stream-Reordering und Head-of-Line-Blocking — eine verlorene Submessage blockt nachfolgende. Für Reliable-Topics akzeptabel; für Hochfrequenz-Best-Effort nicht ideal.

3 · Shared-Memory für In-Box-IPC

Wann: Mehrere Prozesse auf demselben Host (Multi-Service-Container, Multi-Worker-Pipeline). UDP-Loopback braucht ~2–10 µs pro Hop; SHM ~200 ns.

// Cargo.toml: zerodds-dcps = { features = ["same-host-shm"] }
use zerodds_dcps::runtime::{RuntimeConfig, UserTransportKind};

let cfg = RuntimeConfig {
    // Preference order: first kind that matches a peer locator wins.
    user_transports: vec![
        UserTransportKind::Shm,  // SHM for same-host peers (fast path)
        UserTransportKind::UdpV4,  // UDP fallback for cross-host
    ],
    ..Default::default()
};

▶ Runnable example: rust-transport-tuning

POSIX-Permissions: shm_open mit 0644. Für Cross-User-Setups: alle Prozesse mit gemeinsamer Group laufen lassen oder umask anpassen.

Trade-Off: Segment-Größe (4 MB Default) capt Burst-Pufferung. Bei Producer-Schneller-als-Consumer steigt Slot-Overflow → Best-Effort drop oder Reliable-Block.

4 · UDS für Container-Sidecar

Wann: App-Container redet mit DDS-Sidecar im selben Pod (Kubernetes-Sidecar-Pattern), kein Network-Exposure gewünscht.

// Cargo.toml: zerodds-dcps = { features = ["same-host-uds"] }
use zerodds_dcps::runtime::{RuntimeConfig, UserTransportKind};

let cfg = RuntimeConfig {
    user_transports: vec![
        UserTransportKind::Uds,  // UDS for container sidecars
    ],
    ..Default::default()
};

▶ Runnable example: rust-transport-tuning

Pod-Setup (Kubernetes):

volumes:
  - name: zerodds-ipc
    emptyDir: { medium: Memory }
containers:
  - name: app
    volumeMounts:
      - mountPath: /run/zerodds
        name: zerodds-ipc
  - name: zerodds-sidecar
    image: zerodds/agent:rc1
    volumeMounts:
      - mountPath: /run/zerodds
        name: zerodds-ipc

Trade-Off: Filesystem-Permissions managen (umask 0660, gemeinsame fsGroup im PodSpec). Linux-Abstract-Namespace (@zerodds-agent) vermeidet das, ist aber nicht portabel.

5 · TSN für Hard-Realtime

Wann: Industrial-Control-Loops mit ≤1 ms Jitter-Budget, Mixed-Critical-Network (Control + Telemetry auf gleicher NIC), TSN-fähige Switches und NICs.

Voraussetzungen:

  • Linux Kernel ≥5.10 mit NETIF_F_HW_TX_TIMESTAMP + SO_TXTIME
  • TSN-fähige NIC (Intel i210/i225, Marvell Octeon)
  • TSN-Switch (Cisco IE-3400, Hirschmann RS, ...) mit IEEE 802.1Qbv-Schedule

TSN-PIM-Konfig (XML, DDS-TSN 1.0 §7.3):

<dds_tsn>
  <qos_library name="rt_telemetry">
    <qos_profile name="control_loop">
      <dscp>46</dscp>            <!-- Express-Forwarding -->
      <preemptable>false</preemptable>
      <deadline_us>500</deadline_us>
    </qos_profile>
  </qos_library>
</dds_tsn>

Linux qdisc (taprio): ZeroDDS-TSN-Stack rendert die qdisc-Konfig aus der PIM-Beschreibung; manuelle tc qdisc-Pflege ist optional.

Spec-Coverage: DDS-TSN 1.0 Spec-Coverage →

Trade-Off: TSN-Switches sind nicht billig (4-stelliger Bereich pro Switch). Plus: jeder Hop muss TSN-fähig sein — schon ein Standard-Switch im Pfad torpediert die Jitter-Garantien.

6 · Multi-Transport-Failover

Wann: Same-Box-IPC bevorzugt (SHM/UDS), aber Cross-Host muss auch funktionieren (UDP-Fallback). Discovery wählt pro Peer den besten Pfad.

// Cargo.toml: zerodds-dcps = { features = ["same-host-shm", "same-host-uds"] }
use zerodds_dcps::runtime::{RuntimeConfig, UserTransportKind};

let cfg = RuntimeConfig {
    // Preference order: first kind that matches a peer locator wins.
    user_transports: vec![
        UserTransportKind::Shm,  // SHM for same-host peers (fast path)
        UserTransportKind::Uds,  // UDS for container sidecars
        UserTransportKind::UdpV4,  // UDP fallback for cross-host
    ],
    ..Default::default()
};

▶ Runnable example: rust-transport-tuning

Locator-Resolution: Discovery-SPDP propagiert für jeden Participant alle erreichbaren Locators. Beim Match wählt der Sender den ersten in der Praeferenz-Liste, den der Empfänger auch hat.

Trade-Off: Mehr Backends = mehr Open-File-Descriptors + mehr Discovery-Overhead (jeder Backend sendet eigene Beacons). Plus: SHM-Segment-RAM bleibt allokiert auch wenn niemand drauf lauscht.