GeotrekCE / Geotrek-admin

Paths management for National Parks and Tourism organizations
https://geotrek.fr
BSD 2-Clause "Simplified" License
136 stars 76 forks source link

:zap: Error 500 in heavy load conditions #4359

Open lpofredc opened 2 weeks ago

lpofredc commented 2 weeks ago

Describe the bug

Last sprint, BiodivSports app instance have often been unusable due to an heavy load (almost camptocamp calls, which culminate to more than 250000 hits/day this summer). Consequently, server returned very often an 500 error to users.

Problem have been fixed by configuring ASGI Django mode, instead of traditional WSGI mode. (PR Coming very very soon).

To Reproduce

Difficult to reproduce...

Expected behavior

No error ;)

Screenshots

None

babastienne commented 1 week ago

Thanks @lpofredc for your feedbacks. Glad to hear that your change in configuration has solved the issue.

Looking forward to see your PR :+1:

submarcos commented 1 week ago

Hello @lpofredc

ça serait bien d'en discuter

Dans la mesure ou vos données ne changent pas trop souvent, peut être qu'un simple cache au niveau nginx pourrait convenir sans pour autant compléxifier le code pour un cas qui n'est pas forcément généraliser.

à disposition pour en parler

lpofredc commented 1 week ago

Merci @submarcos pour ces pistes. A ma connaissance, le cache nginx ne pourra pas répondre à ce cas de figure. la forte charge de l'instance concernait très majoritairement des appels d'API sur la liste des zones sensibles au format geojson filtrées par bbox, avec des coordonnées de bbox spécifiques à chaque appel.

submarcos commented 1 week ago

Merci @submarcos pour ces pistes. A ma connaissance, le cache nginx ne pourra pas répondre à ce cas de figure. la forte charge de l'instance concernait très majoritairement des appels d'API sur la liste des zones sensibles au format geojson filtrées par bbox, avec des coordonnées de bbox spécifiques à chaque appel.

Hello, en effet je ne connais pas toutes les problématiques, d'ou mon intérêt d'en discuter avant pour avoir tes retours d’expérimentations, avant de te laisser ouvrir une PR qui pourrait apporter d'autres problématiques en résolvant certaines. L'ASGI est un grand pas en avant, mais pour avoir expérimenté avec django ce n'est pas encore totalement au point, aussi en essayant d'être un peu le garde fou de la complexité du code je voudrais être certain que ce qui est implémenté est nécessaire et relativement simple. Je suis dispo pour discuter conception avant de relire ta PR si jamais

submarcos commented 1 week ago

Utiliser un moteur asgi avec du code synchrone peut en effet aider à paralleliser et résoudre certains de tes problèmes mais en empirant les perfs générales car les actions synchrones seront convertties à la volée. As-tu fait des benchmarks poussés, et comparé avec d'autres système synchrones utilisant les threads comme gevent ou gthread ? https://blog.muehlemann-popp.ch/gunicorn-uvicorn-and-uwsgi-tested-which-wsgi-server-leads-in-speed-652d9bf9d2a7 Il es tfort probable que l'utilisation de gevents avec gunicorn soit tout aussi efficace sans changer le moteur pour du faux asynchrone (synchrone converti mais threadé)

submarcos commented 1 week ago

Donc autant je serai méfiant et j'attendrai pas mal de tests pour passer à uvicorn (du moins tant qu'on utilise pas les fonctions asynchrones de django qu isont tjrs en cours d'implémenation), autant si il est vrai que gunicorn + gevents améliore considérablement les perfs, alors on pourrait le mettre en place très rapidement

lpofredc commented 1 week ago

Merci @submarcos pour ces pistes. J'ai pu faire des tests sur différents scenarii proposés avec jmeter (100 utilisateurs/100s/10boucles d'itération) avec un appel sur l'API Sensitivearea geojson filtrée par une bbox vers le lac de genève.

Avec WSGI sync (config par défaut) tel que configuré dans le Dockerfile (gunicorn geotrek.wsgi:application --bind=0.0.0.0:8000), les perfs sont très mauvaises, avec des temps de réponse allant wsgi_sync

Avec ASGI comme proposé dans la PR (gunicorn geotrek.asgi:application --bind=0.0.0.0:8000 --worker-class uvicorn.workers.UvicornWorker), c'est nettement mieux (on tourne à environ 200ms/réponse). asgi

Avec WSGI et gevents (`gunicorn geotrek.wsgi:application -k gevent --bind=0.0.0.0:8000, pas mieux que WSGI sync. Ai-je manqué quelque chose sur son implantation? wsgi_gevent

Du coup, j'ai ensuite fait des tests en jouant sur les workers, et là c'est franchement mieux et plus comparable. Et gevent ne montre pas d'effets sur ces tests.

Pour ASGI, pas de différence. Par contre, pour WSGI, que ce soit avec sync ou gevent, c'est nettement mieux, et comparable avec ASGI:

wsgi avec workers 5 (gunicorn geotrek.wsgi:application --bind=0.0.0.0:8000 --workers 5) wsgi_workers5

wsgi avec gevent et workers 5 (gunicorn geotrek.wsgi:application --bind=0.0.0.0:8000 -k gevent --workers 5) wsgi_gevent_workers5_threads2

Au vu de ces résultats, je pense qu'on peut en effet se passer de ASGI pour rester sur WSGI sync, en effet, il semble qu'on puisse se passer de l'ASGI pour rester sur WSGI sync mais avec une personnalisation des workers pour améliorer les perfs (la doc indique (nb core*2)+1). A voir si c'est encore améliorable avec le paramétrage des threads.

submarcos commented 1 week ago

Alors en effet, ce n'est pas documenté mais la version docker necessite de configurer le nombre de workers. le nombre a été mis à 1 par défaut car selon l'orchestrateur de containr utilisé, il estmieux de scaler les containes (kubernetes, docker swarm, dokku) que les workers (docker compose etc)

Donc en effet il suffit de surcharger la CMD du dockerfile.

On peut:

submarcos commented 1 week ago

ET vu que tu as une instance à forte sollicitation je suis interessé par tes retours avec optimisatios de orker + gevent ou gthread

submarcos commented 2 days ago

Je pense qu'on va clarifier / simplifier le nombre de workers gunicorn, par exemple en mettant un variable d'environnement, avec pour défaut 1 (afin de scaler les containers), mais avec une valeur de 5 dans le env.dist, pour que les utilisateurs de docker compose n'aient pas de probleme à l'install