Overview
Over the past year, justbus-rs has pretty much remained stagnant and there wasn't much changes to the codebase and internals of it. However, this year I would like to add more modularity to the project to enable people to choose between the caching strategies they want due to the fact that some caching strategies may work better with a different type of cpu.
Upgrading to actix-web 3.0
With the release of actix-web 3.0, I have decided that upgrading to the latest version will definitely benefit justbus-rs as there are many improvements within actix especially code safety. A lot of unsafe code blocks have been removed and this will also ensure that justbus-rs is less likely to run into weird safety issues. However, since a lot of unsafe blocks have been removed, that may have impacted performance in some way, BUT having a safer implementation is more desirable than a faster one with hidden bugs due to usage of unsafe
.
Logging
For v0.3.0, you can enable logging by passing the feature flag logging
to enable logging via env_logger
crate. At the current moment I haven't really take a look at other logging alternatives but this shall suffice. Do note that logging has huge performance overhead since it's writing the logs to stdout. In the future I may try exploring other logging techniques which has lesser overhead.
TLS
If you want to enable TLS you can enable it via the tls
flag. Internally it uses rustls as benchmarks suggests that they perform better than OpenSSL.
Different types of caching strategies
Currently I am looking different ways to implement the caching mechanism, however it is only limited to in-memory cache as I do not want any external communication which can be a bottleneck. The few ways I would like to cache the responses are
parking_lot::RwLock<HashMap<u32, String>>
(More details below why I want to add this back)cht lock-free hashmap
Dashmap
All these features can be toggled using feature flags during compilation if the user wishes to change the default caching strategy.
RwLock<HashMap<u32>, String>
Initially, in my previous post, I mentioned that I removed this method to cache the responses. However, ever since I upgraded my machine to a Ryzen 3600, the performace of RwLock<HashMap<u32, String>>
managed to reach the same or even better performance than cht
. Honestly, I am not sure what causes the increase in performance, but I suspect the huge CPU cache and higher memory bandwidth has something to do with it. Unfortunately, I am unable to test this hypothesis as I already sold my old DDR3 ram that sits on the older Intel Z77 motherboard.
You can enable this feature via the swisstable
. If the user wishes to take advantage of hardware lock elision, they can simply switch to the nightly compiler and compile with the nightly
feature to enable it.
Cht
lock-free hashmap and Dashmap
The current implementation uses cht
as that was one of the few concurrent hashmap implementations that I can find during the early stages of justbus-rs. Cht option will still be available via the cht
feature. Dashmap has been advertised as one of the fastest concurrent hashmap in rust with really fantastic benchmarks. For the next v0.3.0 of justbus-rs, Dashmap has been included via the dashmap
feature.
Performance
Disclaimer, this benchmark is naive and YMMV. You should do your own testing as there are a lot of other variables that is purposely ommited for the sake of brevity. For the benchmarks we will be using the following machine
Personal Computer
- CPU: Ryzen 3600 @ stock frequency (6 core processor)
- RAM: 2x8GB DDR4 CL16 3600Mhz
- OS: Ubuntu 20.04
swisstable
Running 15s test @ http://localhost:8080/api/v1/timings/83139
6 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.40ms 4.49ms 109.89ms 92.99%
Req/Sec 126.60k 33.29k 172.64k 74.11%
11357888 requests in 15.05s, 23.48GB read
Non-2xx or 3xx responses: 59
Requests/sec: 754475.17
Transfer/sec: 1.56GB
Memory Usage @ Peak: 21MB
Closing words
0.3.0 has quite a number of changes with regards to compilation and the internal codebase might be more verbose, however this is done to ensure that the final binary does not contain any additional things that the user might not want to use. All in all, the functionality remains the same as there are 0 changes to the json representation and it should be as easy to change the old server to the new one without altering any client code.