Skip to main content

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

Example: Configuring Hash Sharding

sharding:
  algorithm: hash
  shard_key: instance
  shard_count: 4
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

  1. Set up a remote storage backend (e.g., Thanos, Cortex)
  2. Configure remote_write in Prometheus to send data to the backend
  3. Configure remote_read to fetch data from the backend
  4. Use prometheus.yml to define job targets and scrape intervals
  5. 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

Example: Setting Shard Count in Configuration

sharding:
  count: 4
  strategy: hash
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
func (s *Shard) GetShardForKey(key string) *Shard {
    hash := fnv1a.HashString(key)
    for _, shard := range s.shards {
        if hash <= shard.MaxHash {
            return shard
        }
    }
    return s.shards[0]
}
Reduces shard movement during scaling
Dynamic Resharding Automatically redistributes data when shards become unbalanced
sharding:
  strategy: dynamic
  threshold: 0.15
  rebalance_interval: 30s
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

Example: Querying Head Series Count


prometheus_tsdb_head_series

Example: Monitoring Compaction Duration


prometheus_tsdb_compaction_duration_seconds
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

Example: Cross-shard metric aggregation

sum by (job, instance) (
  rate(http_requests_total[5m])
)
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.

Key Considerations

  • Storage capacity must accommodate data retention policies
  • Memory allocation affects query performance and caching
  • CPU allocation impacts scraping and aggregation efficiency
  • Network bandwidth affects inter-shard communication and data sync

Was this article helpful?