23 - Dead Letter Queue : ne plus perdre d'événements
Ce que tu vas apprendre
- Ce qu'est la Dead Letter Queue (DLQ) et quand elle se remplit
- Activer et configurer la DLQ
- Lire les événements de la DLQ avec un pipeline de reprocessing
- Les stratégies pour corriger et re-indexer les événements rejetes
- Surveiller la taille de la DLQ
Prerequisites
- Connaitre l'output Elasticsearch (voir article 17)
- Connaitre les pipelines multiples (voir article 20)
Le problème : Elasticsearch rejette des documents
Tu as un pipeline qui tourne depuis des semaines. Un jour, un développeur change le format d'un champ dans les logs : status_code passe de "200" (string) a 200 (integer). Ton mapping Elasticsearch attend un keyword. Le document est rejete avec un mapper_parsing_exception.
Sans la DLQ, cet événement est perdu. Logstash log l'erreur et passe au suivant. Avec la DLQ, l'événement est sauvegarde sur disque. Tu peux le corriger et le re-indexer plus tard.
Ce qui déclenché la DLQ
La DLQ recoit les événements que l'output Elasticsearch n'a pas pu indexer apres toutes les retries. Les causes les plus courantes :
| Erreur | Cause | Exemple |
|---|---|---|
mapper_parsing_exception |
Type de champ incorrect | String dans un champ integer |
illegal_argument_exception |
Valeur invalide | Date mal formee |
version_conflict_engine_exception |
Conflit de version | Deux updates simultanes du meme doc |
document_parsing_exception |
JSON invalide | Champ avec des caractères de contrôle |
Les erreurs 429 (Too Many Requests) et 503 (Service Unavailable) ne vont PAS dans la DLQ. Logstash les retente automatiquement (voir article 17).
Activer la DLQ
Dans logstash.yml
yaml# logstash/config/logstash.yml
dead_letter_queue.enable: true
dead_letter_queue.max_bytes: 1024mb
dead_letter_queue.storage_policy: drop_newer
dead_letter_queue.flush_interval: 5000
| Paramètre | Description |
|---|---|
dead_letter_queue.enable |
Active la DLQ (défaut: false) |
dead_letter_queue.max_bytes |
Taille max sur disque (défaut: 1024 Mo) |
dead_letter_queue.storage_policy |
Que faire quand la DLQ est pleine : drop_newer (défaut) ou drop_older |
dead_letter_queue.flush_interval |
Frequence d'écriture sur disque en ms |
Ou sont stockes les fichiers DLQ
/usr/share/logstash/data/dead_letter_queue/
└── main/ # nom du pipeline
├── 1.log # premier segment
├── 2.log # deuxieme segment
└── .lock # verrou
Monte un volume Docker pour persister la DLQ entre les redemarrages :
yamllogstash:
volumes:
- logstash-data:/usr/share/logstash/data
Le pipeline de reprocessing
Pour relire les événements de la DLQ, créé un pipeline dédié avec l'input dead_letter_queue :
# logstash/pipeline/dlq-reprocess.conf
input {
dead_letter_queue {
path => "/usr/share/logstash/data/dead_letter_queue"
pipeline_id => "main"
commit_offsets => true
}
}
filter {
# L'evenement original est dans les champs normaux
# Les metadonnees DLQ sont dans [@metadata]
# Voir la raison du rejet
ruby {
code => '
reason = event.get("[@metadata][dead_letter_queue][reason]")
plugin = event.get("[@metadata][dead_letter_queue][plugin_type]")
event.set("dlq_reason", reason)
event.set("dlq_plugin", plugin)
'
}
# Corriger le probleme selon le type d'erreur
if [dlq_reason] =~ /mapper_parsing_exception/ {
# Forcer la conversion des champs problematiques
mutate {
convert => {
"status_code" => "string"
"duration" => "string"
}
}
}
# Nettoyer les champs DLQ avant re-indexation
mutate {
remove_field => ["dlq_reason", "dlq_plugin"]
}
}
output {
elasticsearch {
hosts => ["http://elasticsearch:9200"]
index => "logs-recovered-%{+YYYY.MM.dd}"
}
}
Metadonnees DLQ
Chaque événement DLQ contient des metadonnees sur le rejet :
json{
"@metadata": {
"dead_letter_queue": {
"plugin_id": "elasticsearch_1",
"plugin_type": "elasticsearch",
"reason": "mapper_parsing_exception: failed to parse field [status_code] of type [keyword] in document...",
"entry_time": "2026-03-31T14:23:01.000Z"
}
}
}
plugin_id: quel output a rejete l'événementreason: le message d'erreur complet d'Elasticsearchentry_time: quand l'événement a ete mis en DLQ
pipelines.yml avec le pipeline DLQ
yaml- pipeline.id: main
path.config: "/usr/share/logstash/pipeline/main.conf"
pipeline.workers: 4
- pipeline.id: dlq-reprocess
path.config: "/usr/share/logstash/pipeline/dlq-reprocess.conf"
pipeline.workers: 1
pipeline.batch.size: 50
Le pipeline DLQ tourne en parallèle du pipeline principal. Il lit les événements rejetes, les corrige et les re-indexé dans un index séparé (logs-recovered-*).
Stratégies de correction
1. Convertir les types
La cause la plus frequente. Un champ a change de type dans les logs source.
filter {
mutate {
convert => {
"status_code" => "string"
}
}
}
2. Supprimer les champs problématiques
Si un champ est corrompu et que tu n'en as pas besoin :
filter {
mutate {
remove_field => ["corrupted_field"]
}
}
3. Re-indexer dans un index différent
Si le mapping de l'index original ne peut pas etre change (il est deja utilise par d'autres documents) :
output {
elasticsearch {
hosts => ["http://elasticsearch:9200"]
index => "logs-recovered-%{+YYYY.MM.dd}"
}
}
L'index logs-recovered-* a son propre mapping qui accepte les types corriges.
4. Envoyer les événements non recuperables dans un fichier
Si certains événements ne peuvent pas etre corriges :
output {
if [dlq_unrecoverable] == "true" {
file {
path => "/data/dlq-unrecoverable-%{+YYYY-MM-dd}.json"
codec => json_lines
}
} else {
elasticsearch {
hosts => ["http://elasticsearch:9200"]
index => "logs-recovered-%{+YYYY.MM.dd}"
}
}
}
Surveiller la DLQ
Verifie régulièrement la taille de la DLQ :
bash# Taille des fichiers DLQ
docker exec logstash du -sh /usr/share/logstash/data/dead_letter_queue/
Si la DLQ grossit, c'est qu'un problème recurrent envoie des événements en erreur. Corrige la cause racine (mapping, format de log, pipeline) plutot que de juste reprocesser.
Sur paltemps.fr, on a une alerte quand la DLQ dépassé 100 Mo. Ca veut dire que plus de ~100 000 événements ont ete rejetes. A chaque fois, la cause etait un changement de format dans les logs d'une application sans mise à jour du pipeline.
Résumé
- La DLQ sauvegarde les événements rejetes par Elasticsearch sur disque
- Activee avec
dead_letter_queue.enable: truedanslogstash.yml - Un pipeline dédié lit la DLQ, corrige les événements et les re-indexé
- Les causes les plus courantes : mapping conflicts, types incorrects, valeurs invalides
- Les erreurs 429/503 ne vont pas en DLQ (Logstash les retente automatiquement)
- Surveille la taille de la DLQ et corrige la cause racine
Precedent : 22 - Monitoring | Suivant : 24 - Sécurité