I’m writing a server application and thought I’d seek some input from experienced Rust developers on the architecture. I’ve been writing complex servers in Kotlin, Java and previously C++ for years, but am fairly new to Rust.
The overall requirements are:
- Accept http requests (think crud)
- Data is provided by two database backends, both with a configurable number of external connections
- Configuration is read at startup, but can also be updated at runtime
- Some caching layers will be needed later on
My initial idea on how to build this:
- Base http server part on hyper (https://github.com/hyperium/hyper). Requests are on a standard format, so no complex routing necessary
- Launch one thread per DB connection
- Put http requests onto one of two async channels - one for each DB type: (https://docs.rs/async-channel/1.4.1/async_channel/)
- Each request allocates a response channel and includes that in the request
- DB connection threads polls the associated request channel, performs a DB lookup & data transformation and puts the result on the request-specific response channel
- Using channels this way as a hand-off between threads (and async/sync) - is that current best practice?
- It seems a bit wasteful to allocate a new response channel for every request. Any better way to do this?
- One of the two DB layers is Postgres, which has an async Rust client (https://docs.rs/tokio-postgres/0.5.5/tokio_postgres/). Perhaps it’s possible to create another design using this. However, I am very concerned about controlling number of DB connections.
- Should I use skip the async bit and build a thread-based server? It would probably work initially, but I am expecting this server to eventually handle a very large number of requests. There will be horizontal scaling as well of course though.
Any help very much appreciated! Thanks!