21 - Performance et tuning Logstash
Ce que tu vas apprendre
- Les trois leviers de performance : workers, batch size, JVM heap
- Identifier le bottleneck (input-bound, filter-bound, output-bound)
- Configurer la persistent queue pour la durabilité
- Les paramètres JVM et le garbage collector
- Mesurer le debit et les latences
Prerequisites
- Avoir un pipeline en production ou pre-production
- Connaitre
pipelines.yml(voir article 20)
Le pipeline est une chaîne
La performance de Logstash est celle de son maillon le plus faible. Le pipeline est une chaîne : input -> queue -> filter -> output. Si l'output met 100 ms a envoyer un batch dans Elasticsearch, peu importe que tes filtres prennent 1 ms.
La première étape, c'est de trouver ou ca bloque.
Identifier le bottleneck
L'API de monitoring donne les metriques par phase :
bashcurl -s http://localhost:9600/_node/stats/pipelines | python3 -m json.tool
Cherche ces metriques dans la réponse :
json{
"pipelines": {
"main": {
"events": {
"in": 150000,
"filtered": 150000,
"out": 150000,
"duration_in_millis": 45000,
"queue_push_duration_in_millis": 200
},
"plugins": {
"filters": [
{ "id": "grok_1", "events": { "duration_in_millis": 25000, "in": 150000 } },
{ "id": "mutate_1", "events": { "duration_in_millis": 1000, "in": 150000 } }
],
"outputs": [
{ "id": "elasticsearch_1", "events": { "duration_in_millis": 18000, "in": 150000 } }
]
}
}
}
}
Interprétation :
- Grok : 25 000 ms pour 150 000 events = ~0.17 ms/event. C'est le plus lent.
- Mutate : 1 000 ms = negligeable.
- Elasticsearch output : 18 000 ms = ~0.12 ms/event. Correct.
- Queue push : 200 ms = la queue n'est pas un bottleneck.
Ici, c'est Grok le bottleneck. Deux solutions : optimiser le pattern Grok, ou remplacer par Dissect.
Types de bottleneck
| Bottleneck | Symptome | Solution |
|---|---|---|
| Input-bound | events.in stagne malgre les donnees en attente |
Plus de connexions, Filebeat plus rapide |
| Filter-bound | plugins.filters.duration eleve |
Optimiser Grok, passer a Dissect, plus de workers |
| Output-bound | plugins.outputs.duration eleve |
Bulk size plus grand, Elasticsearch plus rapide |
| Queue-bound | queue_push_duration eleve |
Queue plus grande, workers plus rapides |
Les trois leviers
1. pipeline.workers
Le nombre de threads qui executent les filtres et outputs en parallèle.
yaml# pipelines.yml
- pipeline.id: main
pipeline.workers: 4
Valeur par défaut : nombre de CPUs. Sur une machine 4 cores, tu as 4 workers.
Augmenter les workers aide quand le bottleneck est le filtre ou l'output. Chaque worker traite un batch d'événements indépendamment.
Regles :
- Commence par le nombre de CPUs
- Si le CPU n'est pas a 100% et que le pipeline prend du retard, augmente
- Au-dela de 2x le nombre de CPUs, tu n'as plus de gain (context switching)
- Si tu utilises le filtre aggregate, force
pipeline.workers: 1
2. pipeline.batch.size
Le nombre d'événements traites en un seul batch par worker.
yaml- pipeline.id: main
pipeline.batch.size: 250
Valeur par défaut : 125.
Un batch plus grand réduit l'overhead par événement (moins d'appels Bulk API a Elasticsearch). Mais il augmente la latence : un événement attend que le batch soit plein avant d'etre traite.
Regles :
- 125 est bon pour la plupart des cas
- Si le bottleneck est l'output Elasticsearch, monte a 250 ou 500
- Au-dela de 1000, les gains sont marginaux et la mémoire augmente
pipeline.batch.delay(défaut 50 ms) contrôle le temps d'attente max si le batch n'est pas plein
3. JVM heap
Logstash tourne sur la JVM. La heap est la mémoire allouee a la JVM.
yaml# compose.yaml
environment:
- "LS_JAVA_OPTS=-Xms1g -Xmx1g"
Ou dans le fichier jvm.options :
-Xms1g
-Xmx1g
-Xms et -Xmx doivent etre identiques. Ca évité que la JVM redimensionne la heap en permanence.
Regles :
- Minimum : 256 Mo (dev local uniquement)
- Recommande : 1 Go pour un pipeline standard
- Maximum : pas plus de la moitie de la RAM disponible
- Si tu utilises la persistent queue ou le filtre aggregate, augmente a 2-4 Go
- Au-dela de 8 Go, le garbage collector devient un problème (pauses longues)
Tableau recapitulatif
| Paramètre | Défaut | Dev | Prod legere | Prod lourde |
|---|---|---|---|---|
pipeline.workers |
nb CPUs | 2 | 4 | 8-16 |
pipeline.batch.size |
125 | 125 | 250 | 500 |
pipeline.batch.delay |
50 ms | 50 | 50 | 10 |
Heap (-Xms/-Xmx) |
1 Go | 256m | 1g | 4g |
La persistent queue
Par défaut, la queue est en mémoire. Si Logstash crash, les événements dans la queue sont perdus. La persistent queue écrit les événements sur disque.
yaml# pipelines.yml
- pipeline.id: main
path.config: "/usr/share/logstash/pipeline/main.conf"
queue.type: persisted
queue.max_bytes: 4gb
queue.page_capacity: 64mb
queue.drain: true
┌─────────┐ ┌────────────────────┐ ┌────────────────┐
│ INPUT │───>│ PERSISTENT QUEUE │───>│ FILTER + OUTPUT│
│ │ │ │ │ │
│ │ │ /usr/share/ │ │ │
│ │ │ logstash/data/ │ │ │
│ │ │ queue/main/ │ │ │
└─────────┘ └────────────────────┘ └────────────────┘
│
fichiers .page
sur disque
| Paramètre | Description |
|---|---|
queue.type: persisted |
Active la queue persistante |
queue.max_bytes |
Taille max sur disque (4 Go = ~15 millions d'events standard) |
queue.page_capacity |
Taille d'une page (fichier individuel) |
queue.drain: true |
Traiter tous les events avant de s'arrêter (graceful shutdown) |
Avantages :
- Survit aux crashes de Logstash
- Absorbe les pics (si l'output est temporairement lent)
queue.drain: truegarantit qu'un arrêt propre n'abandonne pas d'events
Inconvenients :
- Plus lent que la queue mémoire (~10% d'overhead)
- Necessite du disque rapide (SSD recommande)
- Ne protégé pas contre un crash du système entier (disque corrompu)
Monte un volume pour la queue dans Docker :
yamllogstash:
volumes:
- logstash-queue:/usr/share/logstash/data
Mesurer le debit
Avec l'API
bash# Events par seconde (calculer sur un intervalle)
curl -s http://localhost:9600/_node/stats/pipelines | \
python3 -c "
import json, sys
data = json.load(sys.stdin)
for pid, p in data['pipelines'].items():
e = p['events']
print(f'{pid}: in={e[\"in\"]} out={e[\"out\"]} filtered={e[\"filtered\"]}')
"
Avec le codec dots
Temporairement, remplace l'output par stdout { codec => dots }. Chaque point est un événement. Compte les points par seconde.
Avec les metriques Logstash
L'API /stats expose les compteurs depuis le démarrage. Pour le debit instantane, fais deux appels espaces de 10 secondes et calcule la différence.
Checklist de tuning
- Mesure d'abord, optimise ensuite (API
_node/stats) - Identifie le bottleneck (filter, output, queue)
- Si filter-bound : Dissect au lieu de Grok, ancrer les patterns, réduire le nombre de filtres
- Si output-bound : augmenter batch_size, activer
http_compressionsur l'output ES - Si les deux : augmenter workers
- Ajuste la heap JVM (pas plus de 50% de la RAM)
- Active la persistent queue en production
- Monitore en continu (voir article 22)
Sur paltemps.fr, le tuning se fait en trois itérations. D'abord les workers (le plus simple), puis la batch size, et enfin la heap. Rarement besoin de toucher aux paramètres avances.
Résumé
- La performance de Logstash depend de trois leviers : workers, batch size, JVM heap
- Identifie le bottleneck avec l'API
_node/stats/pipelinesavant d'optimiser - Workers = nombre de CPUs par défaut, augmente si CPU < 100% et pipeline en retard
- Batch size = 125 par défaut, augmente a 250-500 si l'output est le bottleneck
- Heap = 1 Go recommande, jamais plus de 50% de la RAM
- La persistent queue protégé contre les pertes en cas de crash (10% d'overhead)
Precedent : 20 - Pipelines multiples | Suivant : 22 - Monitoring