Dead Letter Exchanges (DLX)
Konfigurera Dead Letter Exchanges för att hantera meddelanden som inte kan levereras eller behandlas korrekt. Implementera robust felhantering och strategier för att behandla meddelanden på nytt.
Dead Letter Exchanges (DLX) är en gratis lektion i RabbitMQ-meddelanden och asynkrona system på CoddyKit. Detta är lektion 3 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för RabbitMQ-meddelanden och asynkrona system, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i RabbitMQ-meddelanden och asynkrona system innehåller totalt 4 lektioner.
Vad är en Dead Letter Exchange?
I meddelandeköer kan meddelanden ibland inte bearbetas korrekt. De kan vara ogiltiga eller så kan konsumenten misslyckas. Vad händer med dessa "problemmeddelanden"?
En Dead Letter Exchange (DLX) i RabbitMQ är en mekanism för att hantera meddelanden som inte kan levereras eller bearbetas. Den fungerar som en särskild brevlåda för post som inte kan levereras.
När meddelanden hamnar fel
Meddelanden blir "dead-lettered" (skickas till en DLX) under vissa specifika förhållanden:
- Avvisas av konsumenten: En konsument avvisar uttryckligen ett meddelande (med
basic.rejectellerbasic.nack) och angerrequeuesomfalse. - Meddelandets TTL löper ut: Ett meddelandes Time-To-Live (TTL) löper ut medan det ligger i en kö.
- Gräns för kölängd: Kön når sin maximala längd och nya meddelanden gör att äldre meddelanden tas bort.
- Meddelandet kan inte routas: Om ett meddelande publiceras till en exchange med flaggan mandatory, men inte kan routas till någon kö, kan det också bli dead-lettered. (Mindre vanligt, men möjligt.)
Grundläggande DLX-konfiguration
För att använda en DLX måste ni konfigurera huvudkön så att den pekar på den. Detta görs när ni deklarerar huvudkön:
x-dead-letter-exchange: Namnet på den exchange som dead-lettered-meddelanden ska skickas till.x-dead-letter-routing-key: En valfri routingnyckel som används vid publicering till DLX. Om den inte anges används det dead-lettered-meddelandets ursprungliga routingnyckel.
Ni måste också deklarera själva DLX:en och en 'dead-letter queue' (DLQ) som är bunden till DLX:en.
DLX-konfiguration och producent (Nack-exempel)
Nu konfigurerar vi en huvudkö som skickar avvisade meddelanden till en DLX. Den här producenten deklarerar en DLX, en dead-letter queue (DLQ) och binder ihop dem. Därefter deklarerar den vår main_queue och konfigurerar den så att den använder DLX:en.
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
public class DLXProducerNack {
private static final String MAIN_QUEUE_NAME = "main_nack_queue";
private static final String DLX_EXCHANGE_NAME = "dlx_exchange";
private static final String DLQ_QUEUE_NAME = "dlq_nack_queue";
private static final String DLQ_ROUTING_KEY = "dlq_nack_key";
public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
// 1. Declare DLX and DLQ
channel.exchangeDeclare(DLX_EXCHANGE_NAME, "topic", true);
channel.queueDeclare(DLQ_QUEUE_NAME, true, false, false, null);
channel.queueBind(DLQ_QUEUE_NAME, DLX_EXCHANGE_NAME, DLQ_ROUTING_KEY);
// 2. Declare main queue with DLX arguments
Map<String, Object> args = new HashMap<>();
args.put("x-dead-letter-exchange", DLX_EXCHANGE_NAME);
args.put("x-dead-letter-routing-key", DLQ_ROUTING_KEY);
channel.queueDeclare(MAIN_QUEUE_NAME, true, false, false, args);
String message = "Message to be rejected!";
channel.basicPublish("", MAIN_QUEUE_NAME, null, message.getBytes(StandardCharsets.UTF_8));
System.out.println(" [x] Sent '" + message + "' to " + MAIN_QUEUE_NAME);
}
}
}Konsument med Basic Reject
Den här konsumenten lyssnar på main_nack_queue. När den tar emot ett meddelande använder den basicReject(deliveryTag, false) för att avvisa det utan att lägga det i kön igen. Då skickas meddelandet till vår konfigurerade DLX. Konsumenten lyssnar också på DLQ:n för att visa det dead-lettered-meddelandet.
Kör producenten från föregående scen och kör sedan den här konsumenten.
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class DLXConsumerNack {
private static final String MAIN_QUEUE_NAME = "main_nack_queue";
private static final String DLQ_QUEUE_NAME = "dlq_nack_queue";
public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
// Consumer for the main queue, will reject messages
System.out.println(" [*] Waiting for messages in " + MAIN_QUEUE_NAME + ".");
DeliverCallback mainQueueDeliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
System.out.println(" [x] Received from " + MAIN_QUEUE_NAME + ": '" + message + "'");
System.out.println(" [x] Rejecting message. It should go to DLQ.");
channel.basicReject(delivery.getEnvelope().getDeliveryTag(), false); // Don't requeue
};
channel.basicConsume(MAIN_QUEUE_NAME, false, mainQueueDeliverCallback, consumerTag -> {});
// Consumer for the dead-letter queue
System.out.println(" [*] Waiting for messages in " + DLQ_QUEUE_NAME + " (DLQ).");
DeliverCallback dlqDeliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
System.out.println(" [DLQ] Received dead-lettered message: '" + message + "'");
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
};
channel.basicConsume(DLQ_QUEUE_NAME, false, dlqDeliverCallback, consumerTag -> {});
}
}DLX med meddelande-TTL (producent)
Meddelanden kan också bli dead-lettered om de löper ut. Den här producenten skickar ett meddelande med en kort Time-To-Live (TTL) på 5 sekunder till en huvudkö. Om ingen konsument bearbetar det inom den tiden blir det dead-lettered.
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.AMQP;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
public class DLXTTLProducer {
private static final String MAIN_QUEUE_NAME = "main_ttl_queue";
private static final String DLX_EXCHANGE_NAME = "dlx_exchange"; // Reuse DLX
private static final String DLQ_QUEUE_NAME = "dlq_ttl_queue"; // Separate DLQ for TTL
private static final String DLQ_ROUTING_KEY = "dlq_ttl_key";
public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
// Declare DLX and DLQ (if not already done)
channel.exchangeDeclare(DLX_EXCHANGE_NAME, "topic", true);
channel.queueDeclare(DLQ_QUEUE_NAME, true, false, false, null);
channel.queueBind(DLQ_QUEUE_NAME, DLX_EXCHANGE_NAME, DLQ_ROUTING_KEY);
// Declare main queue with DLX arguments and message TTL
Map<String, Object> args = new HashMap<>();
args.put("x-dead-letter-exchange", DLX_EXCHANGE_NAME);
args.put("x-dead-letter-routing-key", DLQ_ROUTING_KEY);
args.put("x-message-ttl", 5000); // Message TTL of 5 seconds
channel.queueDeclare(MAIN_QUEUE_NAME, true, false, false, args);
String message = "This message will expire!";
channel.basicPublish("", MAIN_QUEUE_NAME, null, message.getBytes(StandardCharsets.UTF_8));
System.out.println(" [x] Sent '" + message + "' to " + MAIN_QUEUE_NAME);
System.out.println(" [x] Message has a TTL of 5 seconds. It will dead-letter if not consumed.");
}
}
}Observera TTL-baserad dead-lettering (konsument)
Den här konsumenten lyssnar endast på dead-letter-kön (dlq_ttl_queue). Kör producenten från föregående scen och kör sedan den här konsumenten. Ni kommer att se meddelandet visas i DLQ:n när dess TTL på 5 sekunder har löpt ut, även om ingen konsument avvisar det.
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class DLXTTLConsumer {
private static final String DLQ_QUEUE_NAME = "dlq_ttl_queue";
public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
// Consumer for the dead-letter queue for TTL messages
channel.queueDeclare(DLQ_QUEUE_NAME, true, false, false, null);
System.out.println(" [*] Waiting for dead-lettered messages in " + DLQ_QUEUE_NAME + ".");
System.out.println(" Run DLXTTLProducer first, then wait 5 seconds.");
DeliverCallback dlqDeliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
System.out.println(" [DLQ] Received expired dead-lettered message: '" + message + "'");
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
};
channel.basicConsume(DLQ_QUEUE_NAME, false, dlqDeliverCallback, consumerTag -> {});
}
}Fördjupning i DLX-routingnycklar
När ett meddelande blir dead-lettered publiceras det till DLX:en. Routingnyckeln som används vid denna publicering är viktig:
- Som standard används meddelandets ursprungliga routingnyckel.
- Om ni anger
x-dead-letter-routing-keynär ni deklarerar huvudkön ersätter den nya nyckeln den ursprungliga.
Detta gör det möjligt att routa dead-lettered-meddelanden till olika dead-letter-köer baserat på deras ursprungliga sammanhang eller specifika feltyper.
Bearbeta dead-lettered-meddelanden igen
Syftet med en DLX är inte bara att lagra misslyckade meddelanden, utan också att erbjuda en väg för återställning. Vanliga strategier för att hantera meddelanden i DLQ:n är bland annat:
- Manuellt ingripande: Granska meddelanden i DLQ:n och publicera dem manuellt igen efter att det underliggande problemet har åtgärdats.
- Loggning och aviseringar: Logga helt enkelt informationen om det dead-lettered-meddelandet och utlösa aviseringar för vidare undersökning.
- Automatisk omförsökstjänst: En särskild konsument för DLQ:n som försöker bearbeta meddelanden igen efter en fördröjning, eventuellt med exponentiell backoff.
- Separat feltjänst: Rota dead-lettered-meddelanden till en särskild tjänst som enbart är avsedd för felhantering och rapportering.
Kontrollera era DLX-kunskaper
Vilka av följande förhållanden kan leda till att ett meddelande blir dead-lettered av RabbitMQ?
Repetition: Dead Letter Exchanges
I den här lektionen utforskade vi Dead Letter Exchanges (DLX) i RabbitMQ. Ni har lärt er följande:
- DLX tillhandahåller en robust felhanteringsmekanism för meddelanden som inte kan bearbetas.
- Meddelanden blir dead-lettered på grund av att konsumenten avvisar dem, att TTL löper ut eller att kön når sin längdgräns.
- Ni konfigurerar en huvudkö med
x-dead-letter-exchangeochx-dead-letter-routing-key. - Praktiska exempel visade hur DLX konfigureras för avvisade och utgångna meddelanden.
- Vi gick igenom strategier för att bearbeta meddelanden från en dead-letter-kö igen.
DLX är ett viktigt verktyg för att bygga robusta och feltåliga meddelandesystem.
Lär dig RabbitMQ-meddelanden och asynkrona system med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 11
- Lektioner
- 44
Vanliga frågor
Är lektionen ”Dead Letter Exchanges (DLX)” gratis?
Ja – du kan läsa vilka 3 lektioner som helst i lärvägen RabbitMQ-meddelanden och asynkrona system, inklusive ”Dead Letter Exchanges (DLX)”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i RabbitMQ-meddelanden och asynkrona system innehåller totalt 4 lektioner.
Vad lär jag mig i ”Dead Letter Exchanges (DLX)”?
Konfigurera Dead Letter Exchanges för att hantera meddelanden som inte kan levereras eller behandlas korrekt. Implementera robust felhantering och strategier för att behandla meddelanden på nytt. Ni övar på RabbitMQ-meddelanden och asynkrona system med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig RabbitMQ-meddelanden och asynkrona system?
Du behöver inga förkunskaper. Utbildningen i RabbitMQ-meddelanden och asynkrona system på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.
Hur lång tid tar lektionen ”Dead Letter Exchanges (DLX)”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här RabbitMQ-meddelanden och asynkrona system-lektionen?
Ja. Varje RabbitMQ-meddelanden och asynkrona system-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Headers-exchange på djupet
- Bindings mellan exchanges
- Dead Letter Exchanges (DLX)
- Alternativa exchanges för oroutningsbara meddelanden