Comparthing Logo
accodamento dei messaggimodelli di affidabilitàsistemi distribuitiarchitettura cloudgestione degli erroriinfrastruttura cloud

Code di messaggi non recapitabili vs. tentativi in memoria

Le code di messaggi non recapitabili (DLQ) e i tentativi di ripetizione in memoria rappresentano due approcci fondamentalmente diversi alla gestione degli errori di elaborazione dei messaggi nei sistemi distribuiti: le DLQ forniscono un isolamento duraturo dei messaggi problematici, mentre i tentativi di ripetizione in memoria offrono un ripristino leggero e a bassa latenza, senza overhead di persistenza.

In evidenza

  • Le code di messaggi non recapitabili conservano i messaggi non recapitati a tempo indeterminato, risultando quindi essenziali per gli scenari di audit e conformità.
  • I tentativi di ripetizione in memoria vengono eseguiti con un overhead dell'ordine dei microsecondi, rispetto alle latenze superiori ai millisecondi delle operazioni in coda.
  • Le DLQ consentono a team operativi separati di gestire i guasti senza dover implementare modifiche al codice dell'applicazione.
  • Le tempeste di tentativi derivanti da approcci in memoria possono innescare guasti a cascata se non delimitate da interruttori automatici.

Cos'è Code di lettere non recapitate?

Code di messaggi persistenti che acquisiscono i messaggi non elaborati correttamente per una successiva ispezione e rielaborazione.

  • I messaggi vengono spostati nella coda dei messaggi non recapitabili (DLQ) dopo aver superato il numero massimo di tentativi, preservando il contenuto completo e i metadati.
  • Inizialmente reso popolare dai sistemi di messaggistica aziendale come IBM MQ e JMS, ora è uno standard in AWS SQS, Azure Service Bus e RabbitMQ.
  • Consente l'analisi dei guasti disaccoppiata senza bloccare le pipeline di elaborazione principali, permettendo ai team di risolvere i problemi e riprodurre i messaggi
  • In genere si integrano con i sistemi di monitoraggio e allerta per notificare agli operatori quando i messaggi entrano nello stato di "lettera morta".
  • Supporto per le policy di scadenza basate sul tempo, con le DLQ di AWS SQS che conservano i messaggi fino a 14 giorni per impostazione predefinita.

Cos'è Tentativi in memoria?

Logica di ritentativo immediato eseguita all'interno dello stesso processo senza persistenza di messaggi esterni.

  • Le politiche di ritentativo implementano comunemente un backoff esponenziale, con ritardi che raddoppiano tra i tentativi (ad esempio, 1 secondo, 2 secondi, 4 secondi, 8 secondi).
  • Framework come Polly (.NET), Resilience4j (Java) e Retry (Python) forniscono strategie di ritentativo configurabili con modelli di interruzione di circuito.
  • Non consumare risorse infrastrutturali aggiuntive oltre alla memoria e alla CPU già presenti nell'applicazione di elaborazione.
  • Fallisce completamente se l'applicazione si arresta in modo anomalo durante un nuovo tentativo, perdendo lo stato del tentativo e potenzialmente il contesto operativo originale.
  • Ideale per guasti transitori come interruzioni di rete, timeout di connessione al database e indisponibilità temporanea del servizio.

Tabella di confronto

Funzionalità Code di lettere non recapitate Tentativi in memoria
Persistenza Archiviazione permanente dei messaggi in una coda separata Effimero, esiste solo nella memoria dell'applicazione.
Ripristino in caso di guasto Resiste ai crash e ai riavvii dell'applicazione. Perso se il processo termina durante il tentativo
Costo delle infrastrutture Costi aggiuntivi di archiviazione e trasferimento della coda Nessuna infrastruttura aggiuntiva oltre all'applicazione.
Visibilità operativa Metriche integrate, allarmi e funzionalità di riproduzione Richiede registrazione e monitoraggio personalizzati
Impatto della latenza Latenza più elevata dovuta alle operazioni di coda Latenza minima, esecuzione immediata dei tentativi.
Caso d'uso adatto Flussi di lavoro critici che richiedono un'elaborazione garantita Operazioni non critiche con guasti transitori
Ordinamento dei messaggi Può preservare o alterare l'ordine originale Mantiene naturalmente la sequenza del processo
Collaborazione di squadra Consente la gestione separata delle squadre per la correzione e la riproduzione Strettamente legato alla distribuzione dell'applicazione

Confronto dettagliato

Garanzie di affidabilità e durata

Le code di messaggi non recapitabili (DLQ) sono ideali quando non è assolutamente possibile perdere messaggi. Una volta che un messaggio finisce in una DLQ, vi rimane finché qualcuno non se ne occupa esplicitamente, anche se l'intero servizio viene riavviato. I tentativi di invio in memoria, al contrario, svaniscono nel nulla se il pod si arresta in modo anomalo o il processo viene interrotto durante un'implementazione. Questo rende le DLQ la scelta ideale per transazioni finanziarie, aggiornamenti di inventario o qualsiasi attività legata alla conformità normativa.

Caratteristiche di prestazioni e latenza

tentativi in memoria vincono a mani basse in termini di velocità. Non c'è alcun passaggio di rete, nessuna chiamata API alla coda, nessun overhead di serializzazione, solo una breve pausa e un nuovo tentativo. Per i sistemi ad alto throughput che elaborano migliaia di messaggi al secondo, questa differenza si fa sentire. Le DLQ introducono una latenza misurabile, soprattutto quando i messaggi devono attraversare i confini della rete per raggiungere un servizio di coda separato. Alcuni team adottano un approccio ibrido, utilizzando i tentativi in memoria per correzioni rapide e temporanee e le DLQ come ultima risorsa.

Complessità operativa e debug

Le code di messaggi non recapitabili (DLQ) creano un confine operativo ben definito. Il tecnico di turno viene avvisato, esamina la coda, corregge il bug sottostante e riproduce i messaggi. Si tratta di un flusso di lavoro ben noto. I tentativi di ripetizione in memoria, invece, seppelliscono gli errori nei log dell'applicazione, spesso richiedendo l'aggregazione dei log e dashboard personalizzate per sapere che i tentativi sono in corso. Quando i tentativi si esauriscono, il sistema di risoluzione degli errori diventa un vero incubo, soprattutto nei microservizi, dove l'errore potrebbe propagarsi a cascata prima che qualcuno se ne accorga.

Considerazioni sui costi su larga scala

I servizi di code cloud addebitano un costo per richiesta e per messaggio memorizzato. Una coda di messaggi non recapitabili (DLQ) molto trafficata, con milioni di messaggi, può avere un impatto significativo sulla bolletta, soprattutto se le politiche di conservazione sono permissive. I tentativi di risposta in memoria sono sostanzialmente gratuiti dal punto di vista dell'infrastruttura, sebbene consumino memoria e possano sovraccaricare altri thread se il numero di tentativi non viene limitato. Per le startup attente ai costi, questo spesso fa pendere la bilancia a favore delle soluzioni in memoria, finché i ricavi non giustificano il costo aggiuntivo in termini di affidabilità.

Integrazione con le architetture moderne

Le architetture event-driven e le funzioni serverless hanno reso le DLQ (Dead Letter Queues) più rilevanti che mai. AWS Lambda, Azure Functions e Google Cloud Functions supportano nativamente le configurazioni di dead letter. I tentativi di ripetizione in memoria si integrano più naturalmente nei server applicativi tradizionali e nei processi a lunga esecuzione. L'ascesa di Kubernetes e del calcolo effimero ha di fatto complicato le strategie in memoria: i container possono essere terminati con scarso preavviso, rendendo le DLQ sempre più interessanti anche per i team che in precedenza le evitavano.

Pro e Contro

Code di lettere non recapitate

Vantaggi

  • + Durata del messaggio garantita
  • + Passaggio di consegne operativo chiaro
  • + Integrazione nativa del cloud
  • + Supporta la riproduzione e la verifica
  • + Isola l'impatto del guasto

Consentiti

  • Costi aggiuntivi per le infrastrutture
  • Latenza end-to-end più elevata
  • Richiede un meccanismo di riproduzione
  • Può accumulare messaggi obsoleti
  • Architettura più complessa

Tentativi in memoria

Vantaggi

  • + Latenza estremamente bassa
  • + Nessuna infrastruttura aggiuntiva
  • + Semplice da implementare inizialmente
  • + Costi operativi minimi
  • + Feedback rapido in caso di guasto

Consentiti

  • Perso a causa di un arresto anomalo del processo
  • Nascosto dalle operazioni
  • Può causare tempeste di tentativi
  • Stretto accoppiamento con il ciclo di vita dell'applicazione.
  • Più difficile da debuggare a posteriori.

Idee sbagliate comuni

Mito

Le code di messaggi non recapitabili eliminano la necessità di qualsiasi logica di ritentativo nelle applicazioni.

Realtà

Le DLQ sono la destinazione finale dopo l'esaurimento dei tentativi di invio, non un sostituto della logica di ritentativo. La maggior parte delle implementazioni esegue ancora tentativi di invio immediati o ritardati prima ancora di considerare un messaggio non valido. Senza tentativi intermedi, ogni piccolo problema temporaneo inonderebbe immediatamente la DLQ.

Mito

I tentativi di accesso in memoria sono sempre più veloci e quindi offrono prestazioni migliori.

Realtà

Sebbene i singoli tentativi siano più veloci, un numero illimitato di tentativi in memoria può saturare i pool di thread e degradare la velocità di elaborazione complessiva del sistema. Il vantaggio in termini di prestazioni scompare rapidamente quando un'ondata di tentativi attiva i circuit breaker o sovraccarica i servizi a valle.

Mito

I messaggi presenti nelle code di messaggi non recapitabili vengono elaborati automaticamente in un secondo momento.

Realtà

Le DLQ sono archivi passivi: non succede nulla a quei messaggi finché non viene intrapresa un'azione esplicita, umana o automatizzata. Molti team hanno scoperto messaggi vecchi di mesi che languivano nelle DLQ perché nessuno aveva implementato la pipeline di replay.

Mito

È necessario scegliere esclusivamente tra DLQ e tentativi di accesso in memoria.

Realtà

Questi modelli si completano a vicenda in modo eccellente. I sistemi più resilienti utilizzano tentativi in memoria con backoff esponenziale per un ripristino rapido, per poi passare alle DLQ (Download Line Queue) dopo una soglia ragionevole. Questo approccio a livelli copre sia le modalità di errore transitorie che quelle persistenti.

Mito

I tentativi di accesso in memoria non sono adatti ai sistemi distribuiti.

Realtà

Sebbene meno robusti delle DLQ, i tentativi di ripetizione in memoria rimangono comuni e appropriati nei sistemi distribuiti per operazioni idempotenti e non critiche. La chiave sta nell'adattare la strategia di ripetizione alle effettive conseguenze aziendali di un eventuale errore, senza presumere che un unico modello sia adatto a tutti i casi.

Mito

Le code di messaggi non recapitabili impediscono la perdita di messaggi durante le interruzioni di sistema.

Realtà

Le DLQ sono utili solo per i messaggi già accettati dal sistema di accodamento. Se il messaggio non raggiunge la coda primaria a causa di un'interruzione di rete o di un guasto del produttore, la DLQ non può recuperarlo magicamente. L'affidabilità end-to-end richiede anche la persistenza lato produttore.

Domande frequenti

Cosa fa sì che un messaggio venga spostato nella coda dei messaggi non recapitabili?
I messaggi in genere entrano nella coda dei messaggi non recapitabili (DLQ) dopo aver esaurito i tentativi di retry configurati, il che potrebbe significare aver superato un numero massimo di ricezioni in SQS, non essere riusciti a recapitare i messaggi a più destinatari o essere stati esplicitamente rifiutati dal codice dell'applicazione. Il fattore scatenante esatto varia a seconda della piattaforma: AWS SQS utilizza una policy di redrive che specifica il numero massimo di ricezioni, mentre Azure Service Bus tiene traccia del numero di consegne. Una volta superata tale soglia, l'infrastruttura di messaggistica sposta o copia automaticamente il messaggio nella coda dei messaggi non recapitabili associata.
Come gestiscono i tentativi in memoria i riavvii o i crash dei processi?
Non lo fanno, e questa è la loro limitazione fondamentale. Qualsiasi stato di ritentativo esiste esclusivamente nell'heap del processo in esecuzione. Se l'applicazione si arresta in modo anomalo, viene terminata durante un'implementazione o il container viene riprogrammato, tutti i ritentativi in sospeso e il loro contesto scompaiono. Per le operazioni che devono sopravvivere a tali eventi, sono necessari meccanismi di ritentativo persistenti, che si tratti di una DLQ, di una coda di processi basata su database o di sistemi di attività distribuiti come Celery o Hangfire.
È possibile combinare code di messaggi non recapitabili con tentativi di ripetizione in memoria nello stesso sistema?
Assolutamente, e questa è effettivamente una best practice per molti team. Il modello tipico prevede tentativi in memoria con backoff esponenziale per un ripristino immediato e temporaneo, ad esempio tre tentativi in pochi secondi. Se questi falliscono, il messaggio o l'operazione viene pubblicato in una coda con supporto DLQ per una gestione duratura. Questo offre la velocità dei tentativi in memoria per i picchi di traffico e la sicurezza delle DLQ per i problemi persistenti.
Quali sistemi di monitoraggio è opportuno impostare per le code di messaggi non recapitabili?
Come minimo, configurate gli allarmi sulla profondità della coda, sull'età del messaggio più vecchio e sulla frequenza dei messaggi in arrivo. Un picco improvviso negli arrivi in DLQ di solito indica un bug implementato. Gli avvisi sull'età dei messaggi individuano i casi in cui la riproduzione non avviene. Molti team monitorano anche il rapporto tra i messaggi in DLQ e i messaggi elaborati correttamente come indicatore di salute. CloudWatch, Azure Monitor o Datadog possono tutti visualizzare queste metriche tramite l'integrazione con i cercapersone.
Esistono alternative sia alle DLQ che ai tentativi di accesso in memoria?
Diversi modelli rispondono a esigenze simili. Il modello Outbox rende persistenti gli eventi a livello transazionale insieme ai dati aziendali, garantendo l'atomicità. Il modello Saga gestisce transazioni distribuite di lunga durata con azioni compensative. Le code di processi basate su database come Sidekiq o pg-boss offrono la persistenza senza la necessità di broker di messaggi dedicati. L'event sourcing ricostruisce lo stato da un log di sola aggiunta, rendendo diversa la semantica dei tentativi. La scelta giusta dipende dai requisiti di coerenza e dall'infrastruttura esistente.
Come si possono riprodurre in modo sicuro i messaggi da una coda di messaggi non recapitabili?
Non riprodurre mai direttamente i messaggi nella coda originale senza prima ispezionarli, perché questo crea cicli infiniti se la causa principale persiste. Piuttosto, reindirizza i messaggi dalla coda DLQ a un ambiente di analisi separato, esamina campioni rappresentativi per identificare lo schema di errore, risolvi il problema di fondo e poi riproduci i messaggi in batch in modo selettivo, monitorando la situazione. AWS offre funzionalità di ritrasmissione della coda DLQ e strumenti come Amazon EventBridge Pipes possono automatizzare i flussi di lavoro di riproduzione condizionale.
Quali sono le caratteristiche di una buona politica di ritentativo per i tentativi di accesso in memoria?
Il backoff esponenziale con jitter è lo standard di riferimento. Senza jitter, i tentativi sincronizzati da più client possono creare gravi problemi di sovraccarico per i servizi in fase di ripristino. Limita il ritardo massimo per evitare attese illimitate e imposta sempre un numero massimo di tentativi. Considera l'utilizzo di circuit breaker che interrompono completamente i tentativi quando i tassi di errore superano determinate soglie, dando ai servizi a valle il tempo di ripristinarsi anziché sovraccaricarli mentre sono inattivi.
Le funzioni serverless funzionano bene con i tentativi di ripetizione in memoria?
Non particolarmente. Lambda e funzioni simili sono progettate per essere stateless e di breve durata. Un tempo di esecuzione massimo di quindici minuti significa che la finestra di tentativi in memoria è limitata. Ancora più importante, se Lambda fallisce, l'intero contesto di esecuzione scompare. Le architetture serverless privilegiano fortemente lo stato esterno, rendendo le DLQ o le funzioni step con logica di tentativi integrata molto più adatte rispetto agli approcci in memoria.
In che modo le problematiche relative all'ordine dei messaggi differiscono tra questi approcci?
Le DLQ (Download Line Queue) possono complicare le garanzie di ordinamento. Se la coda primaria è FIFO (First-In, First-Out), lo spostamento di messaggi da e verso una DLQ potrebbe interrompere la sequenza, a meno che la piattaforma non preveda espressamente di preservare l'ordinamento. I tentativi di ripetizione in memoria all'interno di un singolo consumer mantengono naturalmente l'ordine dei messaggi di quel consumer, anche se più consumer elaborano comunque in parallelo. Alcuni sistemi utilizzano numeri di sequenza o un ordinamento a livello di applicazione per ricostruire la sequenza corretta dopo qualsiasi meccanismo di ripetizione.
Quali considerazioni di sicurezza si applicano alle code di lettere non recapitate?
Le code DLQ contengono gli stessi dati sensibili delle code primarie, a volte anche di più, poiché includono il contesto degli errori. Applica la stessa crittografia, gli stessi controlli di accesso e la stessa registrazione degli eventi. Fai attenzione ai meccanismi di riproduzione: la rielaborazione di vecchi messaggi potrebbe innescare effetti collaterali imprevisti se i sistemi a valle non sono idempotenti. Alcuni settori regolamentati richiedono flussi di lavoro di approvazione espliciti prima che i messaggi delle code DLQ possano essere consultati o riprodotti.
Quando è opportuno evitare completamente i tentativi di accesso in memoria?
Evitateli quando l'elaborazione ha effetti collaterali non idempotenti, ad esempio quando un doppio addebito su una carta di credito a causa di un tentativo di ripetizione è catastrofico. Evitateli quando la semantica "exactly-once" è importante e non disponete di deduplicazione. Non fate affidamento su di essi per operazioni di lunga durata in cui il processo potrebbe non durare abbastanza a lungo da completare i tentativi di ripetizione. E non utilizzateli quando i team operativi necessitano di visibilità sui modelli di errore senza implementare modifiche al codice.
Come si confrontano i costi a livello aziendale?
Una tipica configurazione AWS con code SQS standard e DLQ potrebbe costare qualche dollaro per milione di messaggi, più lo spazio di archiviazione per i messaggi conservati. Per un sistema che elabora miliardi di messaggi al mese, questo diventa un costo significativo. I tentativi di ripetizione in memoria spostano il costo sulla potenza di calcolo, che è già inclusa nel prezzo. Tuttavia, i picchi di tentativi di ripetizione possono aumentare l'utilizzo di CPU e memoria, potenzialmente richiedendo istanze di dimensioni maggiori. La maggior parte delle analisi del costo totale di proprietà privilegia la memoria per i flussi di lavoro a basso volume e bassa criticità e le DLQ per i flussi di lavoro essenziali a basso volume.

Verdetto

Scegliete le code di messaggi non recapitabili (dead letter queue) quando la perdita di messaggi è inaccettabile e i team operativi necessitano di confini di errore ben definiti da gestire. Optate per i tentativi in memoria (in-memory retries) quando la velocità è fondamentale, la semplicità dell'infrastruttura è un requisito imprescindibile e i guasti sono effettivamente transitori piuttosto che sistemici. Molti sistemi maturi combinano entrambe le soluzioni, utilizzando i tentativi in memoria per il ripristino immediato e le code di messaggi non recapitabili come ultima risorsa.

Confronti correlati

Aggregazione dei dati di telemetria vs. registrazione da un'unica fonte

L'aggregazione della telemetria consolida metriche, log e tracce provenienti da diverse fonti in un'unica pipeline, mentre la registrazione da una singola fonte si concentra sull'acquisizione e l'analisi dei dati provenienti da un'unica origine specifica. La scelta più appropriata dipende dalla complessità del sistema, dagli obiettivi di osservabilità e dalla scalabilità operativa.

AWS vs Google Cloud

Questo confronto esamina Amazon Web Services e Google Cloud analizzando le loro offerte di servizi, modelli di prezzo, infrastruttura globale, prestazioni, esperienza degli sviluppatori e casi d'uso ideali, aiutando le organizzazioni a scegliere la piattaforma cloud che meglio si adatta alle loro esigenze tecniche e aziendali.

Bilanciamento del carico nei sistemi di apprendimento automatico vs. gestione semplice delle richieste API

Nei sistemi di machine learning, il bilanciamento del carico gestisce i carichi di lavoro di inferenza e addestramento che richiedono un uso intensivo della GPU su hardware specializzato, mentre la semplice gestione delle richieste API distribuisce il traffico HTTP leggero su server generici. Le due soluzioni differiscono notevolmente in termini di complessità, requisiti di risorse e intelligenza di routing.

Cache locale vs. cluster di cache centralizzata

La cache locale memorizza i dati direttamente sui server applicativi per un accesso a bassissima latenza, mentre i cluster di cache centralizzati implementano un'infrastruttura dedicata e condivisa a cui più servizi possono accedere simultaneamente per una gestione dello stato coerente.

Calcolo distribuito contro centri dati centralizzati

Il calcolo distribuito ripartisce i carichi di lavoro su molte macchine interconnesse, mentre i data center centralizzati concentrano la potenza di elaborazione in un'unica struttura fisica. Entrambi gli approcci sono alla base dei moderni servizi cloud, ma differiscono notevolmente in termini di scalabilità, tolleranza ai guasti e struttura dei costi.