Json webService with actix

hi, all, i'm new in learning rust..

i intend to learn the best practice for implementing web service in actix.
the use case is simple : querying some records from a postgresql db table, and then displaying/printing those records in json format.

from the result of googling over these words : "rest api with actix web postgresql", i've got this simple example : https://turreta.com/2019/09/21/rest-api-with-rust-actix-web-and-postgresql-part-1/

i'm following that example, and then here's my source code : https://github.com/sharing-lab/ws-benchmark/tree/master/implementations/actix-sync

then i benchmarked it using "ab -n 1000 -c 4 ..." on a Xeon(R) CPU E3-1225 v5 @ 3.30GHz (4 cores), and i got 1623 requests per second (rps)

i think it's a wrong way of using actix, is it? it's synchronous (blocking)
so i made some change, based on the official actix example : https://github.com/actix/examples/blob/master/r2d2/src/main.rs

i changed : .route(web::get().to(color::get_list)) ,
into this : .route(web::get().to_async(color::get_list))

and i put / move blocking code inside web::block(move || { ... }) : https://github.com/sharing-lab/ws-benchmark/blob/master/implementations/actix-r2d2/src/color/mod.rs

i also used r2d2. the complete async version is : https://github.com/sharing-lab/ws-benchmark/tree/master/implementations/actix-r2d2

then the benchmark result became : 13434 rps. so it's more than 8 x increase in performance/speed (the complete benchmark notes : https://github.com/sharing-lab/ws-benchmark/blob/master/results-xeon_4_core.txt)

is there any more missing point in implementing the correct best practice to develop webservice in actix ?

Thanks very much

One thing to watch for is whether the server is CPU-bound or I/O-bound.

If I/O-bound (meaning it has free CPU cycles during peak load) then there are more optimizations you could make. Beginning these can be challenging, but you might get some good info out of the tracing or async-log crates. Postgres may be the bottleneck, for example.

If you're CPU-bound (100% pegged on all CPU cores during peak load) then you're at the theoretical limit of what the software+hardware combination can do. At this point the only wins to be gained are optimizations from CPU profiling.

While load testing, it's probably also worth running the load generator, HTTP server, and the database all on their own hosts. This will allow you to scale the test (e.g. multiple servers - each on their own hosts - behind a load balancer - running on its own host - and multiple databases - each on their own hosts, etc). It will also provide more realistic latency metrics. And importantly for CPU-bound tests, it will help show you where the real hot-spots are by giving exclusive access to all CPU resources for each process. In other words, so the HTTP server and DB will not fight over limited CPU resources.