Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust as a first class Redis development language #11703

Open
madolson opened this issue Jan 10, 2023 · 0 comments
Open

Rust as a first class Redis development language #11703

madolson opened this issue Jan 10, 2023 · 0 comments

Comments

@madolson
Copy link
Contributor

madolson commented Jan 10, 2023

This issues serves as the main discussion point for including Rust as a development language within the Redis project. I won't dive too much into Rust itself outside of highlighting my personal perspective on how it relates to C development. The goal is to outline how we as a comunity could start developing Redis features in Rust, and whether or not we want to do that.

Why Rust and why Now?

Rust released its first stable version in 2015, and has steadily been growing in popularity since then. Several major holes in the language have been closed in recent years such as async support, support for custom allocators, and comprehensive support for ARM, among hundreds of other features. At AWS, we've adopted using Rust as one of the preferred system development languages for building high performant systems, with several notable systems being built in it such as firecracker as well as a port of our TLS implementation s2n. I can also share that ElastiCache has multiple features built using Rust that have reached production. The linux kernel also agreed to start accepting changes in Rust, which to some people that may lend some strong weight to the argument that it has become "mature".

Personal Anecdotes of using Rust while at AWS

My team at AWS, Amazon ElastiCache, has begun to use Rust as the preferred language for new project development. We opted to not port existing features for the time being, since we didn't see the ROI being high. We have brought a small amount of Rust code to production.

Our experience has been consistent with what other individuals and teams have indicated:

** The Good **

  • Memory and thread safety are amazing. Crashes always produce easy to understand and debug messages. Writing idiomatic Rust code also adds a lot of protection for logic bugs which can trigger panics. It's much easier to trust new code will behave as expected. Memory leaks are also effectively non-existent, although technically possible.
  • A modern development style. Rust pushes you towards a very standardized way of writing code that most rust developers understand. Having an actual style checker is really delightful as well.
  • Much easier testing than C. Writing unit and integration tests are much easier compared to having to build a bespoke system in C. This is obviously still doable in C, although we don't do it, but having a standard mechanism in Rust is nice.
  • Modern tool chains and libraries. I'm not sure how relevant this is for us, but it's much easier to import and manage external dependecies and the standard library is rich and filled with a lot of high quality libraries.
  • Macros are better then the C preprocessor. Macros are an interative improvement over the C preprocessor, allowing for more expressive code generation without having to resort to custom python preprocessing.
  • Async and likeweight threads, like Tokio tasks, make writing event driven code trivial. One issue I have with Redis is the complexity in writing asynchronous code, which is made easier with async functions.
  • Writing simple things is simple. Against the trend a lot of people mention, it's not that hard to understand Rust code or make small changes to it. Once the architecture is in place, minor improvements become relatively quick to implement. I think that contributors would be able to understand and make fixes without fully learning Rust.

** The OK **

  • Support for FFI. Rust makes it pretty easy to generate code that interfaces easily with C code with a module called bindgen. This is still a bunch of work and annoying to figure out, but once the expertise is in place it feels pretty manageable.

** The Bad **

  • Ramp up is long to understand how to design code in Rust. At least 3 months for experienced engineers to really begin to understand how to write in the language, longer for more junior development. This was especially painful as we had few engineers who understood the language so they became a bottleneck when things aren't working the way you expect. As our team has matured, this became a lot easier.
  • "Safe" Rust can be very inconvenient. There is a lot of code that we simply couldn't write, or couldn't write concisely, with Rust. Many paradigms that engineers have learned, a notable one being linked lists, simply couldn't translate well and the code need to be re-designed.
  • Although the Rust style checker is great, it still misses a lot of stuff. It's still easy to write bad Rust code, so deep reviews are still important to make sure the correct paradigms are being used. It's easy to fix a problem by "copying" memory when you really just need to better handle mutability, for example.
  • "Unsafe" rust is still required to integrate with Redis. All of the memory issues we've seen while using rust come from the interface between Redis and Rust, which is to be expected.
  • Incomplete portability. Rust is available on a lot of systems thanks to it's integration with LLVM, but that still means it's not as portable as Redis is today for systems that don't support LLVM. I think over time this will become a more minor issue.

How should we use Rust in Redis

I want to start by outlining what I think are a good set of "tenets" for when to write Rust code.

  • Bias towards Rust when memory or thread safety are critically important. Features that use and manipulate a lot of memory, especially between threads, should strongly consider using Rust.
  • Bias towards Rust when the change can be made independently in Rust and connected via a coherent interface.
  • Bias towards Rust when the usage of the standard or third party libraries dramatically simplifies the code without a cost in memory or performance.
  • Bias against Rust when portability is important. The core functionality of Redis should be portable to all platforms.
  • Bias against Rust when the complexity of the code is small and the overheads of learning and using Rust by the community are high.

Rust as a first class modules/extensions language

Based on the previous tenets, I think the main use case for Rust is using it to build complex extensions and modules. These modules can be built independently (perhaps taking a dependency on server.h or some other file) and then merged together after. In order to integrate with C, we need to expose FFI for the APIs we want to call, so it needs to be implemented on a well defined API boundary, which fits into the module use case well.

The examplar module we are discussing is the Cluster V2 raft management system. I don't know if the intention is to make it multi-threaded, but I do believe that using something like tokio, a rust event based runtime, or some other runtime framework would dramatically simplify the design of the system. Tokio has some amount of learning curve, but it is highly performant and has great introspection tools. I've used it quite a bit at AWS and am very happy with it.

Some additional places to consider rust code:

  • Redis benchmark. It's self-contained and arguable needs a rewrite given it's limitations.
  • Redis-cli. It's self-contained and also has a lot of code that is all over the place, it could use some refactor.
  • A new hiredis/compiled Redis client. There are a couple, and then we would have a first class serialization/deserialization library for RESP.
  • RDB parsing library. We've talked about it a bit, perhaps writing this in rust would be a good place to start.

An argument could be made that in the future if we choose to multi-thread some parts of Redis, there would be a stronger justification for rebuilding parts of the core in Rust, but we aren't there yet.

Additional Reading References

Rust Vs C.
https://pvs-studio.com/en/b/0733/
https://www.bitdegree.org/tutorials/rust-vs-cpp/#rust-the-language-of-the-future
Linux Kernel discussion about adopting Rust

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Backlog
Development

No branches or pull requests

1 participant