Available Crates
quinn
: Most used QUIC crate in Rust
- Support
tokio
, async-std
runtime officially, and can be easily implement custom runtime provider.
- Bigger community
s2n
: Open-sourced by Amazon, already be used in production environment.
- Only support
tokio
runtime officially, but it has multiple provider for testing.
- Has better
tracing
support than quinn
from logs we can get more information, which is super helpful for debugging.
The differences between QUIC and TCP
- In TCP, the connection is keep-alived, if on both sides, we do not explicitly close the connections, and no network error happens, the connections are promised good. However, in QUIC, at least in
quinn
, the connections are not keep-alived, even though, we do not explicitly close the connections, the connections can be either closed by server or closed by client implicitly.
- Conclusion: In our Rust code, we cannot have a connection pool like TCP, we need to hold an
Endpoint
, as the result, we may need to frequently establish connection between the server and client (But establish connection is cheap for QUIC). More research should be done, and research some open-source projects.
- TCP establishes a connection using a three-way handshake and maintains this connection until it is explicitly closed. This continuous connection is useful for certain types of long-lived connections but can be less efficient for short or sporadic data exchanges.
- (But in our mixnet, it seems that we want to hold the connections e.g. nodes in layer1 holds the connections to the nodes of the layer2).
- In my opinion, long lived connections may be not suitable for our mixnet (this is also the reason why we need to replace TCP)
e.g. If we have multiple packets need to be sent from node1 to node2 at the same time, in TCP, we either
- Queue the packet2 (if we only holding one connection for each peer, currently we do this way to solve run out of file descriptor problem),
- Or open another connection to send packet, again, this will bring run out file descriptor problem back if we cannot deal it correctly.
- QUIC, on the other hand, is designed to minimize connection establishment time, especially during subsequent connections. It uses a connection ID rather than just relying on IP addresses and port numbers. This allows QUIC connections to persist even when underlying network properties (like IP address) change, without the need for a traditional "keep-alive" mechanism.
- For the same example, if we use QUIC,
- It uses connection IDs rather than relying solely on the tuple of source/destination IP addresses and ports. This approach can reduce the need for maintaining a large number of file descriptors for different connections, as multiple streams and interactions can occur over a single QUIC connection.
- QUIC also allows multiple logical streams to be multiplexed over a single connection. This means that applications (we can just treat node-to-node (our mixnet layered design) as applications) can forward more packets with fewer actual connections, thus consuming fewer file descriptors.
- QUIC supports moving connections between IP addresses without needing to establish a new connection, which is useful for switching networks (e.g. our light node runs on mobile devices, for mobile devices, change network from 5g to wifi frequently happens).