Moteur web Python pour un site en prod (sans asynchrone) ?
Bonjour à tous,
Je travaille sur un projet de site web à très fort trafic, avec des exigences proches de plateformes comme YouTube ou Netflix. Mon objectif est de construire une base ultra optimisée, scalable, sécurisée, et surtout entièrement thread-safe, sans utiliser de programmation asynchrone.
Objectifs techniques :
-
Utiliser une architecture multi-threadée non bloquant
-
Tourner avec Gunicorn (autre si vous argumentez bien)
-
Pas d’async/await, ni d’event loop et tous ces trucs.
-
Un contrôle fin sur les requêtes, middlewares, headers, gestion des connexions, etc... et SURTOUT la gestion des blocs pour les Upload
-
Une solution robuste pour de la vraie production
Ce que j’ai testé et pourquoi j’ai changé :
Flask
J’ai commencé avec Flask, que j’ai trouvé simple à prendre en main. Le fait que chaque requête soit gérée dans un thread me convenait bien.
Mais j’ai eu un déclic en travaillant sur la gestion des fichiers en upload :
-- Impossible de contrôler les chunks. Flask reçoit d’abord tout le fichier complet en mémoire ou disque temporaire, puis seulement après on peut le traiter.
Résultat : un utilisateur mal intentionné pourrait envoyer de très gros fichiers, ce qui sature le serveur avant même que je puisse intervenir. Pour moi, c’est une faiblesse critique, et ça m’a fait abandonner Flask.
FastAPI
J’ai ensuite essayé FastAPI, que j’ai trouvé plus moderne et surtout plus souple pour toucher aux couches basses (middlewares, injection, etc.).
Mais là encore, gros déclic :
-- FastAPI est construit autour de l’asynchrone, et c’est une vraie contrainte. Même quand on veut juste rester synchrone, on se retrouve bloqué, certaines libs ne marchent plus comme prévu, et ça complique énormément le code.
Je trouve que ce modèle ne correspond pas du tout à une architecture basée sur du multithread synchrone.
gunicorn -k uvicorn.workers.UvicornWorker --bind 192.168.1.30:8080 --workers 1 --threads 500 app:app
Ce que je cherche maintenant, trouver un meilleur module ou framework capable de :
-
Supporter une vraie production lourde
-
Offrir des performances et une stabilité maximales
-
Rester synchronisé, thread-safe, sans asynchrone forcé
-
Et donner un contrôle total sur la gestion fine des requêtes
Deux réécritures du site en quatre jours, j’en suis à me demander si le problème c’est vraiment les frameworks…
Là je suis sur Django. Je pensais toucher le fond, mais non : je creuse encore.
(Et je bloque sur une erreur que même ChatGPT aurait honte d’inventer.)
À ce rythme, je vais pouvoir sortir un framework à moi tout seul...
Par pitié, aidez-moi...
- Donner suite en anglais
- Création site web - Guide
- Site de telechargement - Accueil - Outils
- Site comme coco - Accueil - Réseaux sociaux
- Web office - Guide
- Site pour vendre des objets d'occasion - Guide
3 réponses
bonjour,
Bizarre d'essayer ainsi d'utiliser une seule solution pour toutes les fonctions. L'upload de fichiers peut très bien se faire via un autre module.
Par ailleurs, les protections doivent être mises en place à différents niveaux, tu ne peux pas tout contrôler uniquement au niveau de ton application.
Dans ta liste "Objectifs techniques", tu inclus des contraintes arbitraires que tu ne justifies pas. Un peu comme si tu voulais aller sur Mars et mettais, comme objectif technique, que tu voulais utiliser exclusivement un vélo.
Si tu as des contraintes de resources, de budget, et de compétences, il est préférable de les décrire.
Bonjour,
Juste pour essayer de comprendre le problème, supposons qu'un utilisateur mal intentionné veuille uploader un gros fichier, quelle serait la stratégie que tu veux mettre en place ? Cherches-tu à imposer une taille d'upload maximale (en gros on coupe l'upload une fois une certaine taille maximale atteinte) ?
Concernant flask, est-ce que cette proposition ou cette proposition a du sens dans ton cas d'usage (je ne me rend pas compte si la taille est connue ?
Peut-être une autre façon de formuler ma question, admettons que tu travailles en C avec des sockets (ou même quelque chose d'un peu plus évolué comme gio), quel serait la stratégie que tu souhaiterais mettre en place ?
Bonne chance
La taille des fichiers doit être dynamique, et non fixe comme Flask l’impose :
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024
Alors qu’avec FastAPI, j’ai request.stream() qui contient le flux du fichier, ce qui me permet de le gérer dès le début, sans problème de buffering (comme l’a expliqué GPT).
J'ai le même problème de buffering avec Django également.
@app.post("/upload") async def upload_stream(request: Request): total_size = 0 async for chunk in request.stream(): if not chunk: break start_time = time.time() total_size += len(chunk) print(f"Reçu {len(chunk)} octets, total = {total_size}") if total_size > MAX_UPLOAD_SIZE: raise HTTPException(status_code=413, detail="Upload exceeds max size") elapsed_time = time.time() - start_time expected_time = len(chunk) / ( 0.2 * 1024 * 1024 ) # 5Mo/s if elapsed_time < expected_time: await asyncio.sleep(expected_time - elapsed_time) return JSONResponse(content={"detail": "Upload processed", "total_size": total_size})
/\
Ce code est utilisé par FastAPI pour gérer les uploads sans buffering. Mais comme je l’ai mentionné, je fais des commandes bloquantes comme :
query = {"uploadTime": {"$lte": last_uploaded}} files_cursor = collection.find(query) \ .sort("uploadTime", -1) \ .skip((page - 1) * per_page) \ .limit(per_page)
Cela bloque le serveur pendant l’exécution de la commande, ce qui pose problème, car je gère un très grand nombre de demandes et je ne peux pas me permettre de tout bloquer. C’est là qu’intervient le multithreading : je dois faire du vrai parallélisme (comme avec Threading).
Le problème, c’est que FastAPI ne supporte pas cela, tandis que Flask, lui, place chaque demande dans un nouveau thread, mais il a l’inconvénient de ne pas permettre des uploads dynamiques.
| **Critères** | **Django** | **Flask** | **FastAPI** |
|----------------------------------------------------|-----------------|----------------|--------------------|
| **MultiThread** |je sais pas | ✅ | ❌ |
| **Contrôle du Stream des Uploads**| ❌ | ❌ | ✅ |
Est-il nécessaire d'utiliser la même technologie pour tous les url? Pourquoi se limiter à un seul framework?
La plupart des serveurs web permettent de configurer quelles requêtes sont gérées par quel framework.
Il me semblerait logique d'utiliser différents framework pour différentes fonctions (file upload, ...).
Bonjour,
Peut-on imaginer surcharger dans flask certains décorateurs / méthodes afin qu'au lieu d'utiliser app.config['MAX_CONTENT_LENGTH'], on utilise une taille passée en paramètre desdits décorateurs / méthodes ? Voir par exemple ici.
Bonne chance
Bonjour,
Merci pour ta réponse, même si je pense qu’on ne s’est pas totalement compris sur mes contraintes.
1. Sur les "objectifs techniques" :
Ce ne sont pas des choix arbitraires. Si j'exclus l'asynchrone, ce n'est pas par goût personnel ou par ignorance, c’est parce que :
Je travaille avec des modules synchrones, certains natifs, d'autres plus bas niveau, qui ne sont pas compatibles avec l’async/await. Les forcer à fonctionner dans un contexte asynchrone, c’est prendre des risques de blocage, de fuites mémoire, ou de comportements imprévisibles.
En pratique, j’ai déjà testé FastAPI, et j’ai été confronté à ces problèmes : complexité inutile, erreurs silencieuses, mauvaise compatibilité avec certaines bibliothèques.
2. Sur la gestion de l’upload :
Je suis bien conscient qu’on peut gérer les uploads autrement.
Mais mon retour d’expérience avec Flask, par exemple, montre que le traitement du fichier ne commence qu’une fois l’intégralité reçue.
- Cela veut dire que je n’ai aucun contrôle sur les chunks ou les headers en amont, ce qui laisse une fenêtre exploitable pour un upload flood avant que mon app n’ait la main.
C’est exactement ce que j’essaie d’éviter. Je veux pouvoir intercepter les données dès les premiers octets si nécessaire.
3. Sur les protections :
Je ne compte évidemment pas uniquement sur l’application pour sécuriser le système :
J’ai NGINX en reverse proxy, avec des limites de débit, de taille, etc...
Des pare-feu en amont
Et la couche applicative en dernière ligne
Mais je veux aussi avoir un contrôle bas niveau côté serveur applicatif, surtout pour les cas où les protections frontales ne suffisent pas (attaque bien formée, contournement, etc..). Je ne veux pas que l’app soit passive dans ce modèle.
4. Et enfin, sur les ressources, budget et compétences :
Justement, mon approche prend en compte :
Le besoin d’un système ultra optimisé, stable, et sûr
Avec des outils que je maîtrise à fond, en synchrones, et qui peuvent monter en charge via Gunicorn + multithreading
.