Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Luca Cominardi
    @Mallets
    But this is only one piece of the story. Configuring the SN in this way allows to limit the wire overhead to 2 bytes. So, where are the other 2 bytes?
    Luca Cominardi
    @Mallets
    This is in the data message itself and how resources are represented:
    • In zenoh each resource is represented by a key, in the form of URI. E.g. /home/sensor/temperature
    • The key can be arbitrary long. This is very handy for the user who is completely free to define his own key structure, as complex/nested as he wants to be.
    • However, transmitting the whole key is not wire efficient at all. For this reason, in zenoh we have a mechanism to do some dynamic mapping between the complete string form of the key into a more compact integer form, called simply resource ID. This means that we have a wire-efficent mapping for identifying resources departing from simple integers sent on the wire. This resource ID is encoded as VLE, thus the possibility to use only 1 byte.
    • In order to use this wire-efficient representation you may need to use the declare_resource() primitive in zenoh, which does exactly that under the hood.
    So, summarizing. 4 bytes are the minimal overhead that can be achieved by zenoh thanks to:
    1) SN negotiation and limited to 1 byte. This might have an impact on the achievable throughput due to max num of messages that can be on the fly at the same time.
    2) The efficient mapping between string and integer resources on the wire.
    @OliLay I hope this clarify your doubt
    halfbit
    @halfbit:matrix.org
    [m]
    that's really really nice
    halfbit
    @halfbit:matrix.org
    [m]
    with that sync branch, I get 1.5 million msgs/sec with the shm thr samples, amazing
    so... yeah I think removing some async stuff there really did do some magic
    Luca Cominardi
    @Mallets
    Yes, that’s what we discovered by investigating in depth the async stack. It’s very powerful, but has a huge cost when used everywhere. So, the sync branch is really an ongoing effort of fencing the async part in few specific parts in zenoh.
    halfbit
    @halfbit:matrix.org
    [m]
    makes a lot of sense
    Oliver Layer
    @OliLay
    Hi @Mallets. Thank you very much for the information, which makes the protocol much clearer for me now. I was a bit confused, because I have zenoh TCP traffic captured, and as I saw in the source code that requires the frame length and the payload length to be prepended each. With leaving that aside (e.g. using UDP) and using a 1 byte SN as you said, I get how you can have a 4 byte data message on the wire. Thanks again :)
    kydos
    @kydos

    with that sync branch, I get 1.5 million msgs/sec with the shm thr samples, amazing

    Using shared memory is useful for payload that are at least 1Kbytes. Otherwise try w/o shared memory for smaller data… You should get even higher throughput.

    halfbit
    @halfbit:matrix.org
    [m]
    kydos (Angelo Corsaro) for my message size avg of about 512 bytes, shm does about 100-200k msgs/s more
    you know, on my desktop, not necessarily a great comparison given a lot of these things are likely to be small embedded linux arm devices, still impressive to me
    kydos
    @kydos
    Cool @halfbit:matrix.org, glad to hear that you are happy about the performance level.
    Luca Cominardi
    @Mallets
    @OliLay yes, right. In case of operating over TCP we need to add 2 bytes to identify the actual batch length on the wire. This is not needed on UDP or e.g. QUIC. Moreover, to complete really the story, the 2 bytes for TCP + 2 bytes for SN number are sent only once per wire-frame. Each frame then can contain multiple data messages. E.g., considering a frame batch is max 64KB, you can fit in it thousands of 8 bytes tiny messages. For each of those message you get the minimal 2 bytes overhead for data messages. But then, the 2 bytes of TCP and 2 bytes of the SN are sent only once for all those thousands of tiny messages.
    Oliver Layer
    @OliLay
    @Mallets yes, I get that. Thanks :)
    halfbit
    @halfbit:matrix.org
    [m]
    whats a <LOCATOR> in the args list:
    Julien Enoch
    @JEnoch
    That’s the « address » of a transport endpoint in the format "<transport>/<address>". e.g.:
    • tcp/123.4.5.6:7447 (or tcp/eu.zenoh.io:7447)
    • tls/123.4.5.6:7447
    • udp/123.4.5.6:7447
    • quic/123.4.5.6:7447
      ...
    halfbit
    @halfbit:matrix.org
    [m]
    also is nats-bench somehow cheating? seems like a peer to peer connection would be significantly faster than one with a broker involved
    nats-bench is just a hair behind this thing
    which... is surprising, given I imagine at least a few additional copies and syscalls are involved
    Luca Cominardi
    @Mallets
    A locator is the ‘place’ where you make yourself available and others can connect to: in TCP/UDP terms it’s IP:PORT.
    Examples are locators are:
    • tcp/192.168.1.1:7447
    • tcp/mydoing.com:7447
    • tcp/localhost:7447
    • unixsock-stream//tmp/mysock.sock
    Ok, I see that @JEnoch replied before me :D
    Tbh we didn’t have a look into nats-bench deeply, so I don’t really know about the inner details… what do you experience?
    halfbit
    @halfbit:matrix.org
    [m]
    ah ok that makes sense, I figured it'd just take the ip addr but it didn't like that
    nats-bench pushing 512 byte messages to a local nats server, with a single publisher/subscriber gets me 1.4 million msgs/s
    I'd rather see latency histograms than throughput though to be honest
    kydos
    @kydos
    @halfbit:matrix.org, what are you using for benchmarking NATS, dds-bench? If so this is not really apple to apple comparison, please take a look at this line https://github.com/nats-io/nats.go/blob/3b1f6fcc1e1014c838036367494c3012523166b0/examples/nats-bench/main.go#L168
    halfbit
    @halfbit:matrix.org
    [m]
    nats-bench
    they have their own bench tool which I mean, yeah, hard to say its doing even remotely the same stuff
    kydos
    @kydos
    Their test is written in such a way to do user-level batching/flushing — real-world application rarely do that manually.
    halfbit
    @halfbit:matrix.org
    [m]
    yeah we don't do that in using nats
    kydos
    @kydos
    In zenoh if you look at the code for pub/sub used for throughput that’s what a beginner would write. We think that is important as your application will not need to get into these nasty details to get decent performances
    Our scheduling is done at the transport level, thus it is transparent for the user.
    halfbit
    @halfbit:matrix.org
    [m]
    its interesting that batching is even needed, I get the ideal scenario is avoiding too many sys calls... would io_uring do better without having to batch up messages?
    push messages into a queue with the kernel, let it do things as fast as it can kind of deal
    rather than this goofy, lets buffer up a million messages then call write once
    that nats-bench is doing at least
    kydos
    @kydos
    At a transport level zenoh sends frames, a frame can include multiple messages. One frame is sent with a single sys-call (if we do not need to fragment), how we pack it up is part of our scheduler, but the goal is taking care of reducing syscalls while at the same times ensuring message prioritisation.
    To be more precise within a zenoh session we can use multiples links, e.g. TCP/IP connections, to ensure that we can better recover congestions over WAN — that is a relatively well known trick.
    halfbit
    @halfbit:matrix.org
    [m]
    makes sense, and seemingly what nats does as well
    zenoh seems to be capped by the line rate between two computers, which is fantastic
    at least on this puny gigabit network I have
    no 10g to test against :-)
    Geoff
    @geoff_or:matrix.org
    [m]
    I can't get the zenoh-bridge-dds to work across NAT ☹️

    On a native PC, I launch:
    ./target/release/zenoh-bridge-dds -m peer -d 0 -l tcp/10.89.76.138:7447 -e tcp/10.89.76.139:7447

    On a container running on another PC, I launch:
    ./target/release/zenoh-bridge-dds -m peer -d 0 -l tcp/10.92.70.153:7447 -e tcp/10.89.76.138:7447

    The container's host is forwarding port tcp/7447 into the container. I confirmed that port forwarding is working with iperf.

    However when I run a ROS 2 publisher on the native PC, and then list topics in the container, I don't see the published topic.

    Geoff
    @geoff_or:matrix.org
    [m]
    I can see the two instances of zenoh-bridge-dds talking to each other in wireshark
    Geoff
    @geoff_or:matrix.org
    [m]
    That's a wireshark capture from the host
    Interestingly, in captured packet 19 I can see the IP address of the container (10.92.70.153) being sent to the native PC (10.89.76.138). I don't know how zenoh discovery works but is it possible that the instance of zenoh running inside the container is telling the instance running on the native PC to connect to the container's IP rather than the IP of the host PC (which would then NAT and forward that connection into the container)?