Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should diesel be run using a sync actor, actix_web::web::block or futures-cpupool?

Background

I am working on an actix-web application using diesel through r2d2 and am unsure of how to best make asynchronous queries. I have found three options that seem reasonable, but am unsure of which one is best.

Potential Solutions

Sync Actor

For one I could use the actix example, but it is quite complicated and requires a fair deal of boilerplate to build. I hope there exists a more reasonable solution.

Actix_web::web::block

As another option I could use the actix_web::web::block to wrap my query functions into a future, but I am unsure of the performance implications of this.

Is the query then running in the same Tokio system? From what I could find in the source, it creates a thread in the underlying actix-web threadpool. Is that a problem?

If I read the code right, r2d2 blocks its thread when acquiring a connection, which would block part of the core actix-web pool. Same with database queries. This would then block all of actix-web if I do more queries than I have threads in that pool? If so, big problem.

Futures-cpupool

Finally, the safe bet that may have some unneeded overhead is futures-cpupool. The main issue is that this means adding another crate to my project, though I don't like the idea of multiple cpu-pools floating around in my application needlessly.

Since both r2d2 and diesel will block there are a surprising amount of tricky things in here.

Most importantly, do not share this cpupool with anything not using the same r2d2 pool (as all threads created may just block waiting for an r2d2 connection, locking down the whole pool when work exists).

Secondly (a bit more obviously), you thus shouldn't have more r2d2 connections than threads in the pool and vice-versa since the bigger one would waste resources (connections unused/threads constantly blocked) (perhaps one more thread, for maybe quicker connection handover by the OS scheduler rather than the cpupool scheduler).

Finally, mind what database you are using and the performance you have there. Running a single connection r2d2 and a single thread in the pool might be best in a write heavy sqlite application (though I would recommend a proper database for such).

Old answers

Old solutions that may work

https://www.reddit.com/r/rust/comments/axy0hp/patterns_to_scale_actixweb_and_diesel/

In essence, recommends Futures-cpupool.

What is the best approach to encapsulate blocking I/O in future-rs?

Recommends Futures-cpupool for general cases.

Old solutions that don't work

https://www.reddit.com/r/rust/comments/9fe1ye/noob_here_can_we_talk_about_async_and_databases/

A really nice fix for a old actix-web version. From what I can find requests no longer have a cpu-pool in them.

like image 441
logina Avatar asked Nov 08 '19 12:11

logina


1 Answers

I am going with futures-cpupool. It is the best solution due to the blocking nature of my interactions.

Using actix_web::web::block is decent enough, but will use a shared thread-pool in actix (and due to the blocking calls I use this can block the entire thread pool and interfere with other tasks given to actix_web).

It is better to use futures-cpupool to create a separate threadpool per database just for database interactions. This way you group all the tasks that need to wait for each other (when there are more tasks than connections) into one pool, preventing them from blocking any other tasks that don't need a connection and potentially limiting the number of threads to the number of connections (so that the task will only be scheduled when it won't be blocked).

In the case where you only want to use one database connection (or very few) the sync actor is a pretty good option. It will act like a futures-cpupool with one thread, ensuring that all tasks are run one at a time, except that it will use one of actix-web's underlying threads rather than a separate one (therefore, only good for very few connections). I find the boilerplate too big to be worth it, though.

like image 118
logina Avatar answered Dec 23 '22 11:12

logina