Implementing Sharding and Scaling
1. Sharding by Hash
| Property | Description | Values | Notes |
|---|---|---|---|
| sharding.algorithm | Algorithm used for sharding | hash |
Default sharding method in Prometheus |
| shard.key | Label used to determine shard | instance |
Can be any label present on metrics |
| shard.count | Number of shards to create | 4 |
Must be a power of 2 for optimal distribution |
Note: Hash sharding ensures consistent distribution of metrics across shards, reducing contention and improving query performance.
2. Sharding by Target
| Property | Description | Values |
|---|---|---|
| sharding.strategy | Defines the sharding strategy for target distribution | hash, range |
| sharding.key | Key used for sharding logic (e.g., target labels) | instance, job, custom label |
Example: Configuring sharding by target label
scrape_configs:
- job_name: "sharded-metrics"
scrape_interval: 15s
sharding:
strategy: hash
key: instance
Note: Sharding by target ensures that each Prometheus instance only scrapes a subset of targets, reducing load and improving scalability.
3. Using Modulus Relabeling
Modulus relabeling is a technique used in Prometheus to distribute metrics across multiple instances by hashing metric labels and assigning them to specific shards based on a modulus operation.
| Label | Description | Usage |
|---|---|---|
| __shard__ | Calculated shard ID based on the modulus of a label value. | Used internally by Prometheus to route metrics to the correct shard. |
| __modulus__ | Configurable value that determines the number of shards. | Set in Prometheus configuration to define shard distribution. |
Example: Configuring Modulus Relabeling
scrape_configs:
- job_name: "sharded-metrics"
static_configs:
- targets: ['localhost:9090']
relabel_configs:
- source_labels: [__address__]
target_label: __shard__
modulus: 4
Note: The
modulus parameter determines how many shards the metrics will be distributed across. Ensure that all Prometheus instances in the sharding setup use the same modulus value to maintain consistency.
4. Implementing Horizontal Scaling
Example: Configuring Prometheus for Horizontal Scaling
# prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"]
rule_files:
- "rules.yml"
remote_write:
- url: "http://remote-prometheus-1:9090/api/v1/write"
queue_config:
capacity: 1000
max_samples_per_send: 100
batch_send_deadline: 5s
remote_read:
- url: "http://remote-prometheus-1:9090/api/v1/read"
| Configuration Option | Description | Default Value |
|---|---|---|
| remote_write.url | URL to write samples to | None |
| remote_write.queue_config.capacity | Maximum number of samples to queue | 1000 |
| remote_write.queue_config.max_samples_per_send | Maximum samples per send request | 100 |
| remote_write.queue_config.batch_send_deadline | Max time to wait before sending a batch | 5s |
| remote_read.url | URL to read samples from | None |
Note: Horizontal scaling in Prometheus is achieved through remote storage and federation.
Horizontal Scaling Strategies
- Remote Storage: Write samples to external systems like Thanos or Cortex
- Federation: Use one Prometheus instance to scrape and forward metrics to another
- Sharding: Split the target list across multiple Prometheus instances
Steps to Implement Horizontal Scaling
- Set up a remote storage backend (e.g., Thanos, Cortex)
- Configure
remote_writein Prometheus to send data to the backend - Configure
remote_readto fetch data from the backend - Use
prometheus.ymlto define job targets and scrape intervals - Scale Prometheus instances horizontally by sharding target lists
5. Configuring Shard Count
| Parameter | Description | Default Value | Notes |
|---|---|---|---|
| shard.count | Number of shards to use for data distribution | 1 |
Must be a positive integer. Increasing this value increases parallelism but also resource usage. |
| shard.strategy | Strategy used to distribute data across shards | hash |
Options: hash, range, round-robin |
Note: The shard count should be chosen based on the expected data volume and query patterns to ensure optimal performance and resource utilization.
6. Using Service Discovery Filtering
Service discovery filtering in Prometheus allows you to narrow down the targets that are scraped by using label-based matching. This is particularly useful in environments with many services where you want to focus on specific subsets.
| Filter Type | Description | Example |
|---|---|---|
| static_config | Defines a static list of targets with labels. | {"targets": ["localhost:9090"], "labels": {"job": "prometheus"}} |
| file_sd_config | Uses a file to define targets and labels. | [{"targets": ["localhost:9090"], "labels": {"job": "prometheus"}}] |
| consul_sd_config | Discovers targets from Consul. | {"server": "localhost:8500", "services": ["prometheus"]} |
| kubernetes_sd_config | Discovers targets from Kubernetes. | {"role": "pod", "namespace": "monitoring"} |
Example: Filtering by Label in Prometheus Configuration
scrape_configs:
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"]
labels:
job: "prometheus"
env: "production"
- job_name: "node_exporter"
static_configs:
- targets: ["localhost:9100"]
labels:
job: "node_exporter"
env: "production"
- job_name: "filtered_exporter"
static_configs:
- targets: ["localhost:9100"]
labels:
job: "node_exporter"
env: "staging"
Note: Label-based filtering is applied at the job level. You can use relabeling rules to further refine which targets are scraped.
7. Implementing Dynamic Sharding
| Component | Description | Configuration |
|---|---|---|
| sharding.strategy | Defines the sharding approach used by Prometheus | hash, range |
| sharding.key | Key used for sharding logic (e.g., metric name) | __name__, job |
| sharding.replica | Replica identifier for sharded instances | replica=0 |
Example: Dynamic sharding configuration
scrape_configs:
- job_name: "prometheus"
static_configs:
- targets: [localhost:9090]
relabel_configs:
- source_labels: [__address__]
target_label: replica
replacement: "0"
Note: Dynamic sharding requires a consistent hashing algorithm to ensure that metrics are consistently routed to the same shard.
Warning: Misconfiguring sharding keys can lead to data inconsistency or loss.
| Sharding Strategy | Description | Use Case |
|---|---|---|
| hash | Uses hash-based distribution to assign metrics to shards | High cardinality metrics |
| range | Assigns metrics based on a range of values | Metrics with predictable value ranges |
8. Balancing Shard Load
| Strategy | Description | Implementation | Notes |
|---|---|---|---|
| Consistent Hashing | Maps metrics to shards using a hash ring for even distribution | |
Reduces shard movement during scaling |
| Dynamic Resharding | Automatically redistributes data when shards become unbalanced | |
Triggers when load exceeds threshold |
| Load Metrics | Tracks shard CPU, memory, and query rate to detect imbalance | rate(prometheus_tsdb_head_samples_appended_total[5m]) |
Used to calculate shard load ratio |
Example: Load Balancing Configuration
sharding:
strategy: consistent_hash
shards:
- name: shard-1
host: http://prometheus-1:9090
- name: shard-2
host: http://prometheus-2:9090
Note: Consistent hashing ensures minimal data movement when shards are added or removed.
Warning: Overloading a shard can cause query timeouts and data loss.
Load Balancing Best Practices
- Monitor shard CPU and memory usage regularly
- Use consistent hashing to minimize data reshuffling
- Set thresholds for rebalancing to avoid frequent resharding
9. Monitoring Shard Performance
| Metric | Description | Unit | Notes |
|---|---|---|---|
| prometheus_tsdb_head_chunks | Number of chunks in the head block | chunks | Indicates memory usage and ingestion rate |
| prometheus_tsdb_head_series | Number of series in the head block | series | Shows active time series count |
| prometheus_tsdb_wal_truncations | Total number of WAL truncations | count | High values may indicate performance issues |
| prometheus_tsdb_compaction_duration_seconds | Duration of compaction in seconds | seconds | Measures time to compact chunks into blocks |
| prometheus_tsdb_blocks_loaded | Number of blocks loaded into memory | blocks | Indicates how many block files are currently loaded |
Note: Use these metrics to detect performance bottlenecks in sharded environments.
10. Using Thanos for Scaling
Example: Deploying Thanos with Prometheus
prometheus:
config:
remote_write:
- url: "http://thanos-remote-write:19291/api/v1/receive"
send_exemplars: true
remote_read:
- url: "http://thanos-query:10902/api/v1/read"
thanos:
query:
endpoint:
- "http://prometheus:9090"
store:
endpoint:
- "http://prometheus:9090"
| Component | Description | Notes |
|---|---|---|
| thanos-query | Aggregates and queries data from multiple Prometheus instances | Must be configured with store endpoints |
| thanos-store | Stores and serves long-term metrics data | Can be configured with object storage (S3, GCS) |
| thanos-compact | Compacts and downsamples long-term data | Runs periodically to reduce storage size |
| thanos-ruler | Runs alerting rules across multiple Prometheus instances | Can be deployed in a distributed fashion |
Note: Thanos requires a shared object storage backend (e.g., S3, GCS) to store long-term metrics and metadata.
Warning: Ensure that all Prometheus instances are configured with consistent remote write endpoints to avoid data loss.
Thanos Scaling Benefits
- Horizontal scaling of Prometheus instances
- Long-term storage with object storage
- Global query view across multiple Prometheus instances
- High availability through distributed architecture
11. Implementing Cross-Shard Queries
When working with sharded Prometheus instances, cross-shard queries require special handling to ensure data consistency and performance. These queries span multiple shards and often involve aggregations across different Prometheus instances.
| Query Type | Description | Notes |
|---|---|---|
| Cross-shard aggregation | Aggregates metrics from multiple shards using PromQL | Use sum by (instance) or similar to combine results |
| Shard-aware query routing | Directs queries to specific shards based on labels or metrics | Requires external query routers like Thanos or Cortex |
| Global query federation | Collects and federates metrics from all shards into a single view | May introduce latency due to data collection overhead |
Note: When using cross-shard queries, ensure that the same metric labels are consistent across shards to avoid incorrect aggregations.
Warning: Queries that span multiple shards may experience higher latency than local queries, especially in high-latency network environments.
Key Considerations for Cross-Shard Queries
- Label consistency across shards is critical for accurate results.
- Use query routers like Thanos or Cortex to simplify cross-shard queries.
- Aggregations should be performed at the shard level where possible to reduce cross-shard data transfer.
- Monitor query performance and latency when querying across shards.
12. Planning Capacity for Shards
| Resource | Description | Recommended Allocation |
|---|---|---|
| Storage | Amount of disk space required per shard | 100GB - 500GB per shard depending on data retention |
| Memory | RAM needed for each shard's in-memory data structures | 2GB - 8GB per shard |
| CPU | Processing power for scraping and querying | 2 - 4 vCPUs per shard |
| Network | Bandwidth for scraping targets and inter-shard communication | 100 Mbps - 1 Gbps per shard |
Example: Shard Capacity Estimation
# Estimate storage needs based on metrics per second
METRICS_PER_SECOND=10000
RETENTION_DAYS=30
STORAGE_PER_METRIC=256 bytes
TOTAL_STORAGE_GB=$(echo "scale=2; ($METRICS_PER_SECOND * 86400 * $RETENTION_DAYS * 256) / (1024*1024*1024)" | bc)
echo "Estimated storage per shard: ${TOTAL_STORAGE_GB} GB"
Note: Shard capacity planning should consider both historical data and real-time scraping load.