Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Advanced Zenoh Tutorial -- Part I

Advanced Zenoh Tutorial -- Part I

This three-part webinar series is designed for developers who want to master Zenoh’s full potential. We’ll cover everything from core concepts to advanced programming techniques, performance tuning, and deployment strategies. The sessions use Rust as the primary language with some complementary examples in Python. Whether you're building robotics systems, telemetry pipelines, or IoT infrastructures—this series will help you unlock the true power of Zenoh.

Avatar for Angelo Corsaro

Angelo Corsaro

May 09, 2025
Tweet

Video

More Decks by Angelo Corsaro

Other Decks in Programming

Transcript

  1. Get It. Build It. Run It $ git clone [email protected]:kydos/zenoh.git

    $ git checkout dev/zsak $ cd zenoh $ cargo build —release —features “stats” $ ./target/release/zenohi -h
  2. Cloud to Microcontroller Today, more and more systems, operate from

    the cloud down to the micro-controller This poses new challenges as existing technologies were not designed to work in this scenario Cloud Edge Device
  3. Simplicity does not precede complexity, but follows it — A.

    Perils Digital Frankensteins Today, building systems that span from the micro-controller to the data-centre feels like assembling a digital Frankenstein Multiple technologies are stitched together only to make data fl ow end-to- end Few more have to be packed-up to deal with data storage… Not to mention computations
  4. Dragons teach us that if we want to climb high

    we have to do it against the wind. Pub/Sub/Query protocol that Uni fi es data in motion, data at rest and computations from embedded microcontrollers up the data centre Provides location-transparent abstractions for high performance pub/sub and distributed queries across heterogeneous systems Built-in support for Shared Memory / Zero-Copy as well as built-in support for distributed storage alignments
  5. Runs Everywhere Written in Rust for security, safety and performance

    Native libraries and API bindings for many programming languages, e.g., Rust, C/C++, Python, JS, REST, C# and Kotlin Built-in support Shared Memory and Zero Copy Supports network technologies from transport layer down- to the data link. Currently runs on, TCP/IP, UDP/IP, QUIC, Serial, Bluetooth, OpenThreadX, Unix Sockets, Shared Memory Available on embedded and extremely constrained devices and networks — 5-7 bytes minimal overhead Data Link Network Transport Physical …
  6. Why Rust? 70% of security vulnerability are due to memory

    safety issues Rust is memory and concurrency safe, high performance, productive and has a great ecosystem
  7. Zenoh Implementations ZettaScale leads two implementations of the Zenoh protocol

    Zenoh written in Rust and Zenoh Pico written in C and targeting micro- controllers When using C/C++ APIs, applications can target either of these versions — it is a compile-time decision C C CPP Zenoh Pico Zenoh C Rust CPP Python Kotlin Java TS Rust Go JS
  8. Supported OS OS Linux, MacOS, Windows, Android, iOS, QNX Embedded

    Targets Arduino, ESP32, Zephyr, FreeRTOS, … Automotive Targets AUTOSAR Classic (microSAR)
  9. Any Topology Peer-to-peer Clique and mesh topologies Client Client Mesh

    Peer Peer Peer Peer Peer Clique Peer Peer Peer Peer Client
  10. Any Topology Peer-to-peer Clique and mesh topologies Brokered Routed Client

    Client Brokered Clients communicate through a router or a peer Mesh Peer Peer Peer Peer Peer Router Client Client Client Client Router Router Client Clique Peer Peer Peer Peer Client
  11. Router Router Any Topology Peer-to-peer Clique and mesh topologies Brokered

    Routed Router Router Router Client Client Routed Routers forward data to and from peers and clients Brokered Clients communicate through a router or a peer Mesh Peer Peer Peer Peer Peer Router Client Client Client Client Router Router Client Clique Peer Peer Peer Peer Client
  12. Putting it all Together Each Zenoh application can transparently run

    across multiple links at the same time All of this transparently to the application Router Router Router Client Client Client Peer Peer Peer Peer Peer serial Unix Pipes OpenThread Serial TCP/IP QUIC QUIC QUIC TLS TLS TLS Unix Sockets
  13. Zenoh Runtime Storage Plugins Protocol Plugins MAIN MEMORY FILE SYSTEM

    Runtime Plugins Zenoh Flow RocksDB Plug-In Architecture
  14. Zenoh’s Primitives Zenoh is built upon two primitives operating on

    named data: pub/sub and query/reply Named data is represented by as (key, value) tuple, e.g., (bot-1/sensor/speed, 25) These two orthogonal primitives allow Zenoh to e ffi ciently deal with distributed computations, data/event dissemination and storage
  15. bot-1/sensor/speed Pub/Sub Cont Pub Sub1 Sub2 Sub3 bot-1/sensor/* bot-1/sensor/speed bot-2/sensor/speed

    Sub4 Sub5 bot-2/** bot-2/sensor/speed Pub */sensor/* Zenoh matching is based on key expressions A subscriber has associated a key expression and will receive all publications with a matching key
  16. Composing Zenoh’s Abstractions Publish/Subscribe. Trivially supported by Zenoh’s Publisher and

    Subscriber Remote Computation. A Queryable represents a generalised computation, since it can transparently deal with replication and partitioning Storage. Represented by the combination of a Queryable and a Subscriber Additionally all these primitives enjoy location transparency by the virtue of being data-centric. Recap
  17. Sub1 Queryable1 Sub1 Queryable1 Example — Storage The combination of

    a Subscriber and a Queryable allow to abstract any storage Each publication matching the Subscriber expression will be ingested on the storage Every query matching the Queryable will result on a storage query Zenoh provides o ff the shelf integration with mainstream storage technologies Sub1 Queryable1 In fl uxDB File System AWS S3 bot$*/sensor/** bot$*/sensor/** bot$*/sensor/**
  18. bot-1/compute/nav/path <attachment> Query/Reply When issuing a query Zenoh will route

    it to a set of Queryable The set of queryable addressed depends on the query target, it can be Best Matching, All and All Complete Triggered queryable respond with a fi nite stream of values Get Queryable1 bot-1/compute/nav/* Queryable2 bot-*/compute/nav/* Queryable3 bot-1/compute/nav/path
  19. bot-1/compute/nav/path <attachment> Query/Reply Cont Get Queryable1 bot-1/compute/nav/* Queryable2 bot-*/compute/nav/* Queryable3

    bot-1/compute/nav/path ALL When issuing a query Zenoh will route it to a set of Queryable The set of queryable addressed depends on the query target, it can be Best Matching, All and All Complete Triggered queryable respond with a fi nite stream of values
  20. Query/Reply Cont When issuing a query Zenoh will route it

    to a set of Queryable The set of queryable addressed depends on the query target, it can be Best Matching, All and All Complete Queryable1 Queryable3 BEST MATCH Assuming Queryable3 is the closest in routing distance bot-1/compute/nav/path <attachment> bot-1/compute/nav/* bot-*/compute/nav/* bot-1/compute/nav/path Get Queryable2
  21. Query/Reply Cont When issuing a query Zenoh will route it

    to a set of Queryable The set of queryable addressed depends on the query target, it can be Best Matching, All and All Complete Get Queryable1 Queryable2 Queryable3 ALL COMPLETE Completeness allows to indicate that a queryable does not have “holes”. In other terms it commits to provide answers for any key included in its key expression bot-1/compute/nav/path <attachment> bot-1/compute/nav/* bot-*/compute/nav/* bot-1/compute/nav/path
  22. Example Let’s assume that each robot exposes a queryable to

    retrieve status Notice that when we do a query we don’t need to know if the data is being computed or retrieved from a store Zenoh abstracts the di ff erence between the two — which is extremely fl exible Get Queryable1 Queryable2 Queryable3 bot-1/status/** bot-2/status/** bot-2/status/**
  23. Example Let assume we want to get the battery status

    for bot1 get bot-1/status/battery Get Queryable1 Queryable2 Queryable3 84%, nil bot-1/status/** bot-2/status/** bot-2/status/** 84% 42% 21%
  24. 84%, nil 42%, nil 21%, nil Example Let assume we

    want to get the battery status for all bots get bot-$*/status/battery Get Queryable1 Queryable2 Queryable3 bot-1/status/** bot-2/status/** bot-2/status/** 84% 42% 21%
  25. nil 42%, nil 21%, nil Example Let assume we want

    to get the battery status for all bots that have less than 50% of remaining charge get bot-$*/status/battery?level<0.5 Get Queryable1 Queryable2 Queryable3 bot-1/status/** bot-2/status/** bot-2/status/** 84% 42% 21%
  26. API Design Support for both async and sync programming model

    Builders everywhere to ensure evolvability Needs to “resolve” by calling res() in order to craft the request
  27. Synch or Async: Pick Your Choice Zenoh supports both sync

    and async APIs Depending on your application and the integration requirement with other libraries and native code it may be preferable to use one or the other To use the sync API you need to use the zenoh.Wait trait.
  28. Opening a Session #[tokio::main] async fn main() { let c

    = zenoh::Config::default(); let z = zenoh::open(c).await.unwrap(); // Use the session } Sync API Async API use zenoh::Wait; fn main() { let c = zenoh::Config::default(); let z = zenoh::open(c).wait().unwrap(); // Use the session }
  29. Producing Data w/o a Publisher Zenoh makes it possible to

    “put” data without needing to declare a publisher The declaration of a publisher is just an optimisation that should be done for resources that are written regularly z.put("daily/quote/latin", "Per aspera ad astra.").await.unwrap(); z.put("daily/quote/hindi", "A união faz a força.").await.unwrap();
  30. Producing Data with a Publisher The declaration of a publisher

    is just an optimisation It is a way to indicating to Zenoh that a given resource is going to be written often and thus implement a series of runtime and wire optimisations — in other terms make the common case fast! let z_pub = z.declare_publisher("daily/quote/latin").await.unwrap(); z_pub.put("Audaces fortuna juvat.").await.unwrap(); Publishers can be declared for any valid key expression, such as, daily/quote/latin , daily/quote/*, daily/quote/**
  31. What can I “put”? pub fn put<IntoZBytes>(&self, payload: IntoZBytes) ->

    PublisherPutBuilder<'_> where IntoZBytes: Into<ZBytes>, In Zenoh you can put anything that can be converted into ZBytes This includes, strings, vectors, slices and arrays of u8, and Shared Memory bu ff ers
  32. Subscriber Declaration A subscriber is declared by providing a key

    expression, such as, daily/quote/* and daily/** Zenoh guarantees that a subscriber will receive the put operation performed for keys- expressions that match with that of the subscriber Example: A Subscriber for daily/quote/* matches daily/quote/latin and daily/quote/ brazilian, while daily/** matches daily/quote/latin daily/quote/brazilian daily/world/english, etc. let sub = z.declare_subscriber("daily/quote/*").await.unwrap();
  33. Samples received by a subscriber can be consumed asynchronously using

    a stream and as such avoiding any inversion of control This keeps the code highly readable and can leverage all the stream combinators Subscribers as Streams let sub = z.declare_subscriber("daily/quote/**").await.unwrap(); while let Ok(s) = sub.recv_async().await { println!("{}: {}", s.key_expr(), s.payload().try_to_string().unwrap()); } let kvs = sub.iter().fuse() .map(|s| { let k = String::from(s.key_expr().as_str()); let v = String::from(s.payload().try_to_string().unwrap()); (k, v)});
  34. Queryable A queryable is a network endpoint that answers to

    queries matching its key expression The answer to a query is a fi nite stream of (key, values) Queryable are quite powerful and can be used to represent both the reading-half of a datastore/database as well as trigger computations
  35. Declaring a Queryable The declaration of a queryable requires minimally

    the key expression associated with it let queryable = z.declare_queryable("daily/quote/**") .complete(is_complete) .await.unwrap(); You can also specify the completeness of this queryable w.r.t. the set of keys represented by its key expression. If the queryable “has answers” for any key in the set expressed by its key expression then it ice complete, otherwise it is not.
  36. Visualizing Completeness Another way of visualising complete queryable, is like

    a set w/o any “holes” This property is especially important if you want to use queryable to do quorums Complete Non Complete
  37. Query In Zenoh queries are issued by using the get

    operation z.get(k) .target(query_target) .consolidation(consolidation) .res().await.unwrap(); The result of a query is a fi nite stream of Replies Controls who, among matching, is eligible to be targeted Controls if and how replies are consolidated
  38. Query Target The query target controls, among the queryable whose

    key expression matches that of the query, the set that should be used to execute the query pub enum QueryTarget { #[default] BestMatching, All, AllComplete, #[cfg(feature = "complete_n")] Complete(u64), } BestMatching. Bigger intersection and closer in routing terms All. All the queryable that intersect the query AllComplete. All queryable that fully cover the query. In other terms the query key expression is superset of the query expression Complete(N). Among the queryable that are complete pick N — routing considerations will be used to decide. (This is useful for read quorums, N is your read quorum :-)
  39. Key Highlights Zenoh is one of a kind protocol —

    it uni fi es data in motion, data at rest and computations It is the only protocol able to run from the microcontroller up to the datacenter It has not topological constraints It is extremely easy to use!