ELK Stack — FAQ
Frequently Asked Questions
Common questions and answers about the ELK Stack, Elasticsearch, and the broader Elastic ecosystem.
General Questions
What is the difference between ELK Stack and Elastic Stack?
ELK Stack originally referred to Elasticsearch + Logstash + Kibana. When Elastic added Beats (lightweight data shippers), they rebranded to Elastic Stack to include all four components. Today, “ELK Stack” and “Elastic Stack” are used interchangeably in the community, though “Elastic Stack” is the official name.
The Elastic Stack also includes:
- Elastic Agent — unified agent replacing individual Beats
- Fleet — centralized agent management
- APM Server — application performance monitoring
- Elastic Security — SIEM and endpoint protection
What is the licensing model for Elasticsearch?
As of Elasticsearch 7.11+, Elastic changed from Apache 2.0 to a dual license:
| License | Features | Cost |
|---|---|---|
| Elastic License 2.0 | Most features including security, alerting, ML | Free |
| SSPL | Server-side public license (source-available) | Free |
| Basic (self-managed) | Core features + security + ILM | Free |
| Platinum | ML, advanced security, cross-cluster replication | Paid subscription |
| Enterprise | Searchable snapshots, all features | Paid subscription |
Key point: Basic security (TLS, RBAC, API keys) is free since version 6.8/7.1.
What is OpenSearch and how does it differ from Elasticsearch?
OpenSearch is an AWS-maintained fork of Elasticsearch 7.10.2 (the last Apache 2.0 version):
| Aspect | Elasticsearch | OpenSearch |
|---|---|---|
| Maintained by | Elastic | AWS (community) |
| License | Elastic License / SSPL | Apache 2.0 |
| Latest version | 8.x+ | 2.x |
| ML features | Built-in (paid) | Community plugins |
| Security | Built-in (free basic) | OpenSearch Security plugin |
| Cloud offering | Elastic Cloud | Amazon OpenSearch Service |
| Compatibility | Original APIs | Fork of ES 7.10 APIs |
Choose OpenSearch if you need a strictly Apache 2.0 license or are heavily invested in AWS. Choose Elasticsearch for the latest features, better performance, and official support.
How does Elasticsearch compare to Apache Solr?
| Feature | Elasticsearch | Apache Solr |
|---|---|---|
| Ease of setup | Simple, runs out of the box | More configuration needed |
| API | REST + JSON natively | REST, XML, JSON |
| Scaling | Auto-shard rebalancing | Manual shard management |
| Analytics | Powerful aggregations | Facets and stats |
| Real-time | Near-real-time by default | Near-real-time with commit |
| Ecosystem | Full stack (Kibana, Beats, Logstash) | Limited (Banana, Solr UI) |
| Use case fit | Log analytics, observability, search | Enterprise search, e-commerce |
| Community | Very large, active | Mature, Apache community |
Elasticsearch dominates for log analytics and observability. Solr remains competitive for enterprise search use cases.
Architecture Questions
What are the minimum hardware requirements?
Development / Testing:
| Component | CPU | RAM | Disk |
|---|---|---|---|
| Elasticsearch | 2 cores | 4 GB | 20 GB SSD |
| Kibana | 1 core | 2 GB | 1 GB |
| Logstash | 2 cores | 4 GB | 5 GB |
| Filebeat | 1 core | 512 MB | 1 GB |
Production (minimum viable):
| Component | CPU | RAM | Disk |
|---|---|---|---|
| ES Master (×3) | 2 cores | 4 GB | 10 GB SSD |
| ES Data (×2) | 8 cores | 32 GB | 500 GB SSD |
| Kibana (×2) | 4 cores | 8 GB | 10 GB |
| Logstash (×2) | 4 cores | 8 GB | 20 GB |
Rule of thumb: Elasticsearch data nodes should have at least 16 GB RAM (8 GB heap).
Should I use cloud-managed or self-managed Elasticsearch?
| Factor | Cloud-Managed | Self-Managed |
|---|---|---|
| Operational overhead | Low (Elastic manages) | High (you manage everything) |
| Cost | Subscription-based, predictable | Infrastructure + engineering time |
| Customisation | Limited to offering | Full control |
| Upgrades | One-click | Manual rolling upgrades |
| Scaling | Auto or one-click | Manual provisioning |
| Data residency | Cloud provider regions | Your data centres |
| Best for | Teams < 5, rapid deployment | Large teams, compliance needs |
Recommendation: Start with Elastic Cloud for speed, migrate to self-managed only if you have specific compliance, cost, or customisation requirements.
How many shards should I have?
Follow these guidelines:
- Shard size: Target 10-50 GB per shard
- Shards per node: Keep below 20 shards per GB of heap
- Total formula:
total_shards = daily_data_size × retention_days / target_shard_size
Example: 50 GB/day, 30-day retention, 25 GB target shard size:
total_shards = 50 × 30 / 25 = 60 shards
With 1 replica: 120 total shards
3 data nodes: 40 shards per node
Common mistake: Over-sharding with too many small shards. A single shard of 30 GB performs better than 30 shards of 1 GB.
Data Processing Questions
When should I use Logstash vs Beats?
| Criteria | Use Beats | Use Logstash |
|---|---|---|
| Parsing needed | No or minimal | Complex (Grok, multi-step) |
| Transformation | Simple processors | Heavy transformation |
| Resource constraints | Limited (edge) | Dedicated processing server |
| Multiple outputs | Single output | Multiple outputs, routing |
| Enrichment | Basic metadata | Lookups, JDBC, GeoIP |
| Buffering | Limited | Persistent queues |
| Scale | One per host | Centralised, scale horizontally |
Common pattern: Use Beats for collection → Logstash for processing → Elasticsearch for storage.
Modern alternative: Use Beats + Elasticsearch Ingest Pipelines (no Logstash needed for many use cases).
How do I handle high-cardinality fields?
High-cardinality fields (e.g., user IDs, IP addresses, session tokens) can cause memory issues:
Problems:
termsaggregations on high-cardinality fields use significant memoryfielddataon text fields can cause circuit breaker exceptions
Solutions:
// 1. Use keyword type, not text, for aggregations
PUT /my-index
{
"mappings": {
"properties": {
"user_id": { "type": "keyword" }
}
}
}
// 2. Use composite aggregation for paginated results
GET /my-index/_search
{
"size": 0,
"aggs": {
"unique_users": {
"composite": {
"size": 1000,
"sources": [
{ "user": { "terms": { "field": "user_id" } } }
]
}
}
}
}
// 3. Use cardinality aggregation for approximate counts
GET /my-index/_search
{
"size": 0,
"aggs": {
"unique_count": {
"cardinality": {
"field": "user_id",
"precision_threshold": 10000
}
}
}
}
How do I reduce storage costs?
- Enable compression:
PUT /my-index/_settings { "index.codec": "best_compression" } -
Use ILM to move data to cheaper storage tiers (hot → warm → cold → frozen)
- Reduce replicas for older indices:
PUT /my-index/_settings { "number_of_replicas": 0 } - Force merge read-only indices:
curl -X POST "localhost:9200/my-old-index/_forcemerge?max_num_segments=1" -
Use searchable snapshots for cold/frozen tier (store in S3/GCS at ~80% cost reduction)
-
Disable
_sourceif you don’t need the original document (caution: you lose reindex ability) - Optimise mappings — disable indexing for fields you don’t search, use appropriate types
Troubleshooting Questions
My cluster status is yellow — what should I do?
Yellow means all primary shards are allocated, but some replicas are not.
Common causes:
- Single-node cluster — replicas can’t be allocated on the same node:
PUT /my-index/_settings { "number_of_replicas": 0 } -
Insufficient nodes — add more data nodes or reduce replicas
- Disk watermark — check disk usage:
curl -s "localhost:9200/_cat/allocation?v" - Shard allocation filtering — check if allocation rules prevent placement:
curl -s "localhost:9200/_cluster/allocation/explain?pretty"
My cluster status is red — what should I do?
Red means one or more primary shards are unassigned. This is serious.
Immediate steps:
# 1. Check which indices are red
curl -s "localhost:9200/_cat/indices?health=red&v"
# 2. Find unassigned shards
curl -s "localhost:9200/_cat/shards?h=index,shard,prirep,state,unassigned.reason" | grep UNASSIGNED
# 3. Get allocation explanation
curl -s "localhost:9200/_cluster/allocation/explain?pretty"
# 4. Check node status
curl -s "localhost:9200/_cat/nodes?v&h=name,heap.percent,ram.percent,disk.used_percent,node.role"
Common fixes:
- Restart failed nodes
- Reroute stuck shards:
POST /_cluster/reroute?retry_failed=true - Allocate empty primary (DATA LOSS): only as last resort
Elasticsearch is using too much heap memory — how do I fix it?
Diagnosis:
# Check heap usage
curl -s "localhost:9200/_nodes/stats/jvm?pretty" | grep -A 5 "heap"
# Check circuit breakers
curl -s "localhost:9200/_nodes/stats/breaker?pretty"
Solutions:
- Increase heap (up to 50% of RAM, max ~31 GB):
# jvm.options -Xms16g -Xmx16g -
Reduce fielddata — avoid text field aggregations, use keyword type
-
Optimise queries — use filter context for caching, avoid deep pagination
-
Reduce shard count — fewer shards means less overhead
- Use
doc_values(default) instead of fielddata for sorting/aggregations
Search queries are slow — how do I diagnose?
Step 1: Enable slow log:
# elasticsearch.yml (or via API)
index.search.slowlog.threshold.query.warn: 10s
index.search.slowlog.threshold.query.info: 5s
index.search.slowlog.threshold.query.debug: 2s
index.search.slowlog.threshold.fetch.warn: 1s
Step 2: Use the Profile API:
GET /my-index/_search
{
"profile": true,
"query": {
"match": { "message": "error" }
}
}
Step 3: Common optimisations:
- Use
filtercontext instead ofqueryfor exact matches - Add
routingto target specific shards - Use
_sourcefiltering to return only needed fields - Avoid
wildcardqueries with leading wildcards - Pre-sort indices for common sort patterns
- Consider
terminate_afterfor exploratory queries
How do I migrate from ELK to Elastic Cloud?
- Create Elastic Cloud deployment matching your current version
- Set up snapshot repository accessible by both clusters (S3/GCS)
- Snapshot your data:
curl -X PUT "localhost:9200/_snapshot/migration/snapshot_1?wait_for_completion=true" - Register the same repository on Elastic Cloud
- Restore the snapshot on Elastic Cloud
- Update Beats/Logstash to point to the new Cloud cluster
- Verify data and switch DNS/load balancer
- Decommission the old cluster
How do I handle timezone issues in logs?
Problem: Logs arrive with different timezones, causing confusion in Kibana.
Solutions:
-
Standardise on UTC at the source when possible
- Parse and convert in Logstash:
filter { date { match => ["timestamp", "yyyy-MM-dd HH:mm:ss"] timezone => "America/New_York" target => "@timestamp" } } -
Use Kibana timezone setting: Management → Advanced Settings →
dateFormat:tz - Store original timezone in a separate field for reference
Operational Questions
How often should I upgrade Elasticsearch?
- Minor releases (8.12 → 8.13): Every 1-3 months, mainly for bug fixes and features
- Major releases (7.x → 8.x): Plan carefully, test in staging first
- Security patches: Apply immediately
- Always read release notes and run the Upgrade Assistant in Kibana before upgrading
Can I run Elasticsearch on Docker in production?
Yes, with caveats:
- Set
vm.max_map_count=262144on the Docker host - Use volume mounts for data (not Docker volumes for performance)
- Set
ES_JAVA_OPTSexplicitly - Use ECK (Elastic Cloud on Kubernetes) for container orchestration
- Ensure proper resource limits (memory, CPU)
- Pin specific Elasticsearch image versions (don’t use
latest)
How do I handle index rollover for time-series data?
Use Data Streams (recommended in 8.x):
PUT _index_template/logs-template
{
"index_patterns": ["logs-*"],
"data_stream": {},
"template": {
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
}
}
}
PUT _ilm/policy/logs-policy
{
"policy": {
"phases": {
"hot": {
"actions": {
"rollover": {
"max_primary_shard_size": "50gb",
"max_age": "1d"
}
}
},
"delete": {
"min_age": "30d",
"actions": { "delete": {} }
}
}
}
}
Data streams automatically handle rollover, backing indices, and the write index.
Have a question not covered here? Check the Community Resources page for forums and support channels.