π§ Druid Fundamentals
π― What is Apache Druid?
Apache Druid is a distributed, real-time analytics database built for speed and scale. It combines ideas from data warehouses, time-series databases, and search systems to deliver sub-second queries on streaming and batch data at high concurrency[citation:6][citation:18]. It powers user-facing analytics applications at companies like Airbnb, Cisco, and Salesforce[citation:9].
Why Druid Matters
Real-time: Sub-second queries on streaming data. Scale: Billions of rows, petabytes. Concurrency: Thousands of concurrent users. Ingestion: Kafka, Kinesis, batch. Rollup: Pre-aggregation for storage savings. Architecture: Microservices, independently scalable.
# Apache Druid β the big picture
# Real-time analytics database for speed and scale.
# CONCEPTUAL OVERVIEW
print("""
=== Apache Druid ===
What it is:
- Real-time analytics database
- Distributed, columnar
- Sub-second queries
- Streaming + batch ingestion
- Rollup (pre-aggregation)
- High concurrency
Created by:
- Metamarkets (2011)
- Apache (2018)
Key features:
- Kafka/Kinesis ingestion
- SQL + JSON querying
- Time-based partitioning
- Inverted indexes
- Deep storage (S3, HDFS)
- Microservices architecture
What it's NOT:
- Not a data warehouse (no complex joins)
- Not for OLTP
- Not for full-text search
- Not for updates/deletes (append-only)
What it IS:
- Real-time analytics
- User-facing dashboards
- Time-series analysis
- Clickstream, IoT, APM
""")
# WHY IT MATTERS
print("=== Why Druid Matters ===")
print("""
Challenges:
- Real-time data
- High concurrency
- Sub-second latency
- Billions of rows
- Streaming + batch
Druid solves:
- Sub-second queries
- High concurrency
- Real-time ingestion
- Scale
- Storage efficiency (rollup)
""")
# REAL-WORLD
print("=== Real-World Scale ===")
print("""
Companies using Druid:
- Airbnb
- Alibaba
- Cisco
- Netflix
- Salesforce
- Shopify
- Verizon
- Nielsen
Scale examples:
- The R&A: 25B+ rows, sub-second queries [citation:2]
- 250M new rows every 15 minutes [citation:2]
- 100% uptime during global broadcast [citation:2]
""")ποΈ Architecture
π― Microservices Architecture
Druid's architecture is a disassembled database: each core service (ingestion, querying, coordination) can be independently deployed and scaled. Services can fail without impacting others[citation:7][citation:18].
Architecture
Master: Coordinator + Overlord. Query: Broker + Router. Data: Historical + MiddleManager + Peon. Deep Storage: S3, HDFS. Metadata: PostgreSQL, MySQL. Coordination: ZooKeeper.
# Druid Architecture
print("=== Architecture Diagram ===")
print("""
βββββββββββββββββββββββββββββββββββββββββββ
β Clients β
β (BI, Apps, SQL) β
βββββββββββββββββββ¬ββββββββββββββββββββββββ
β
βββββββββββββΌββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββ βββββββββββ βββββββββββ
β Broker β β Router β β Web UI β
β (Query) β β (Proxy) β β β
ββββββ¬βββββ ββββββ¬βββββ βββββββββββ
β β
βββββββββββββΌββββββββββββ
β β
βΌ βΌ
βββββββββββββββββββββββββββββββββββββββββββ
β Coordinator / Overlord β
β (Master Services) β
β β
β - Segment management β
β - Task assignment β
β - Ingestion control β
βββββββββββββββββββ¬ββββββββββββββββββββββββ
β
βββββββββββββΌββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββ βββββββββββ βββββββββββ
βHistoricalβ βMiddleMgrβ βIndexer β
β(Data) β β(Ingest) β β(Ingest) β
ββββββ¬βββββ ββββββ¬βββββ ββββββ¬βββββ
β β β
βββββββββββββΌββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββ
β Deep Storage β
β (S3, HDFS, GCS) β
βββββββββββββββββββββββββββββββββββββββββββ
""")
print("\n=== Services ===")
print("""
MASTER SERVICES:
Coordinator:
- Manages data availability
- Assigns segments to Historicals
- Balances segments
Overlord:
- Controls ingestion workloads
- Assigns tasks to MiddleManagers
- Coordinates segment publishing
QUERY SERVICES:
Broker:
- Receives queries from clients
- Routes to Data servers
- Merges results
Router:
- API gateway
- Routes to Brokers, Coordinators, Overlords
- Runs web console
DATA SERVICES:
Historical:
- Stores queryable data
- Downloads segments from deep storage
- Responds to queries
- No writes
MiddleManager:
- Handles ingestion
- Spawns Peons
- Reads from sources
Peon:
- Task execution engine
- Single task per Peon
- Runs on same host as MiddleManager
Indexer (optional):
- Alternative to MiddleManager + Peon
- Tasks as threads in single JVM
- Easier to configure
""")
print("\n=== Server Types ===")
print(f"{'Server':<20} {'Services':<40}")
print("-" * 60)
print(f"{'Master':<20} {'Coordinator + Overlord':<40}")
print(f"{'Query':<20} {'Broker + Router':<40}")
print(f"{'Data':<20} {'Historical + MiddleManager':<40}")
print("\n=== Deep Storage ===")
print("""
Deep Storage:
- S3
- HDFS
- Google Cloud Storage
- Azure Blob
Purpose:
- Durable data storage
- Backup
- Segment handoff
- Recovery
Metadata Store:
- PostgreSQL
- MySQL
- Derby (dev only)
Coordination:
- ZooKeeper
- Consul (newer)
""")π₯ Ingestion
π― Getting Data In
Druid supports both streaming (Kafka, Kinesis) and batch (S3, HDFS, local) ingestion. Data is indexed, partitioned, and optionally pre-aggregated as it's ingested[citation:6][citation:17].
Ingestion
Streaming: Kafka, Kinesis. Batch: S3, HDFS, files. Exactly-once: Streaming. Formats: JSON, CSV, Parquet, ORC. Rollup: Pre-aggregation. SQL: INSERT, REPLACE.
# Ingestion
print("=== Streaming Ingestion ===")
print("""
Kafka:
- Native pull-based
- Exactly-once
- Zero RPO
- Auto-scaling
Kinesis:
- Native support
- Exactly-once
- AWS
Supervisor:
- Manages tasks
- Autoscaling
- Handles failures
Example (Kafka):
{
"type": "kafka",
"dataSchema": {
"dataSource": "events",
"timestampSpec": {"column": "timestamp", "format": "iso"},
"dimensionsSpec": {
"dimensions": ["user_id", "event_type"]
},
"metricsSpec": [
{"name": "count", "type": "count"},
{"name": "sum_amount", "type": "doubleSum", "fieldName": "amount"}
],
"granularitySpec": {
"type": "uniform",
"segmentGranularity": "HOUR",
"queryGranularity": "MINUTE",
"rollup": true
}
},
"ioConfig": {
"topic": "events",
"consumerProperties": {"bootstrap.servers": "localhost:9092"}
}
}
""")
print("\n=== Batch Ingestion ===")
print("""
Native Batch:
- index_parallel task
- S3, HDFS, local
- JSON, CSV, Parquet, ORC
- Parallelism via subtasks
SQL:
- INSERT INTO ... SELECT
- REPLACE
- MSQ task engine
Hadoop:
- index_hadoop
- YARN
- MapReduce
Example (SQL):
INSERT INTO events
SELECT * FROM TABLE(
EXTERN(
'{"type":"s3","uris":["s3://bucket/events/*.json"]}',
'{"type":"json"}',
'[{"name":"timestamp","type":"string"},{"name":"user_id","type":"long"}]'
)
)
""")
print("\n=== Ingestion Methods ===")
print(f"{'Method':<20} {'Source':<25} {'Format':<20}")
print("-" * 65)
print(f"{'Kafka':<20} {'Kafka':<25} {'JSON, Avro':<20}")
print(f"{'Kinesis':<20} {'Kinesis':<25} {'JSON':<20}")
print(f"{'Native Batch':<20} {'S3, HDFS, local':<25} {'JSON, CSV, Parquet':<20}")
print(f"{'SQL':<20} {'S3, HDFS, Druid':<25} {'Any':<20}")
print(f"{'Hadoop':<20} {'HDFS':<25} {'Any':<20}")
print("\n=== Rollup ===")
print("""
Rollup:
- Pre-aggregation
- Rows with same dimensions + timestamp collapsed
- Metrics aggregated
- Storage savings
- Default: enabled
Example:
Before:
(12:00, user1, click, 1)
(12:00, user1, click, 1)
(12:00, user1, view, 1)
After (rollup):
(12:00, user1, click, 2)
(12:00, user1, view, 1)
Savings:
- Orders of magnitude
- Depends on cardinality
- Trade-off: no individual events
""")
print("\n=== Exactly-Once ===")
print("""
Streaming:
- Exactly-once
- Kafka offsets tracked
- Continuous backup to deep storage
- Zero RPO
Batch:
- At-least-once
- Idempotent writes
- Versioned segments
Guarantees:
- No data loss
- No duplicates
- Durable
""")π¦ Segments & Storage
π― How Data is Stored
Druid stores data in segments β column-oriented files containing up to a few million rows each. Segments are partitioned by time and optionally by other dimensions, compressed, and indexed for fast queries[citation:1][citation:6].
Segments
Columnar: Column-oriented. Compressed: Dictionary, bitmap. Partitioned: By time. Immutable: Append-only. Versioned: MVCC. Deep Storage: Backed up.
# Segments & Storage
print("=== What is a Segment? ===")
print("""
Segment:
- Single file
- Few million rows
- Column-oriented
- Compressed
- Indexed
- Immutable
Identifier:
datasource_interval_version_partition
Example:
clarity-cloud0_2018-05-21T16:00:00.000Z_2018-05-21T17:00:00.000Z_2018-05-21T15:56:09.909Z_1
""")
print("\n=== Segment Lifecycle ===")
print("""
1. CREATE
- Task creates segment
- Data stored in columnar format
2. DEEP STORAGE
- Segment pushed to S3/HDFS
- Durable backup
3. PUBLISH
- Metadata stored in metadata store
- Flag: used = true
4. AVAILABLE
- Loaded by Historical
- Queryable
5. VERSION
- New version overwrites
- Old version dropped
6. DELETE
- Retention rules
- Removed from cluster
""")
print("\n=== Storage Format ===")
print("""
Column-oriented:
- Each column stored separately
- Only needed columns read
- Better compression
Encoding:
- Dictionary (strings)
- Raw (numbers)
- Compressed
Indexes:
- Inverted index (strings)
- Bitmap index
- Time index
Partitioning:
- Time-based (primary)
- Secondary (hash, range)
- Dynamic
""")
print("\n=== Segment States ===")
print("""
sys.segments table:
- is_published: metadata published
- is_available: loaded for querying
- is_realtime: only on realtime tasks
- is_overshadowed: replaced by newer version
Query:
SELECT * FROM sys.segments
WHERE datasource = 'events';
""")
print("\n=== Deep Storage ===")
print("""
Purpose:
- Durable storage
- Backup
- Segment handoff
- Recovery
Options:
- S3
- HDFS
- GCS
- Azure Blob
- Local (dev)
Config:
druid.storage.type=s3
druid.storage.bucket=my-bucket
druid.storage.baseKey=druid/segments
""")
print("\n=== Retention ===")
print("""
Rules:
- Time-based
- Period: P30D (30 days)
- Tier: hot, cold
- Delete: auto
Example:
{
"type": "load",
"tieredReplicants": {"hot": 2, "cold": 1},
"period": "P30D"
}
{
"type": "drop",
"period": "P90D"
}
""")π Rollup & Pre-Aggregation
π― Storage Savings
Rollup is Druid's pre-aggregation feature. Rows with identical dimensions and timestamps are collapsed into a single row with aggregated metrics. This can reduce storage by orders of magnitude[citation:12].
Rollup
Pre-aggregate: At ingestion. Collapse: Same dims + time. Metrics: Sum, min, max, count. Savings: Orders of magnitude. Trade-off: No individual events. Default: Enabled.
# Rollup
print("=== What is Rollup? ===")
print("""
Rollup:
- Pre-aggregation
- At ingestion time
- Rows with same dimensions + timestamp collapsed
- Metrics aggregated
Example:
Input:
(12:00, user1, click, 1)
(12:00, user1, click, 1)
(12:00, user1, view, 1)
(12:00, user2, click, 1)
Rolled up:
(12:00, user1, click, 2)
(12:00, user1, view, 1)
(12:00, user2, click, 1)
Savings: 4 β 3 rows (25%)
With more data: orders of magnitude
""")
print("\n=== Enable/Disable ===")
print("""
granularitySpec:
rollup: true # Default
To disable:
rollup: false
Trade-off:
Enabled: Less storage, faster queries
Disabled: Full event detail
""")
print("\n=== Maximizing Rollup ===")
print("""
Tips:
1. Fewer dimensions
- Only what's needed
2. Lower cardinality
- Fewer unique values
- Better rollup
3. Sketches
- Avoid high cardinality
- Use theta sketches
4. Right granularity
- queryGranularity
- Balance
Example:
SELECT SUM("cnt") / COUNT(*) * 1.0
FROM datasource;
Higher ratio = better rollup
""")
print("\n=== Metrics ===")
print("""
Aggregators:
- count
- longSum
- doubleSum
- longMin
- doubleMax
- thetaSketch
- HLLSketch
Example:
metricsSpec:
- name: count
type: count
- name: sum_amount
type: doubleSum
fieldName: amount
- name: unique_users
type: thetaSketch
fieldName: user_id
""")
print("\n=== Benefits ===")
print("""
1. STORAGE
- Less data
- Cheaper
2. QUERIES
- Faster
- Less data to scan
3. MEMORY
- Less RAM
- More in cache
4. COST
- Less storage
- Less compute
""")π Querying
π― Fast Queries
Druid supports SQL and JSON-over-HTTP querying. Its scatter/gather architecture enables sub-second performance on billions of rows[citation:6][citation:18].
Querying
SQL: Standard SQL. JSON: Native. Scatter: Parallel. Gather: Merge. Pruning: Segment. Sub-second: Fast.
# Querying
print("=== SQL Querying ===")
print("""
Basic:
SELECT * FROM events LIMIT 10;
Aggregation:
SELECT
event_type,
COUNT(*) as count,
SUM(amount) as revenue
FROM events
WHERE __time >= CURRENT_TIMESTAMP - INTERVAL '1' HOUR
GROUP BY event_type
ORDER BY count DESC;
Time-series:
SELECT
TIME_FLOOR(__time, 'PT1M') as minute,
COUNT(*) as events
FROM events
GROUP BY 1
ORDER BY 1;
Approximate:
SELECT
APPROX_COUNT_DISTINCT(user_id) as unique_users,
APPROX_QUANTILE(latency, 0.95) as p95
FROM events;
""")
print("\n=== Query Lifecycle ===")
print("""
1. Client β Broker
2. Broker β Segment pruning
- Time intervals
- Filters
- Only relevant segments
3. Broker β Data nodes (scatter)
- Parallel sub-queries
- Historical + Realtime
4. Data nodes β Process
- Columnar scan
- Index lookup
- Aggregation
5. Broker β Results (gather)
- Merge
- Final aggregation
- Return to client
""")
print("\n=== Query Types ===")
print(f"{'Type':<20} {'Use Case':<40}")
print("-" * 65)
print(f"{'Timeseries':<20} {'Time-based aggregations':<40}")
print(f"{'TopN':<20} {'Top N by metric':<40}")
print(f"{'GroupBy':<20} {'Multi-dimensional grouping':<40}")
print(f"{'Scan':<20} {'Raw data retrieval':<40}")
print(f"{'Search':<20} {'Full-text search':<40}")
print("\n=== SQL vs JSON ===")
print("""
SQL:
- Standard
- Familiar
- Tool compatibility
JSON:
- Native
- Full control
- Advanced features
Example JSON:
{
"queryType": "groupBy",
"dataSource": "events",
"granularity": "minute",
"dimensions": ["event_type"],
"aggregations": [
{"type": "count", "name": "count"},
{"type": "doubleSum", "name": "revenue", "fieldName": "amount"}
],
"intervals": ["2024-01-01/2024-01-02"]
}
""")
print("\n=== Caching ===")
print("""
Caching:
- Query cache (Broker)
- Segment cache (Historical)
- Result cache
Benefits:
- Faster repeated queries
- Less compute
- Lower cost
Cache:
- Per segment
- LRU eviction
- Configurable
""")
print("\n=== Best Practices ===")
print("""
1. Use SQL for compatibility
2. Use JSON for advanced
3. Filter by time
4. Use approximate algorithms
5. Limit dimensions
6. Cache results
7. Monitor query performance
""")π’ Indexes
π― Fast Filtering
Druid builds specialized indexes for different column types: inverted indexes for strings, bitmap indexes for fast filtering, and time indexes for efficient time-range queries[citation:6].
Indexes
Inverted: String columns. Bitmap: Fast filtering. Time: Time ranges. Dictionary: Compression. Spatial: Geo. Range: Numeric.
# Indexes
print("=== Index Types ===")
print("""
1. INVERTED INDEX
- String columns
- Term β row IDs
- Fast equality
- Fast search
2. BITMAP INDEX
- Compressed bitmaps
- Fast filtering
- AND/OR operations
- Memory efficient
3. TIME INDEX
- Time-range queries
- Partition pruning
- Fast
4. DICTIONARY ENCODING
- Strings β IDs
- Compression
- Fast equality
5. RANGE INDEX
- Numeric columns
- Min/max
- Range pruning
""")
print("\n=== How Indexes Work ===")
print("""
Column: event_type
Values: [click, view, click, purchase, click]
Dictionary:
click β 0
view β 1
purchase β 2
Encoded: [0, 1, 0, 2, 0]
Inverted Index:
click β [0, 2, 4]
view β [1]
purchase β [3]
Query: WHERE event_type = 'click'
β Bitmap [1, 0, 1, 0, 1]
β Fast!
""")
print("\n=== Bitmap Index ===")
print("""
Bitmap:
- One bit per row
- 1 = matches
- 0 = doesn't
Example:
click β 10101
view β 01000
Query: WHERE type = 'click' AND type = 'view'
β Impossible
β Empty
Query: WHERE type = 'click' OR type = 'view'
β 10101 OR 01000 = 11101
β Fast!
""")
print("\n=== Configuring Indexes ===")
print("""
At ingestion:
dimensionsSpec:
dimensions:
- name: event_type
type: string
createBitmapIndex: true
Note:
- Bitmap index: default for strings
- Disable for high cardinality
- Memory trade-off
""")
print("\n=== Benefits ===")
print("""
1. SPEED
- Fast filtering
- Fast aggregation
- Sub-second
2. COMPRESSION
- Dictionary encoding
- Bitmap compression
- Less storage
3. MEMORY
- Loaded in memory
- Fast access
4. FLEXIBILITY
- Ad-hoc queries
- Multiple dimensions
""")π’ Deployment
π― Running Druid
Druid can be deployed in various configurations: single-server (dev), cluster (production), and Kubernetes[citation:4][citation:11].
Deployment
Quickstart: Single server. Cluster: Multiple servers. Kubernetes: Operator. Cloud: Managed. Docker: Compose. Imply: Managed.
# Deployment
print("=== Quickstart (Single Server) ===")
print("""
Requirements:
- 6 GiB RAM
- Java 17
- Linux/Mac (not Windows)
Install:
tar -xzf apache-druid-37.0.0-bin.tar.gz
cd apache-druid-37.0.0
./bin/start-druid
Access:
http://localhost:8888/
Services started:
- ZooKeeper
- Broker
- Router
- Coordinator/Overlord
- Historical
- MiddleManager
""")
print("\n=== Docker Compose ===")
print("""
Files:
- docker-compose.yml
- environment
Run:
docker-compose up -d
Services:
- ZooKeeper
- PostgreSQL (metadata)
- 6 Druid containers
Memory:
- 6 GiB minimum
- 7 GiB per service
Single-node configs:
- nano-quickstart
- micro-quickstart
- small
- medium
- large
- xlarge
""")
print("\n=== Cluster Deployment ===")
print("""
Servers:
Master:
- Coordinator
- Overlord
Query:
- Broker
- Router
Data:
- Historical
- MiddleManager
Sizing:
- Coordinator: medium
- Overlord: medium
- Broker: large
- Historical: large
- MiddleManager: large
Scaling:
- Add Historicals (query scale)
- Add MiddleManagers (ingest scale)
- Add Brokers (concurrency)
""")
print("\n=== Kubernetes ===")
print("""
Druid Operator:
- Kubernetes controller
- Manages Druid cluster
- CRDs
- Helm chart
Example:
apiVersion: druid.apache.org/v1alpha1
kind: Druid
metadata:
name: druid-cluster
spec:
nodes:
brokers:
replicas: 3
historicals:
replicas: 5
middleManagers:
replicas: 3
""")
print("\n=== Managed Services ===")
print("""
Imply:
- Druid as a service
- Managed
- Free tier
Confluent:
- Not Druid
- Kafka
AWS:
- Self-managed
- EMR
GCP:
- Self-managed
Azure:
- Self-managed
""")
print("\n=== Best Practices ===")
print("""
1. Separate servers
- Master
- Query
- Data
2. Sizing
- RAM for segments
- CPU for queries
- Disk for cache
3. Deep storage
- S3/HDFS
- Durable
4. Metadata store
- PostgreSQL
- HA
5. ZooKeeper
- 3+ nodes
- Separate
6. Monitoring
- Prometheus
- Grafana
7. Backup
- Deep storage
- Metadata
8. Security
- TLS
- Auth
- ACLs
""")π§ Operations
π― Running in Production
Operating Druid requires monitoring, tuning, and maintenance. Key areas: JVM tuning, segment management, and query optimization.
Operations
Monitoring: Metrics, logs. Tuning: JVM, memory. Segments: Compaction. Queries: Optimization. Backup: Deep storage. Upgrade: Rolling.
# Operations
print("=== Monitoring ===")
print("""
Metrics:
- Query latency
- Query throughput
- Ingestion rate
- Segment count
- JVM heap
- GC pauses
- Disk usage
- Cache hit rate
Tools:
- Prometheus
- Grafana
- Datadog
- New Relic
Endpoints:
- /status
- /druid/coordinator/v1/loadstatus
- /druid/broker/v1/loadstatus
""")
print("\n=== JVM Tuning ===")
print("""
Heap:
- 50% of RAM
- Historical: large
- Broker: medium
Direct memory:
- Segment cache
- Query processing
Example:
-Xms8g -Xmx8g
-XX:MaxDirectMemorySize=16g
-XX:+UseG1GC
GC:
- G1GC
- Tune pause
- Monitor
""")
print("\n=== Segment Management ===")
print("""
Compaction:
- Merge small segments
- Reduce overhead
- Improve queries
Auto-compaction:
- Coordinator
- Configurable
Manual:
POST /druid/coordinator/v1/compact
Retention:
- Load rules
- Drop rules
- Tiered storage
""")
print("\n=== Query Optimization ===")
print("""
1. Time filters
- Always filter by time
- Segment pruning
2. Limit dimensions
- Fewer dimensions
- Better performance
3. Approximate algorithms
- Theta sketches
- HLL sketches
- Faster
4. Caching
- Query cache
- Segment cache
- Result cache
5. Query priority
- Druid supports
- Priority levels
""")
print("\n=== Backup ===")
print("""
What to backup:
- Deep storage (segments)
- Metadata store
- ZooKeeper
- Config
Frequency:
- Continuous (deep storage)
- Daily (metadata)
- On change (config)
Restore:
- Restore files
- Restart
- Verify
""")
print("\n=== Upgrade ===")
print("""
Rolling upgrade:
1. Backup
2. Upgrade Coordinator/Overlord
3. Upgrade Brokers
4. Upgrade Historicals
5. Upgrade MiddleManagers
6. Verify
Or:
- Blue/green
- New cluster
- Switch
""")
print("\n=== Best Practices ===")
print("""
1. Monitor everything
2. Alert on issues
3. Tune JVM
4. Compact segments
5. Retention rules
6. Backup
7. Test upgrades
8. Document
9. Capacity planning
10. Security
""")πΌ Use Cases
π― Where Druid Excels
Druid is ideal for real-time analytics applications that require sub-second queries at scale and high concurrency[citation:2][citation:8].
Use Cases
Clickstream: User behavior. IoT: Sensor data. APM: Network monitoring. Dashboards: User-facing. Fraud: Detection. Observability: Real-time.
# Use Cases
print("=== Clickstream Analytics ===")
print("""
Use case:
- User behavior
- Page views
- Conversion
- A/B testing
Data:
- Events from web/mobile
- Kafka streaming
- Billions of events
Queries:
- Real-time dashboards
- Funnel analysis
- User segmentation
Value:
- Sub-second insights
- High concurrency
- User-facing
""")
print("\n=== IoT Monitoring ===")
print("""
Use case:
- Sensor data
- Device metrics
- Anomaly detection
Data:
- MQTT β Kafka
- Millions of devices
- Real-time
Queries:
- Real-time monitoring
- Alerts
- Dashboards
Value:
- Sub-second
- High concurrency
- Scalable
""")
print("\n=== Network Performance ===")
print("""
Use case:
- Network traffic
- Latency
- Errors
- Capacity
Data:
- Flow logs
- SNMP
- Streaming
Queries:
- Real-time monitoring
- Root cause
- Capacity planning
Value:
- Sub-second
- High concurrency
- Time-series
""")
print("\n=== User-Facing Dashboards ===")
print("""
Use case:
- Analytics dashboards
- Customer-facing
- Internal BI
Data:
- Event streams
- Batch imports
Queries:
- Interactive
- Ad-hoc
- Scheduled
Value:
- Sub-second
- Many users
- Fresh data
""")
print("\n=== Real-World Example ===")
print("""
The R&A (The Open Championship):
- 25B+ rows
- 250M rows per 15 minutes
- Sub-second queries
- 100% uptime
- Millions of fans
Use case:
- Real-time scoring
- Leaderboards
- Fan engagement
- Broadcast feeds
Result:
- Flawless coverage
- Instant updates
- Global scale
[citation:2]
""")
print("\n=== When to Use Druid ===")
print("""
USE DRUID:
β Real-time analytics
β Sub-second queries
β High concurrency
β Streaming + batch
β Time-series
β User-facing dashboards
β Clickstream, IoT, APM
AVOID:
β Complex joins
β OLTP
β Full-text search
β Frequent updates/deletes
β Small data
""")βοΈ vs Alternatives
π― Druid vs ClickHouse vs Pinot
Druid competes with ClickHouse and Pinot in the real-time OLAP space. Each has strengths and trade-offs[citation:3][citation:9][citation:15].
Comparison
Druid: Real-time, concurrency. ClickHouse: Batch speed, SQL. Pinot: Indexing, LinkedIn. Druid: Rollup, streaming. ClickHouse: Raw speed. Pinot: User-facing.
| Aspect | Apache Druid | ClickHouse | Apache Pinot |
|---|---|---|---|
| Origin | Metamarkets | Yandex | |
| Primary Use | Real-time analytics | Batch analytics | User-facing analytics |
| Streaming | Kafka, Kinesis (native) | Kafka (table engine) | Kafka (native) |
| Rollup | Built-in (default) | Materialized views | Pre-aggregation |
| Query Latency | Sub-second | Sub-second | Sub-second |
| Concurrency | Very high | High | Very high |
| SQL | Yes (partial) | Full SQL | Partial SQL |
| Joins | Limited | Full | Limited |
| Updates | No (append-only) | Limited (batch) | No (append-only) |
| Upserts | No | Limited | Yes (CDC) |
| Indexes | Inverted, bitmap | Sparse, skip | Inverted, star-tree |
| Storage | Segments, deep storage | MergeTree | Segments, deep storage |
| Architecture | Microservices | Monolithic | Microservices |
| Best For | Real-time, concurrency | Batch speed, SQL | User-facing, indexing |
# When to Use Which
print("=== Use Druid WHEN ===")
print("""
β Real-time analytics
β Streaming ingestion
β High concurrency
β Sub-second queries
β Rollup (pre-aggregation)
β Time-series
β User-facing dashboards
β Clickstream, IoT, APM
Companies:
- Airbnb
- Cisco
- Netflix
- Salesforce
""")
print("\n=== Use ClickHouse WHEN ===")
print("""
β Batch analytics
β Full SQL
β Fast aggregation
β Raw speed
β Data warehousing
β Log analysis
β Large joins
Companies:
- Yandex
- Cloudflare
- Uber
- eBay
""")
print("\n=== Use Pinot WHEN ===")
print("""
β User-facing analytics
β High concurrency
β Single query shape
β LinkedIn scale
β Indexing
β Upserts (CDC)
Companies:
- LinkedIn
- Uber
- Walmart
- Microsoft Teams
""")
print("\n=== Decision Flow ===")
print("""
Start
β
ββ Streaming? ββYesβββ Druid
β β
β No
β β
ββ Full SQL? ββYesβββ ClickHouse
β β
β No
β β
ββ User-facing? ββYesβββ Pinot
β β
β No
β β
ββ Real-time? ββYesβββ Druid
""")
print("\n=== Combined ===")
print("""
Many companies use multiple:
- Druid: Real-time dashboards
- ClickHouse: Batch analytics
- Pinot: User-facing
Example:
- Kafka β Druid (real-time)
- S3 β ClickHouse (batch)
- Both β Dashboards
""")β Best Practices
π― Doing Druid Right
Follow these best practices for effective real-time analytics with Apache Druid.
Best Practices
Rollup: Enable. Dimensions: Minimize. Time: Filter. Metrics: Choose. Segments: Compact. Monitor.
# Best Practices
print("=== Schema Design ===")
print("""
1. ENABLE ROLLUP
- Default: true
- Storage savings
- Query speed
2. MINIMIZE DIMENSIONS
- Only what's needed
- Lower cardinality
- Better rollup
3. CHOOSE METRICS
- Count
- Sum
- Min/max
- Sketches (approximate)
4. TIMESTAMP
- Primary timestamp
- __time column
- Granularity
5. GRANULARITY
- segmentGranularity
- queryGranularity
- Balance
""")
print("\n=== Ingestion ===")
print("""
1. STREAMING
- Kafka/Kinesis
- Exactly-once
- Auto-scaling
- Handoff
2. BATCH
- S3/HDFS
- Parallel
- SQL or native
- Idempotent
3. FORMATS
- JSON
- CSV
- Parquet
- ORC
4. VALIDATION
- Schema
- Types
- Timestamps
""")
print("\n=== Querying ===")
print("""
1. FILTER BY TIME
- Always
- Segment pruning
2. LIMIT DIMENSIONS
- Fewer = faster
3. APPROXIMATE
- Theta sketches
- HLL
- Faster
4. CACHE
- Query cache
- Segment cache
- Result cache
5. PRIORITIZE
- Query priority
- Important first
""")
print("\n=== Operations ===")
print("""
1. MONITOR
- Metrics
- Logs
- Alerts
2. COMPACT
- Merge small segments
- Reduce overhead
3. RETENTION
- Load rules
- Drop rules
4. BACKUP
- Deep storage
- Metadata
5. UPGRADE
- Rolling
- Test
""")
print("\n=== Anti-Patterns ===")
print("""
AVOID:
β No rollup
β Too many dimensions
β No time filter
β Complex joins
β Small segments
β No monitoring
β No backup
β No retention
""")
print("\n=== Checklist ===")
print("""
β Rollup enabled
β Dimensions minimized
β Metrics chosen
β Time filters
β Approximate algorithms
β Caching
β Monitoring
β Compaction
β Retention
β Backup
β Security
β Documentation
""")β FAQ
π― Frequently Asked Questions
Answers to common questions about Apache Druid.
What is Apache Druid?
Apache Druid is an open-source, distributed, real-time analytics database designed for fast slice-and-dice analytics on large datasets. It combines ideas from data warehouses, time-series databases, and search systems to deliver sub-second queries on streaming and batch data[citation:6][citation:18].
What is the difference between Druid and ClickHouse?
Druid is optimized for real-time streaming ingestion, high concurrency, and pre-aggregation (rollup). ClickHouse is known for raw batch ingestion speed and broad SQL coverage. Druid excels at user-facing analytics at scale; ClickHouse is faster for batch-heavy analytical workloads[citation:3][citation:9].
What is rollup in Druid?
Rollup is Druid's pre-aggregation feature. When enabled, rows with identical dimensions and timestamps are collapsed into a single row with aggregated metrics. This dramatically reduces storage and speeds up queries, at the cost of losing individual event details[citation:12].
Does Druid support exactly-once ingestion?
Yes. Druid provides exactly-once ingestion for Apache Kafka and Amazon Kinesis streams, with continuous backup into deep storage ensuring zero RPO (Recovery Point Objective)[citation:6].
When should I use Apache Druid?
Use Druid for real-time analytics applications that require sub-second queries on streaming and batch data at high concurrency, such as clickstream analysis, IoT monitoring, network performance monitoring, and user-facing dashboards[citation:6][citation:9].
What is a segment in Druid?
A segment is the fundamental storage unit in Druid β a column-oriented file containing up to a few million rows. Segments are partitioned by time, compressed, indexed, and stored in deep storage (S3, HDFS)[citation:1][citation:6].
What is the difference between Druid and Pinot?
Both are real-time OLAP databases. Druid emphasizes rollup, streaming ingestion, and broad use cases. Pinot emphasizes per-column indexing, single-query-shape optimization, and was built by LinkedIn for user-facing analytics[citation:3][citation:9].
How does Druid achieve sub-second queries?
Druid uses scatter/gather parallel processing, columnar storage with compression, bitmap indexes for fast filtering, and segment pruning based on time intervals and filters. Queries only read relevant columns and segments[citation:6].
Can Druid handle updates and deletes?
No, not in the traditional sense. Druid is append-only. You can overwrite data by reingesting with a higher version number, but individual row updates/deletes are not supported. This is a trade-off for performance[citation:1].
How many servers does Druid need?
Druid can run on a single server for development (quickstart). Production clusters typically use 3 server types: Master (Coordinator + Overlord), Query (Broker + Router), and Data (Historical + MiddleManager). Cluster size scales to thousands of nodes[citation:7].
# Quick Reference
print("=== Quick Answers ===")
print("""
Q: What is Druid?
A: Real-time analytics database.
Q: Sub-second queries?
A: Yes β designed for it.
Q: Streaming?
A: Kafka, Kinesis.
Q: Rollup?
A: Pre-aggregation, default on.
Q: Updates?
A: No β append-only.
Q: SQL?
A: Yes β partial support.
Q: Joins?
A: Limited.
Q: Kubernetes?
A: Yes β Druid Operator.
Q: Managed?
A: Imply.
Q: Alternative?
A: ClickHouse, Pinot.
Q: Best for?
A: Real-time, high concurrency.
""")π Future
π― Where Druid Is Going
The future is AI-augmented, cloud-native, Kubernetes-first, and more integrated with the modern data stack.
Future Directions
AI: Auto-optimization. Cloud: Managed. K8s: Native. Integration: Lakehouse. Performance: Faster. Open: Standards.
# Future of Druid
print("=== 1. AI-Augmented ===")
print("""
Trend: AI in Druid
AI:
- Auto-optimization
- Query recommendations
- Anomaly detection
- Auto-scaling
Future:
- Self-tuning
- Predictive
- Autonomous
""")
print("\n=== 2. Cloud-Native ===")
print("""
Trend: Cloud-first
Managed:
- Imply
- AWS
- GCP
- Azure
Serverless:
- No infrastructure
- Auto-scaling
- Pay per use
Future:
- Serverless default
- Managed
- Cost-effective
""")
print("\n=== 3. Kubernetes ===")
print("""
Trend: K8s-native
Druid Operator:
- Kubernetes controller
- CRDs
- Helm
Features:
- Dynamic scaling
- Resource sharing
- Easier deployment
Future:
- K8s default
- Operator
- Cloud-native
""")
print("\n=== 4. Lakehouse Integration ===")
print("""
Trend: Druid + Lakehouse
Integration:
- Iceberg
- Delta Lake
- Hudi
Features:
- Read from lake
- Write to lake
- Unified
Future:
- Lakehouse-native
- Open formats
- Unified analytics
""")
print("\n=== 5. Performance ===")
print("""
Trend: Faster
Features:
- New segment format (v10)
- Better compression
- Faster queries
- Lower memory
Future:
- Sub-100ms
- Higher concurrency
- Lower cost
""")
print("\n=== 6. Open Standards ===")
print("""
Trend: Open wins
Standards:
- SQL
- Iceberg
- OpenLineage
- OpenTelemetry
Future:
- Interoperability
- No lock-in
- Open
""")
# TIMELINE
print("\n=== Timeline ===")
print("""
Past:
2011: Druid at Metamarkets
2018: Apache top-level
2020: Cloud services
2022: Mature
2024: Segment v10
Present:
2025: Mature
2026: AI-augmented
Future:
2030: Serverless?
2035: AI-native?
2040: New paradigms?
""")
print("\n=== Final Thoughts ===")
print("""
Apache Druid is:
- Real-time analytics
- Sub-second queries
- High concurrency
- Streaming + batch
- Rollup
The future is:
- AI-augmented
- Cloud-native
- K8s-first
- Lakehouse-integrated
- Open
"Real-time insights at scale."
Keep exploring. Keep building.
""")