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.