Giter VIP home page Giter VIP logo

quic-rpc's Introduction

Quic-Rpc

A streaming rpc system based on quic

Latest Version Docs Badge license badge status badge

Goals

Interaction patterns

Provide not just request/response RPC, but also streaming in both directions, similar to grpc.

  • 1 req -> 1 res
  • 1 req, update stream -> 1 res
  • 1 req -> res stream
  • 1 req, update stream -> res stream

It is still a RPC system in the sense that interactions get initiated by the client.

Transports

  • memory transport with very low overhead. In particular, no ser/deser, currently using flume
  • quic transport via the quinn crate
  • transparent combination of the above

API

  • The API should be similar to the quinn api. Basically "quinn with types".

Non-Goals

  • Cross language interop. This is for talking from rust to rust
  • Any kind of versioning. You have to do this yourself
  • Making remote message passing look like local async function calls
  • Being runtime agnostic. This is for tokio

Example

computation service

Why?

The purpose of quic-rpc is to serve as an optional rpc framework. One of the main goals is to be able to use it as an in process way to have well specified protocols and boundaries between subsystems, including an async boundary.

It should not have noticeable overhead compared to what you would do anyway to isolate subsystems in a complex single process app, but should have the option to also send messages over a process boundary via one of the non mem transports.

What do you usually do in rust to have isolation between subsystems, e.g. between a database and a networking layer? You have some kind of channel between the systems and define messages flowing back and forth over that channel. For almost all interactions these messages itself will again contain (oneshot or mpsc) channels for independent async communication between the subsystems.

Quic-rpc with the mem channel does exactly the same thing, except that it hides the details and allows you to specify a clean high level interaction protocol in the rust type system.

Instead of having a message that explicitly contains some data and the send side of a oneshot or mpsc channel for the response, it creates a pair of flume channels internally and sends one end of them to the server. This has some slight overhead (2 flume channels vs. 1 oneshot channel) for a RPC interaction. But for streaming interactions the overhead is negligible.

For the case where you have a process boundary, the overhead is very low for transports that already have a concept of cheap substreams (http2, quic, ...). Quic is the poster child of a network transport that has built in cheap substreams including per substream backpressure. However, I found that for raw data transfer http2/tcp has still superior performance. This is why the http2 transport exists.

Currently you would use the quinn transport for cases where you want to have connections to many different peers and can't accept a large per connection overhead, or where you want low latency for small messages.

You would use the hyper transport for cases where you have a small number of connections, so per connection overhead does not matter that much, and where you want maximum throughput at the expense of some latency.

This may change in the future as quic implementations get more optimized.

quic-rpc's People

Contributors

dignifiedquire avatar divagant-martian avatar flub avatar frando avatar omahs avatar rklaehn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

quic-rpc's Issues

Make into_inner more useful for http2 transport

Currently the http2 transport has an into_inner only on the SendSink, because the RecvStream never sees the raw bytes. The framing and deserialization gets done in the forwarder.

The recv side should be changed so that the stream of raw bytes::Bytes is also available for into_inner.

Also, there should be utilities to turn a stream of bytes into an AsyncRead and a sink of bytes into an AsyncWrite. The former exists for futures, but unfortunately not for tokio.

Unix domain socket transport

Either write an UDS transport from scratch, or figure out how to use quinn via an unix domain socket.

This is useful because an unix domain socket is easier to secure than a localhost network socket, and might also give a bit of a performance advantage.

Cant find flume::Connection::New

Hi!
Thank you for your great crate.

I tried to use the example with flume feature(for wasm) but can't find how to init client like in this code:

let client = quic_rpc::transport::quinn::QuinnConnection::new(
        endpoint,
        server_addr,
        "localhost".to_string(),
    );

Cheers!

Wire up some metrics

It would be probably best to have metrics for the transports, since different transports will have different metrics.

Better logging

Currently, some errors like deser errors are silently dropped.

It is intentional that these errors are not forwarded to the use site - what would it do with it. But they should at least be logged somehow.

E.g. in the hyper transport the various things that can go wrong.

Reconnection

A RpcClient should not just wrap a connection, but contain logic to reconnect. Signature should be unchanged.

First, just do brute force. Eventually there would have to be some backoff.

Really allow graceful shutdown

Ok, that's a pretty rubbish title. But what we really need to be able to do is:

  • Signal shutdown to the server.
  • Server stops accepting new connections.
  • Server keeps handling existing connections.
  • Once there are no more connections the server finishes, an event you can away.

The way the server is used in iroh-memstore would allow making use of this to nicely terminate. And I'm pretty sure the hyper and quinn transports allow us to implement this here.

This is kind of already done for the http2 transport, but because there was no use yet for the explicit waiting API it was not handled so needs extending.

fails to build with feature `quinn-transport`

at 0ccd8f5

It's probably a configuration issue but it fails first with a doc test, removing the doc tests brings up a lot of compilation issues afterwards

error: could not compile `quic-rpc` (test "slow_math") due to 48 previous errors
error: could not compile `quic-rpc` (test "quinn") due to 45 previous errors

Version enforcement

We don't do versioning. But we should have optional version enforcement. You should be able to set it up so that quic-rpc will refuse to connect to an endpoint that has a different version (e.g. git commit hash) of the protocol.

Make frame size configurable

Currently all transports that do serialization/deserialization use hardcoded frame sizes.

Those should be made configurable, and check that the frame sizes are compatible with the maximum of the underlying transport. E.g. http2 has 16,777,215 bytes max frame size.

Error handling

Connection error handling works just fine. But often the RPC user will want to send internal errors over the wire.

I don't want to conflate this with the connection error handling. So a RPC call that can produce an user visible error will return something like this: Result<Result<T, UserError>,ConnectionError>. And in principle the UserError should not be a concern of quic-rpc.

But maybe we can come up with something to make writing such things less painful. Some kind of generic serializable user error that interacts well with anyhow.

Upgrade flume

The flume version used here is out of sync with iroh, resulting in duplicate deps. Would be nice to make them match.

Allow closing one half of the request/reply streams pair.

On a request/replay stream/sink pair for individual RPCs it should be possible to close one half while still keeping the other half open.

An example of this would be a watch call, which is a single message as request and a stream of responses. After the client makes the request it should be able to close the channel making it clear no more messages will be sent to the server. Likewise, and more important, the server would do the same: after reading the request it closes the request stream ensuring the client can no longer send any messages on the request stream.

This would be analogous to e.g. quinn::RecvStream::stop or sn2_quic::stream::ReceiveStream::stop_sending (and their send stream equivalents).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.