Bradis
A few years ago, I needed a project. I had become consumed by a desire to use Rust, and I was trying to learn how to do complex things with it. Small projects and challenges were getting old and I felt like I was spinning my wheels. I needed something I was uncomfortable with.
After some failed attempts at contributing to the language or projects around it, I had an idea. I was talking with a friend about Redis, which also consumes a lot of my brain cycles, and I thought “I should make a Redis”.
Yes. I know. There is already a Redis. It works much better than the one I could write. It’s more stable and has more support. This won’t be something to use per se, but rather a tool to focus my efforts. That’s ok!
So my Redis probably wouldn’t be good or complete, but I was determined to make a serious attempt at it. I wanted to write something with production in mind, even if it never lives in production.
Anyways. I started to write Redis with Rust, and several years later I have something that is decidedly not a Redis. It’s a small piece of a Redis, which is not particularly valuable given the existence of a full, free1 Redis.
However!
It also happens to contain all the things I’ve learned in the meantime. It
contains my reintroduction to the stack and the heap after many years of
dynamic languages. It represents my struggles with the borrow checker and my
best attempts at writing unsafe
code. It’s everything I know about
async Rust. It’s an outline of how Redis works. It’s an illustration of how to
do zero-copy networking. It’s my conception of atomic operations and
concurrency. And it’s the absurb amount of fun I had putting it together.
And that’s pretty valuable - at least to me. And maybe someone else…?
I’ve gone a long way on my own but I think I want more now. I’d like to share it with someone. Get some feedback. Ask for help. Compare it to other people’s understanding. Multiply the fun. Divide the despair.
I’ve been calling it Bradis, because it sounds like Redis. And I like the way it declares my existence. Brad is. (I am.)
WASM
One of my favorite things about Rust is its support for compiling to web assembly. With a bit of work and a few caveats2, you can run Rust code in the browser. The repl below is Bradis running in the browser via WASM. Try out some Redis commands!
set x foo
- set a valueget x
- get a valuecommand list
- get a list of commandshset h x 1
- set values in a hashrpush l a b c
- push values into a listsadd s x y z
- push values into a setzadd z 1 x 2 y 3 z
- add values to a sorted setmulti
- start a transactionexec
- execute a transactionclient info
- get info about the current client
Also, try some commands that use two clients.
subscribe news
- subscribe to a channel abovepublish news boom
- publish to a channel belowblpop l 0
- block while waiting for a value aboverpush l a b c
- add a value for the command above
Performance
One of my main goals was to create something that is reasonably competitive
with C-Redis from a latency and throughput standpoint. According to
redis-benchmark
, C-Redis is 1.7 times as fast as Bradis. I have some ideas
for closing that gap, but I’m pretty happy to be in the same order of
magnitude. 100k requests per second is pretty fast!
Bradis:
~: redis-benchmark -t set -n 1000000 -c 20 -p 3333
====== SET ======
1000000 requests completed in 9.57 seconds
20 parallel clients
3 bytes payload
…
Summary:
throughput summary: 104471.38 requests per second
latency summary (msec):
avg min p50 p95 p99 max
0.109 0.040 0.111 0.127 0.143 0.591
C-Redis:
~: redis-benchmark -t set -n 1000000 -c 20
====== SET ======
1000000 requests completed in 5.73 seconds
20 parallel clients
3 bytes payload
…
Summary:
throughput summary: 174581.00 requests per second
latency summary (msec):
avg min p50 p95 p99 max
0.067 0.024 0.063 0.119 0.175 1.799
Repos
Currently, Bradis exists as four repos. If you’re curious about what’s implemented and what isn’t, this is the place to start!
- respite - An implementation of the RESP protocol
- bradis - This is where everything else lives - commands, store, db, etc.
- bradis-server - A server that listens for connections over TCP.
- bradis-web - A WASM build for running in the browser
That’s it
That’s all I’ve got for now. I’ll be writing down all the things I’ve learned here. If you like them, or you don’t like them, or they’re wrong, or you have questions, let me know!
1. License changes notwithstanding.
2. There are a few capabilities that aren’t currently supported in the browser (e.g. threads) so they have to be emulated or left out.