• Stars
    star
    3,927
  • Rank 11,120 (Top 0.3 %)
  • Language
    Rust
  • License
    MIT License
  • Created almost 5 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Incomplete Redis client and server implementation using Tokio - for learning purposes only

mini-redis

mini-redis is an incomplete, idiomatic implementation of a Redis client and server built with Tokio.

The intent of this project is to provide a larger example of writing a Tokio application.

Disclaimer Please don't use mini-redis in production. This project is intended to be a learning resource, and omits various parts of the Redis protocol because implementing them would not introduce any new concepts. We will not add new features because you need them in your project — use one of the fully featured alternatives instead.

Why Redis

The primary goal of this project is teaching Tokio. Doing this requires a project with a wide range of features with a focus on implementation simplicity. Redis, an in-memory database, provides a wide range of features and uses a simple wire protocol. The wide range of features allows demonstrating many Tokio patterns in a "real world" context.

The Redis wire protocol documentation can be found here.

The set of commands Redis provides can be found here.

Running

The repository provides a server, client library, and some client executables for interacting with the server.

Start the server:

RUST_LOG=debug cargo run --bin mini-redis-server

The tracing crate is used to provide structured logs. You can substitute debug with the desired log level.

Then, in a different terminal window, the various client examples can be executed. For example:

cargo run --example hello_world

Additionally, a CLI client is provided to run arbitrary commands from the terminal. With the server running, the following works:

cargo run --bin mini-redis-cli set foo bar

cargo run --bin mini-redis-cli get foo

OpenTelemetry

If you are running many instances of your application (which is usually the case when you are developing a cloud service, for example), you need a way to get all of your trace data out of your host and into a centralized place. There are many options here, such as Prometheus, Jaeger, DataDog, Honeycomb, AWS X-Ray etc.

We leverage OpenTelemetry, because it's an open standard that allows for a single data format to be used for all the options mentioned above (and more). This eliminates the risk of vendor lock-in, since you can switch between providers if needed.

AWS X-Ray example

To enable sending traces to X-Ray, use the otel feature:

RUST_LOG=debug cargo run --bin mini-redis-server --features otel

This will switch tracing to use tracing-opentelemetry. You will need to have a copy of AWSOtelCollector running on the same host.

For demo purposes, you can follow the setup documented at https://github.com/aws-observability/aws-otel-collector/blob/main/docs/developers/docker-demo.md#run-a-single-aws-otel-collector-instance-in-docker

Supported commands

mini-redis currently supports the following commands.

The Redis wire protocol specification can be found here.

There is no support for persistence yet.

Tokio patterns

The project demonstrates a number of useful patterns, including:

TCP server

server.rs starts a TCP server that accepts connections, and spawns a new task per connection. It gracefully handles accept errors.

Client library

client.rs shows how to model an asynchronous client. The various capabilities are exposed as async methods.

State shared across sockets

The server maintains a Db instance that is accessible from all connected connections. The Db instance manages the key-value state as well as pub/sub capabilities.

Framing

connection.rs and frame.rs show how to idiomatically implement a wire protocol. The protocol is modeled using an intermediate representation, the Frame structure. Connection takes a TcpStream and exposes an API that sends and receives Frame values.

Graceful shutdown

The server implements graceful shutdown. tokio::signal is used to listen for a SIGINT. Once the signal is received, shutdown begins. The server stops accepting new connections. Existing connections are notified to shutdown gracefully. In-flight work is completed, and the connection is closed.

Concurrent connection limiting

The server uses a Semaphore limits the maximum number of concurrent connections. Once the limit is reached, the server stops accepting new connections until an existing one terminates.

Pub/Sub

The server implements non-trivial pub/sub capability. The client may subscribe to multiple channels and update its subscription at any time. The server implements this using one broadcast channel per channel and a StreamMap per connection. Clients are able to send subscription commands to the server to update the active subscriptions.

Using a std::sync::Mutex in an async application

The server uses a std::sync::Mutex and not a Tokio mutex to synchronize access to shared state. See db.rs for more details.

Testing asynchronous code that relies on time

In tests/server.rs, there are tests for key expiration. These tests depend on time passing. In order to make the tests deterministic, time is mocked out using Tokio's testing utilities.

Contributing

Contributions to mini-redis are welcome. Keep in mind, the goal of the project is not to reach feature parity with real Redis, but to demonstrate asynchronous Rust patterns with Tokio.

Commands or other features should only be added if doing so is useful to demonstrate a new pattern.

Contributions should come with extensive comments targetted to new Tokio users.

Contributions that only focus on clarifying and improving comments are very welcome.

License

This project is licensed under the MIT license.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in mini-redis by you, shall be licensed as MIT, without any additional terms or conditions.

More Repositories

1

tokio

A runtime for writing reliable asynchronous applications with Rust. Provides I/O, networking, scheduling, timers, ...
Rust
23,031
star
2

axum

Ergonomic and modular web framework built with Tokio, Tower, and Hyper
Rust
17,992
star
3

mio

Metal I/O library for Rust.
Rust
6,301
star
4

tracing

Application level tracing for Rust.
Rust
5,365
star
5

prost

PROST! a Protocol Buffers implementation for the Rust Language
Rust
3,766
star
6

console

a debugger for async rust!
Rust
3,542
star
7

loom

Concurrency permutation testing tool for Rust.
Rust
1,847
star
8

bytes

Utilities for working with bytes
Rust
1,739
star
9

io-uring

The `io_uring` library for Rust
Rust
1,037
star
10

tokio-uring

An io_uring backed runtime for Rust
Rust
946
star
11

turmoil

Add hardship to your tests
Rust
772
star
12

tokio-proto

A network application framework for Rust
Rust
694
star
13

slab

Slab allocator for Rust
Rust
641
star
14

tokio-core

I/O primitives and event loop for async I/O in Rust
Rust
628
star
15

async-stream

Asynchronous streams for Rust using async & await notation
Rust
568
star
16

rdbc

Rust DataBase Connectivity (RDBC) :: Common Rust API for database drivers
Rust
558
star
17

tokio-minihttp

Protocol implementation experimentations
Rust
425
star
18

tokio-metrics

Utilities for collecting metrics from a Tokio application
Rust
254
star
19

tls

A collection of Tokio based TLS libraries.
Rust
243
star
20

tracing-opentelemetry

Rust
233
star
21

website

Website for the Tokio project
TypeScript
211
star
22

valuable

Rust
185
star
23

async-backtrace

Rust
162
star
24

tokio-io

Core I/O primitives for asynchronous I/O in Rust.
Rust
124
star
25

tokio-socks5

An example SOCKSv5 server implementation with tokio
Rust
100
star
26

tokio-tls

An implementation of TLS/SSL streams for Tokio
Rust
95
star
27

simulation

Framework for simulating distributed applications
Rust
92
star
28

tokio-timer

Timer facilities for Tokio
Rust
83
star
29

tokio-service

The core `Service` trait in Tokio and support
Rust
81
star
30

tokio-line

Line protocol for Tokio
Rust
64
star
31

tokio-redis

Redis client for Tokio
Rust
58
star
32

tokio-uds

Unix Domain Sockets for tokio
Rust
52
star
33

doc-push

Tokio doc blitz effort - A concerted effort to improve Tokio's documentation.
50
star
34

tokio-compat

Streamline updating a Tokio 0.1 application to Tokio 0.2.
Rust
48
star
35

book

45
star
36

tokio-openssl

OpenSSL bindings for Tokio
Rust
37
star
37

tokio-middleware

A collection of Tokio middleware
Rust
28
star
38

tokio-rfcs

22
star
39

async

Utilities building on top of Rust's async primitives.
Rust
22
star
40

console-gsoc

Google Summer of Code tokio-console prototype
Rust
12
star
41

service-fn

A service implemented by a closure
Rust
11
star
42

gsoc

Organize the Google Summer of Code projects.
6
star
43

cargo-tokio

A cargo subcommand to help building the Tokio project.
Rust
4
star
44

website-next

Next iteration of the Tokio website.
TypeScript
1
star