1. Dimensionner les index et les shards #
Le réglage le plus impactant.
Règles de dimensionnement #
- Visez 10 à 50 Go par shard. L'ancienne règle « moins de 20 shards par Go de heap » a été retirée par Elastic depuis la 8.3 : surveillez plutôt la limite
cluster.max_shards_per_nodeet la mémoire réellement utilisée par les mappings et les champs. - Un seul shard primaire suffit pour les petits index ; évitez le sur-sharding.
- Utilisez des data streams avec rollover plutôt qu'un index unique géant.
# Toutes les commandes utilisent HTTPS et l'authentification (ca.crt : certificat de l'autorité du cluster)
export ES_PASSWORD='...'
curl --cacert ca.crt -u "elastic:$ES_PASSWORD" -s https://localhost:9200/_cluster/health?pretty
curl --cacert ca.crt -u "elastic:$ES_PASSWORD" -s 'https://localhost:9200/_cat/indices?v&s=store.size:desc&h=index,pri,rep,docs.count,store.size' | head
curl --cacert ca.crt -u "elastic:$ES_PASSWORD" -s 'https://localhost:9200/_cat/shards?v&s=store:desc' | head
curl --cacert ca.crt -u "elastic:$ES_PASSWORD" -s 'https://localhost:9200/_cat/allocation?v'
curl --cacert ca.crt -u "elastic:$ES_PASSWORD" -s 'https://localhost:9200/_cluster/allocation/explain?pretty' # pourquoi un shard n'est pas alloué2. Mappings, templates et ILM #
Maîtriser le schéma et le cycle de vie.
Template et mapping explicite #
curl --cacert ca.crt -u "elastic:$ES_PASSWORD" -X PUT https://localhost:9200/_index_template/logs-app -H 'Content-Type: application/json' -d '{
"index_patterns": ["logs-app-*"],
"data_stream": {},
"priority": 200,
"template": {
"settings": { "number_of_shards": 1, "number_of_replicas": 1, "index.lifecycle.name": "logs-30j", "index.codec": "best_compression" },
"mappings": {
"dynamic": "strict",
"properties": {
"@timestamp": { "type": "date" }, "level": { "type": "keyword" }, "message": { "type": "text" },
"user_id": { "type": "keyword" }, "duration_ms": { "type": "long" }
}
}
}
}'Erreur Courante : Un mapping dynamique laissé libre crée des milliers de champs (explosion de mapping). Utilisezdynamic: strictet des types adaptés (keywordpour les filtres,textpour le plein texte).
À savoir : Le template porte une priorité de 200 : sans elle, il chevauche le template intégrélogs-*-*(priorité 100) et le data stream peut recevoir le mapping intégré au lieu du vôtre. Vérifiez le template appliqué avecPOST _index_template/_simulate_index/logs-app-default.
Cycle de vie (ILM) #
curl --cacert ca.crt -u "elastic:$ES_PASSWORD" -X PUT https://localhost:9200/_ilm/policy/logs-30j -H 'Content-Type: application/json' -d '{
"policy": { "phases": {
"hot": { "actions": { "rollover": { "max_primary_shard_size": "50gb", "max_age": "1d" } } },
"warm": { "min_age": "7d", "actions": { "forcemerge": { "max_num_segments": 1 } } },
"delete": { "min_age": "30d", "actions": { "delete": {} } }
} }
}'
curl --cacert ca.crt -u "elastic:$ES_PASSWORD" -s https://localhost:9200/_ilm/status
curl --cacert ca.crt -u "elastic:$ES_PASSWORD" -s 'https://localhost:9200/logs-app-*/_ilm/explain?pretty' | head -303. Mémoire, sécurité et sauvegardes #
Stabilité de production.
JVM et système #
# jvm.options.d/heap.options : 50 % de la RAM maximum, jamais plus de ~30 Go
-Xms16g
-Xmx16g
sudo sysctl -w vm.max_map_count=262144
sudo swapoff -a # ou bootstrap.memory_lock: true
curl --cacert ca.crt -u "elastic:$ES_PASSWORD" -s 'https://localhost:9200/_nodes/stats/jvm?filter_path=**.heap_used_percent&pretty'Sécurité #
- Activez TLS (transport et HTTP) et l'authentification ; utilisez des clés d'API à portée limitée.
- N'exposez jamais le port 9200 sur Internet ; passez par un reverse proxy.
- Un rôle d'écriture par pipeline d'ingestion, un rôle de lecture par équipe.
curl --cacert ca.crt -u "elastic:$ES_PASSWORD" -X POST https://localhost:9200/_security/api_key -H 'Content-Type: application/json' -d '{
"name": "ingestion-app",
"role_descriptors": { "writer": { "indices": [{ "names": ["logs-app-*"], "privileges": ["create_doc", "auto_configure"] }] } },
"expiration": "90d"
}'Sauvegardes (snapshots) #
curl --cacert ca.crt -u "elastic:$ES_PASSWORD" -X PUT https://localhost:9200/_snapshot/depot -H 'Content-Type: application/json' -d '{ "type": "s3", "settings": { "bucket": "es-snapshots" } }'
curl --cacert ca.crt -u "elastic:$ES_PASSWORD" -X PUT https://localhost:9200/_slm/policy/quotidien -H 'Content-Type: application/json' -d '{
"schedule": "0 30 1 * * ?", "name": "<snap-{now/d}>", "repository": "depot",
"config": { "indices": ["logs-*"] }, "retention": { "expire_after": "30d", "min_count": 5 } }'
curl --cacert ca.crt -u "elastic:$ES_PASSWORD" -s https://localhost:9200/_snapshot/depot/_all?pretty | head -20Bonne Pratique : Testez régulièrement la restauration : une sauvegarde jamais restaurée n'est pas une sauvegarde.
4. Requêtes et ingestion performantes #
Bulk, filtres et pagination.
Bonnes habitudes #
# Ingestion : _bulk par lots de 5 à 15 Mo
curl --cacert ca.crt -u "elastic:$ES_PASSWORD" -s -H 'Content-Type: application/x-ndjson' -XPOST https://localhost:9200/_bulk --data-binary @lot.ndjson | jq '.errors'
# Filtres (cachés, sans score) plutôt que must pour les conditions exactes
curl --cacert ca.crt -u "elastic:$ES_PASSWORD" -s https://localhost:9200/logs-app-*/_search -H 'Content-Type: application/json' -d '{
"size": 20, "_source": ["@timestamp","level","message"],
"query": { "bool": { "filter": [ { "term": { "level": "error" } }, { "range": { "@timestamp": { "gte": "now-15m" } } } ] } },
"sort": [{ "@timestamp": "desc" }]
}'
# Pagination profonde : search_after + PIT
curl --cacert ca.crt -u "elastic:$ES_PASSWORD" -s -XPOST 'https://localhost:9200/logs-app-*/_pit?keep_alive=1m'| À éviter | Préférer |
|---|---|
from: 100000 | search_after avec PIT |
wildcard en préfixe *texte | Analyseur adapté (n-gram) ou champ dédié |
| Mettre à jour un document en boucle | Réindexer en bulk, modèle append-only |
| Un index par jour sans rollover | Data streams et ILM |
Schéma de référence et vérification rapide #
Visualiser le principe et le contrôler en ligne de commande.
Schéma de référence #
curl --cacert ca.crt -u "elastic:$ES_PASSWORD" -s 'https://localhost:9200/_cat/indices/logs-*?v&h=index,health,pri,store.size&s=index'