Le diesel doit-il être exécuté à l'aide d'un acteur de synchronisation, actix_web :: web :: block ou futures-cpupool?


10

Contexte

Je travaille sur une application actix-web utilisant le diesel via r2d2 et je ne suis pas sûr de la meilleure façon de faire des requêtes asynchrones. J'ai trouvé trois options qui semblent raisonnables, mais je ne sais pas laquelle est la meilleure.

Solutions potentielles

Acteur de synchronisation

D'une part, je pourrais utiliser l'exemple d'actix , mais il est assez compliqué et nécessite beaucoup de passe-partout pour être construit. J'espère qu'il existe une solution plus raisonnable.

Actix_web::web::block

Comme autre option, je pourrais utiliser le actix_web::web::blockpour encapsuler mes fonctions de requête dans un avenir, mais je ne suis pas sûr des implications en termes de performances.

La requête s'exécute-t-elle alors dans le même système Tokio? D'après ce que j'ai pu trouver dans la source, il crée un thread dans le pool de threads actix-web sous-jacent . Est-ce un problème?

Si je lis le code correctement, r2d2 bloque son thread lors de l'acquisition d'une connexion, ce qui bloquerait une partie du pool d'actix-web principal. Même chose avec les requêtes de base de données. Cela bloquerait alors tout l'actix-web si je fais plus de requêtes que j'ai de threads dans ce pool? Si oui, gros problème.

Futures-cpupool

Enfin, le pari sûr qui peut avoir des frais généraux inutiles est futures-cpupool . Le problème principal est que cela signifie ajouter une autre caisse à mon projet, bien que je n'aime pas l'idée de plusieurs cpu-pools flottant inutilement dans mon application.

Étant donné que le r2d2 et le diesel se bloqueront, il y a une quantité surprenante de choses délicates ici.

Plus important encore, ne partagez pas ce cpupool avec quoi que ce soit n'utilisant pas le même pool r2d2 (car tous les threads créés peuvent simplement bloquer l'attente d'une connexion r2d2, verrouillant tout le pool lorsque le travail existe).

Deuxièmement (un peu plus évidemment), vous ne devriez donc pas avoir plus de connexions r2d2 que de threads dans le pool et vice-versa car le plus gros gaspillerait des ressources (connexions inutilisées / threads constamment bloqués) (peut-être un thread de plus, pour peut-être plus rapide transfert de connexion par le planificateur du système d'exploitation plutôt que par le planificateur cpupool).

Enfin, pensez à la base de données que vous utilisez et aux performances que vous y avez. L'exécution d'une seule connexion r2d2 et d'un seul thread dans le pool peut être préférable dans une application sqlite lourde en écriture (bien que je recommanderais une base de données appropriée pour cela).

Anciennes réponses

Anciennes solutions qui peuvent fonctionner

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

Essentiellement, recommande Futures-cpupool.

Quelle est la meilleure approche pour encapsuler les E / S bloquantes dans les futurs rs?

Recommande Futures-cpupool pour les cas généraux.

De vieilles solutions qui ne fonctionnent pas

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

Une très bonne solution pour une ancienne version d'actix-web. D'après ce que je peux trouver, les demandes n'ont plus de pool de processeurs.


D'après les commentaires de ce numéro , il semble que futures-cpupoolc'est la solution de contournement recommandée pour le manque de asyncsupport dans Diesel.
Jmb

C'est plus une solution générale. J'espère quelque chose qui tirera parti du système actix. Néanmoins, je vais creuser dans futures-cpupool maintenant pour rechercher des problèmes.
logina

Bienvenue dans Stack Overflow! Il semble que votre question puisse trouver réponse dans les réponses de Quelle est la meilleure approche pour encapsuler les E / S bloquantes dans les versions futures? . Sinon, veuillez modifier votre question pour expliquer les différences. Sinon, nous pouvons marquer cette question comme déjà répondue.
Shepmaster

Étant donné que le cpupool interagit également avec le pool de connexions bloquantes dans r2d2, je ne suis pas sûr de la meilleure façon de résoudre ce problème. J'examine moi-même maintenant et je mettrai à jour cela bientôt.
logina

Réponses:


3

Je pars avec futures-cpupool. C'est la meilleure solution en raison de la nature bloquante de mes interactions.

Utiliser actix_web :: web :: block est assez décent, mais utilisera un pool de threads partagé dans actix (et en raison des appels de blocage que j'utilise, cela peut bloquer l'ensemble du pool de threads et interférer avec d'autres tâches données à actix_web).

Il est préférable d'utiliser futures-cpupool pour créer un pool de threads distinct par base de données uniquement pour les interactions avec la base de données. De cette façon, vous regroupez toutes les tâches qui doivent s’attendre les unes les autres (quand il y a plus de tâches que de connexions) dans un pool, les empêchant de bloquer toutes les autres tâches qui n’ont pas besoin d’une connexion et potentiellement de limiter le nombre de threads au nombre de connexions (pour que la tâche ne soit planifiée que lorsqu'elle ne sera pas bloquée).

Dans le cas où vous ne souhaitez utiliser qu'une seule connexion à la base de données (ou très peu), l'acteur de synchronisation est une assez bonne option. Il agira comme un futur-cpupool avec un seul thread, garantissant que toutes les tâches sont exécutées une à la fois, sauf qu'il utilisera l'un des threads sous-jacents d'actix-web plutôt qu'un thread séparé (donc bon pour très peu de connexions) . Je trouve le passe-partout trop gros pour en valoir la peine.


6
lire mes conclusions ci - dessus - veuillez mettre des informations pertinentes pour la réponse dans la réponse , pas la question.
Shepmaster
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.