HeadlinesBriefing favicon HeadlinesBriefing.com

Principes pour des applications Tokio rapides

Hacker News •
×

Je reviens de Rust Conf. À l'Unconf, nous avons eu une discussion productive sur le débogage et le benchmarking des applications asynchrones. De nombreux aperçus intéressants ont été partagés. Je tente d'en énumérer quelques-uns ici, ainsi que certaines de mes propres expériences. Ceci est la première ébauche de ce que j'espère pouvoir devenir un document vivant de bonnes pratiques. N'hésitez pas à ouvrir une issue ou à soumettre une PR. J'espère aussi ajouter une application d'exemple dans les prochains jours démontrant ces problèmes ainsi que l'apparence du trace dial9.— Russell

Il y a peu de règles strictes et absolues pour écrire du code qui performe bien sur les runtimes Tokio ; la réponse à tant de questions est « ça dépend ». La performance d'une charge de travail dépend de ce qui d'autre s'exécute sur le runtime à ce moment-là. C'est pourquoi tant de problèmes n'apparaissent qu'en production ! Écrire des applications asynchrones performantes est un équilibre entre équité et batching, contention et isolation. Cet article expose quelques principes généraux et couvre les exceptions là où je le peux. Il suppose une familiarité de base avec le runtime work-stealing de Tokio ; un résumé de haut niveau est inclus en annexe.

Principes généraux

D'abord, déterminez si vous avez un problème. Si vous commencez à chercher des signaux d'alarme dans une application Tokio, vous en trouverez. Presque toutes les applications réelles que j'ai vues ont des polls bien plus longs que les 10-100 microsecondes que Alice Ryhl recommande dans son excellent article What is Blocking?. Ces problèmes peuvent ou non affecter les métriques ou le comportement de l'application qui vous importent réellement. Il est important de partir d'une métrique réelle que vous cherchez à améliorer. Par exemple, une application peut avoir de longs polls totalement bénins ; les « corriger » n'aura pas d'impact mesurable sur les métriques visibles par l'utilisateur. Dans l'immense majorité des problèmes que j'ai rencontrés, le problème se trouvait dans le code de l'application lui-même, souvent dans l'interaction entre plusieurs composants d'un système distribué (et pas réellement dans Tokio). dial9 a apporté beaucoup de visibilité à Tokio ; au moins aussi souvent qu'il trouve un problème Tokio, il démontre en réalité clairement son absence. Bien sûr, parfois c'est un problème Tokio. En termes de métriques Tokio, la plus utile est l'histogramme de latence de planification (schedule latency) récemment ajouté. La latence de planification est le temps entre le moment où votre tâche est prête à s'exécuter et le moment où Tokio fait réellement le poll du future. Bien que cela ne vous dise pas quelle est la cause, la latence de planification est le symptôme le plus courant d'interactions médiocres entre Tokio et votre code.

Divisez pour la latence, regroupez pour le débit. Cédez (yield) plus fréquemment pour optimiser la latence. Une faible latence sur de nombreuses requêtes nécessite l'équité entre les connexions. Considérez Redis (ou toute application qui prend en charge le pipelining de requêtes). Une implémentation naïve lira les données directement depuis la connexion tant que davantage de données sont disponibles. Lorsque les requêtes sont pipelinées, la requête pipelinée entière finira dans un tampon en mémoire. Lorsque vous lisez des frames depuis celui-ci, chacune sera Poll::Ready sans revenir au réseau. Cela crée à la fois de longs polls et de l'iniquité entre les clients. L'impact sur le débit est généralement plus faible : le même nombre de requêtes est traité. La latence, cependant, change radicalement car un pipeline entier peut attendre derrière un autre. Céder explicitement après chaque requête peut réduire la latence d'environ 10× dans cet exemple. Vous pouvez faire encore mieux en ne cédant qu'après plusieurs lectures consécutives immédiatement prêtes.

Entités clés : Entreprises : Tokio, Redis | Personnes : Russell, Alice Ryhl | Lieux : Rust Conf

FAQ : Quelle est la métrique Tokio la plus utile pour diagnostiquer les problèmes de performance ?

L'histogramme de latence de planification récemment ajouté est la métrique Tokio la plus utile. La latence de planification est le temps entre le moment où votre tâche est prête à s'exécuter et le moment où Tokio fait réellement le poll du future. Bien que cela ne vous dise pas quelle est la cause, la latence de planification est le symptôme le plus courant d'interactions médiocres entre Tokio et votre code.