What would be the "best" protocol between Rust-based micro-services

I use RUST for its speed so i also want my communication protocol to be fast

What do you think ?

Http+Json ?
gRPC ?
Cap'n proto ?
RSocket ?
Something else ?

2 Likes

I'm not doing anything production grade, but I generally trow serializable types in a cbor codec over AsyncRead/AsyncWrite... Allows you to do IPC over any kind of transport that supports AsyncRead/AsyncWrite, which is quite versatile.

Downsides: kind of low level, no automatic reconnects, ...

http+json: requires an http server, I wouldn't use that for IPC. generally I don't use anything which has json in it's name either, but you could say that's not an objective criteria.

grpc: lot's of people seem to use this. but requires an http connection along it.

cap'n proto: definitely looks interesting, but you need schema files to describe your types. It's not just derive Serialize and off you go (adds complexity especially if you need to support user supplied types). I remember a post on reddit not so long ago that reviewed several things and found it didn't work out well with capn'proto, but I can't find it anymore.

There is also things like compact, which kay uses to get in memory layout to be the same as serialized: https://docs.rs/compact/0.2.15/compact/

You can also look into messaging libraries, like zeromq, rabbitmq, nanomsg, ...

You might want to have a look at:
https://speice.io/2019/09/binary-format-shootout.html

2 Likes

Another serde/transport to look at is bincode/tarpc.

1 Like

Will the client and server always be rust?
Will the data have a schema?
If so will the schema vary over versions of the software?

4 Likes

Nice! These are collections that implement Copy (as opposed to only implementing Clone). Thanks for point this out!

1 Like

I have no idea about "best" but for some time now we have been using the NATS. Which advertises itself as :

NATS.io is a simple, secure and high performance open source messaging system for cloud native applications, IoT messaging, and microservices architectures.

We have remote embedded devices communicating sensor data to our cloud servers over NATS. The kids call it IoT now a days. Our server processes chat among themselves over NATS.

I like NATS because performance is excellent, the API is dead simple and code is available in many languages to drive it, including Rust of course, it can be easily secured, it's dead easy to install and setup and has proven very reliable.

One thing missing is the connection between web browsers and NATS over web sockets. There are some NATS/WS gateway projects out there which I have not tried yet. The good news is that it is on the road map for NATS to get web socket capability this year.

As for the actual NATS message formats that is up to you. We have a mess of raw binary streams from sensors, JSON formatted messages and so on.

Thank you ZiCog. NATS seems to be very interesting. It reminds me the amazing fastest MOM i've ever use in my IT life => TibcoRendezVous. TibRV is used on nearly all stock exchange platform all over the world.

Only problem with Tibco was the price...extremely expensive.

Hope you find NATS useful. I have no connection to the NATS guys, Just think NATS is an excellent project and it fits our messaging requirements brilliantly.

Never heard of TibRV but from what I read about it it provides a similar publish/subscribe messaging system as NATS as it's basic functionality. So if you liked TibRV I guess you will get on with NATS.

Others use MQTT in similar situations, we gave up on in after various difficulties I won't go into.

I was contemplating creating a NATS to websocket gateway in Rust. Mostly as further exercise in Rust. But now they have such functionality planned for this year I might give it a miss. Still tempting mind...

Simple, fast, battery included (auto-reconnect, load balancing, etc...). I like that !

Gonna give it a try for sure man. Thank you for the info again !

If it can work over AsyncRead/AsyncWrite, you might be in luck. I wrote ws_stream_wasm to make idiomatic websockets in wasm convenient, and provide AsyncRead/AsyncWrite.

I also provide the server counterpart ws_stream_tungstenite. This one was using tokio-tungstenite with tokio 0.1 as backend, but I'm just now upgrading it to async-tungstenite, which is fully async/await and runtime agnostic. So within a few days I will be ready to release an update. ws_stream_wasm also probably get's a new maintenance release at the same time for updating deps, some polishing and improving CI configs.

So you get AsyncRead/AsyncWrite to the browser low cost (just have to read some docs). If NATS can use that as an underlying connection and compiles on wasm, you're almost ready to start using it.

Hmm...interesting. Although I don't immediately see how it fits in with my plan. Which is something like this:

  1. A NATS server in the cloud.
  2. Require to make subscriptions and publish to it from the browser over websockets.
  3. For now at least the browser code will be Javascript. I'd like to look into using Rust and WASM at some point.

That demands some kind of gateway process in the cloud that accepts websocket connections from the browser and passes messages on to NATS using it's protocol.

The complication here, as far as I see it, is that when a browser subscribes to something that subscription has to be passed on to NATS by the gateway. Then the gateway has to remember who is subscribed to what such that it can return published messages to the correct websocket connection. Also so that it can unsubscribe when that websocket connection goes away.

All this is doable but it seems like duplicating what goes on inside NATS already, which seems daft.

As it happens some years ago I made such a pub/sub server in Javascript under node.js. It was rude and crude and would never scale well but worked for our purposes.

The idea was to recreate that node.js effort in Rust. If only as a stop gap until NATS gets WS handling, and for a bit of Rust hacking fun.

Anyone got any bright ideas about this?

Disclaimer, I haven't looked at how NATS works internally, but if it can work with a generic connection, really, it might just be a matter of glueing the pieces together.

If I were you, I would still make the browser part in rust and expose an API to Js if you need to use it from Js. That way, no need for a gateway server.

If NATS is a binary that you have to run, that doesn't work however. In the worst case you just have to run a websocket server and make that bridge to NATS on the server. I can recommend async-tungstenite for that still. Represent each connection from the browser as a different connection to your NATS process, that way when the ws connection goes away you just shut down the backend connection to NATS and let it do what it usually does when a client goes away.

That way your code stays simple and lightweight.

The NATS protocol is pretty simple. You can even chat to it with telnet if need be.
Except I intend to enable TLS for security on my NATS server(s)

Currently I think what I need is to be able to chat from code in the browser to my server though HTTPS, which dictates websockets for real-time push data as far as I can tell. I'm looking at getting 10 updates per second for a real-time data visualization application.

It is. It's opensource but I'm not about to go in there and hack it up for my purposes. That would only make it worse!

OK. That is my take on it as well.

Ah, I know nothing about all this async stuff in Rust. The more questions I read about it here the more confused it seems. I'm quite used to async in Javascript but it does not look easy in Rust. In fact I get the impression it's not really stabilized and ready for prime time even.

That is pretty much how my previous pub/sub in node.js worked.

I'd quite like to look into an async approach. I have no idea what tungstenite is. I thought tokio was all the rage for this. Where does one start, given a would like to use existing WS and NATS crates.

I think async rust is young, so it's prime time is ahead of it, but its fully functional. You can perfectly do what you describe today.

tokio and async-std are the two most complete frameworks. They give you a set of basic tools, executor to spawn tasks on, basic connections like TCP, UDP, a file api so you can use the filesystem asynchronously.

Then there is the websocket part. tungstenite is a websocket library. There is others you can look into as well. It can be used both in synchronous and asynchronous code. async-tungstenite helps you run the websocket over a tcp connection from one of the async frameworks.

If both sides are in Rust, then bincode is a pretty painless serde-based encoding. Combining something like that with tokio-util::codec (or futures-codec) makes for very low-boilerplate, high performance networking protocols. (bincode is probably better for this than cbor since it's not self-describing.)

3 Likes

Just saw this on reddit: https://github.com/sphqxe/NATS-WebUI

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.