Files d'attente et équilibrage des tâches
1) Pourquoi les files d'attente de tâches
La file d'attente des tâches (job queue/work queue) sépare les producteurs et les artistes en termes de temps et de vitesse :- Lisse les pics : tampon entre le front et les sous-systèmes lourds.
- Stabilise les SLA : priorités et isolation des classes de charge.
- Simplifie la tolérance aux pannes : Retrai, DLQ, refonte.
- S'adapte horizontalement : ajoutez des workers sans changer d'API.
Domaines types : traitement des paiements, notations, génération de rapports/médias, post-traitement ETL/ML, intégration avec des API externes.
2) Modèle et concepts de base
Producteur : publie la tâche (payload + métadonnées : clé d'identité, priorité, date limite).
File d'attente/topic : tampon/journal des tâches.
Worker : prend la tâche, la traite, la confirme (ack) ou la renvoie avec une erreur.
Visibility Timeout/Lease : « louer » une tâche pendant la durée du traitement, après - auto-rare.
DLQ (Dead Letter Queue) : « enterrer » les tâches après une limite de tentatives/erreurs fatales.
Rate Limit/Concurrency : restrictions de consommation per-worker/per-queue/per-tenant.
- Pull : le worker demande lui-même la tâche (dosage de la charge).
- Push : le courtier pouffe ; Il faut une protection contre le « remplissage » des voleurs faibles.
3) Sémantiques de livraison et de confirmation
At-most-once : pas de retraits ; plus rapide, mais une perte possible.
At-least-once (défaut pour la plupart des files d'attente) : des doublons sont possibles → l'idempotence du gestionnaire est requise.
Effectively exactly-once : atteint au niveau de l'application (idempotence, dedup store, transactions/outbox). Un courtier peut aider, mais pas une « balle magique ».
- Ack/Nack : résultat clair.
- Requeue/Retry: с backoff + jitter.
- Message de poison : envoyer à DLQ.
4) Équilibrage et planification
4. 1 Priorité et algorithmes
FIFO : simple et prévisible.
Queue de priorité : classes prioritaires (P0... P3).
WRR/WSR (Weighted Round-Robin/Random) : parts de CPU/cherezput entre les classes.
WFQ/DRR (équivalent des files d'attente « justes » sur les réseaux) : parts per-tenant/client.
Deadline/EDF : pour les tâches avec deadlines.
Fair Partager : limiter les « voisins bruyants ».
4. 2 Flux de traitement
Simple-flight/Coalescing : combinez les tâches dupliquées par clé.
Caps de concurrence : limites strictes de parallélisme par type de tâche/intégration (API externes).
4. 3 Géo et Chardonnages
Les chardons par clé (tenant/id) → la localisation des données, l'ordre stable dans les chardons.
Sticky aux caches/ressources : hachage en routeurs avec état « attaché ».
5) Retrai, backoff et DLQ
Backoff exponentiel + jitter : 'base 2 ^ attempt ± random'.
Maximum de tentatives et une date limite commune (time-to-die) par tâche.
Classification des erreurs : 'retryable' (réseau/limite), 'non retryable' (validation/interdiction commerciale).
Parking/Delay Queue : tâches retardées (par exemple, répéter après 15 min).
DLQ-Politique : Indiquer où et dans quelles conditions le message « toxique » arrive ; prévoyez un reprocessor.
6) Idempotence et déduplication
Idempotency-Key dans la tâche ; store (Redis/DB) avec TTL pour les N dernières clés :- seen → skip/merge/result-cache.
- Clés naturelles : utilisez 'order _ id/ payment_id' au lieu d'UUID aléatoires.
- Outbox : enregistre le fait de la tâche et son statut dans une seule transaction OBD avec une opération d'entreprise.
- Exactly-once dans le bleu : 'UPSERT' par clé, vérification des versions, 'at-least-once' dans la file d'attente + idempotence dans la base de données.
7) Multi-tenance et classes SLA
Séparez les files d'attente/strimes par classe : 'critical', 'standard', 'bulk'.
Quotas et priorités per-tenant (Gold/Silver/Bronze).
Isolation : pools dedicate de workers sous P0 ; l'arrière-plan est dans un cluster/node distinct.
Contrôle d'admission : ne pas prendre plus que ce que vous pouvez traiter en deadline.
8) Auto Skaling Workers
Métriques pour le skaling : queue depth, rate arrival, temps de traitement, deblines SLA.
KEDA/Horizon Pod Autoscaler : déclencheurs par profondeur SQS/Rabbit/Kafka lag.
Facteurs dissuasifs : API externe des limites de taux, base de données (ne pas détruire le backend).
9) Options technologiques et modèles
9. 1 RabbitMQ/AMQP
Exchanges: direct/topic/fanout; Queues с ack/ttl/DLQ (dead-letter exchange).
Prefetch (QoS) règle le « nombre de tâches sur le worker ».
ini x-dead-letter-exchange=dlx x-dead-letter-routing-key=jobs.failed x-message-ttl=60000
9. 2 SQS (et équivalents)
Visibility Timeout, DelaySeconds, RedrivePolicy (DLQ).
L'idempotence est sur l'annexe (tableau dedup).
Limites : batchi 1-10 messages ; orientez-vous vers les bleus idempotent.
9. 3 Kafka/NATS JetStream
Pour les piplines à grande échelle : haut débit, rétention/repli.
Task-queue au-dessus des logs : une tâche = un message ; contrôle « un worker par clé » via le lot/subject.
Retrai : Tops individuels/subject-suffixes avec backoff.
9. 4 files d'attente Redis (Sidekiq/Resque/Bull/Celery-Redis)
Latence très faible ; surveillez la stabilité (RDB/AOF), les clés retry et lock-keys pour le vol unique.
Convient pour les tâches « légères », pas pour les rétentions à long terme.
9. 5 Cadres
Celery (Python), Sidekiq (Ruby), RQ/BullMQ (Node), Huey/Resque sont des retraits prêts, des horaires, middleware, métriques.
10) Circuits de routage et d'équilibrage
Round-Robin : uniforme mais ne tient pas compte de la « gravité » des tâches.
Weighted RR : répartition par capacité de worker/pool.
Fair/Backpressure-aware : Le voleur ne prend une nouvelle tâche que lorsqu'il est prêt.
Priority lanes : files d'attente séparées par classe ; les workers lisent dans l'ordre [P0→... →Pn] s'il y en a.
Hash-routing : 'hash (key) % shards' - pour le traitement stateful/cache.
11) Taimauts, deblines et SLA
Per-task timeout : travail interne « location » (dans le code worker) ≤ Visibility Timeout du courtier.
Global deadline : la tâche n'a aucun sens après T temps - NACK→DLQ.
Budget-aware : réduisez le travail (brownout) lorsque vous approchez de la date limite (résultats partiels).
12) Observation et gestion
12. 1 Métriques
`queue_depth`, `arrival_rate`, `service_rate`, `lag` (Kafka), `invisible_messages` (SQS).
`success/failed/retired_total`, `retry_attempts`, `dlq_in_total`, `processing_time_ms{p50,p95,p99}`.
`idempotency_hit_rate`, `dedup_drops_total`, `poison_total`.
12. 2 Logs/tracing
Corrélation : 'job _ id', 'correlation _ id', clé de déduplication.
Notez 'retry/backoff/dlq' comme événements ; lingot avec span de la requête source.
12. 3 Dashboards/alertes
Déclencheurs : profondeur> X, p99> SLO, croissance DLQ, tâches « bouffées » (visibility expirée> N), clés « chaudes ».
13) Sécurité et conformité
Isolation des locataires : files d'attente séparées/espace clé, ACL, quotas.
Cryptage dans les transports et/ou « au repos ».
PII-minimisation dans payload ; hash/ID au lieu de PII brut.
Secrets : ne mettez pas de tokens dans le corps des tâches, utilisez vault/refs.
14) Anti-modèles
Retrai sans idempotence → prise d'opérations/argent « deux fois ».
Il n'y a pas d'isolement → pas de retards imprévisibles.
Des retraits sans fin sans DLQ → des tâches éternelles « toxiques ».
Visibility Timeout <temps de traitement → duplications en cascade.
Les gros payload dans la file d'attente → pressent le réseau/mémoire ; il est préférable de le stocker dans le store d'objet et de transmettre le lien.
Le modèle push sans backpressure → les workers sont étouffés.
Mélange des tâches critiques et bulk dans un pool de workers.
15) Chèque de mise en œuvre
- Classer les tâches par SLA (P0/P1/P2) et volume.
- Choisissez un courtier/cadre avec la sémantique et la rétention souhaitées.
- Concevoir les clés, les priorités et le routage (hash/shards/priority lanes).
- Inclure les retraits avec backoff + jitter et la politique DLQ.
- Implémentez l'idempotence (clés, upsert, dedup store avec TTL).
- Configurez les délais : per-task, visibility, deadline partagée.
- Limiter la concurrence et le taux sur les intégrations/tenants.
- Skaling automatique par profondeur/lagune avec fusibles.
- Métriques/tracing/alertes ; runbooks sur la « tempête » et le débordement de DLQ.
- Tests de faux : chute d'un worker, message « toxique », surcharge, longues tâches.
16) Exemples de configurations et de code
16. 1 Celery (Redis/Rabbit) - flow de base
python app = Celery("jobs", broker="amqp://...", backend="redis://...")
app.conf.task_acks_late = True # ack после выполнения app.conf.broker_transport_options = {"visibility_timeout": 3600}
app.conf.task_default_retry_delay = 5 app.conf.task_time_limit = 300 # hard timeout
@app.task(bind=True, autoretry_for=(Exception,), retry_backoff=True, retry_jitter=True, max_retries=6)
def process_order(self, order_id):
if seen(order_id): return "ok" # идемпотентность do_work(order_id)
mark_seen(order_id)
return "ok"
16. 2 RabbitMQ — DLQ/TTL
ini x-dead-letter-exchange=dlx x-dead-letter-routing-key=jobs.dlq x-message-ttl=600000 # 10 минут x-max-priority=10
16. 3 Kafka - retraits par niveaux
orders -> orders.retry.5s -> orders.retry.1m -> orders.dlq
(Transférer avec livraison retardée via scheduler/cron-consumer.)
16. 4 NATS JetStream — consumer с backoff
bash nats consumer add JOBS WORKERS --filter "jobs.email" \
--deliver pull --ack explicit --max-deliver 6 \
--backoff "1s,5s,30s,2m,5m"
17) FAQ
Q : Quand choisir push vs pull ?
A : Pull donne un backpressure naturel et un équilibrage « honnête » ; push est plus facile à basse vitesse et lorsque vous avez besoin d'un minimum de TTFB, mais nécessite des limiteurs.
Q : Comment éviter la clé « chaude » ?
A : Chargez par la clé composite ('order _ id % N'), tamponnez et effectuez le traitement de batch, entrez les limites de la clé per.
Q : Est-il possible de « exactly-once » ?
R : Pratiquement - par l'idempotence et l'outbox transactionnel. Tout à fait « mathématique » exactly-once sur tout le chemin est rarement réalisable et coûteux.
Q : Où stocker de gros investissements de tâche ?
A : Dans le stockage d'objets (S3/GCS) et dans la tâche - référence/ID ; réduit la pression sur le courtier et le réseau.
Q : Comment choisir TTL/visibility ?
A : Visibilité ≥ p99 temps de traitement × stock de 2-3 ×. TTL tâche - moins d'entreprise debline.
18) Résultats
Un système de files d'attente fort est un équilibre entre la sémantique de la livraison, les priorités et les limiteurs. Concevez les clés et le routage, assurez l'idempotence, les retraits avec backoff et DLQ, répartissez les ressources en classes SLA et surveillez les métriques. Vos processus de fond seront alors prévisibles, durables et évolutifs - sans surprise sous les pics.