Store-gateway

The store-gateway is the Cortex service responsible to query series from blocks. The store-gateway is required when running the Cortex blocks storage.

The store-gateway is semi-stateful.

How it works

At startup store-gateways iterate over the entire storage bucket to discover blocks for all tenants and download the meta.json and index-header for each block. During this initial bucket synchronization phase, the store-gateway /ready readiness probe endpoint will fail.

While running, store-gateways periodically rescan the storage bucket to discover new blocks (uploaded by the ingesters and compactor) and blocks marked for deletion or fully deleted since the last scan (as a result of compaction). The frequency at which this occurs is configured via -blocks-storage.bucket-store.sync-interval.

The blocks chunks and the entire index are never fully downloaded by the store-gateway. The index-header is stored to the local disk, in order to avoid to re-download it on subsequent restarts of a store-gateway. For this reason, it’s recommended - but not required - to run the store-gateway with a persistent disk. For example, if you’re running the Cortex cluster in Kubernetes, you may use a StatefulSet with a persistent volume claim for the store-gateways.

For more information about the index-header, please refer to Binary index-header documentation.

Blocks sharding and replication

The store-gateway optionally supports blocks sharding. Sharding can be used to horizontally scale blocks in a large cluster without hitting any vertical scalability limit.

When sharding is enabled, store-gateway instances builds an hash ring and blocks get sharded and replicated across the pool of store-gateway instances registered within the ring.

Store-gateways continuously monitor the ring state and whenever the ring topology changes (e.g. a new instance has been added/removed or gets healthy/unhealthy) each store-gateway instance resync the blocks assigned to its shard, based on the block ID hash matching the token ranges assigned to the instance itself within the ring.

For each block belonging to a store-gateway shard, the store-gateway loads its meta.json, the deletion-mark.json and the index-header. Once a block is loaded on the store-gateway, it’s ready to be queried by queriers. When the querier queries blocks through a store-gateway, the response will contain the list of actually queried block IDs. If a querier tries to query a block which has not been loaded by a store-gateway, the querier will either retry on a different store-gateway (if blocks replication is enabled) or fail the query.

Blocks can be replicated across multiple store-gateway instances based on a replication factor configured via -store-gateway.sharding-ring.replication-factor. The blocks replication is used to protect from query failures caused by some blocks not loaded by any store-gateway instance at a given time like, for example, in the event of a store-gateway failure or while restarting a store-gateway instance (e.g. during a rolling update).

This feature can be enabled via -store-gateway.sharding-enabled=true and requires the backend hash ring to be configured via -store-gateway.sharding-ring.* flags (or their respective YAML config options).

Sharding strategies

The store-gateway supports two sharding strategies:

  • default
  • shuffle-sharding

The default sharding strategy spreads the blocks of each tenant across all store-gateway instances. It’s the easiest form of sharding supported, but doesn’t provide any workload isolation between different tenants.

The shuffle-sharding strategy spreads the blocks of a tenant across a subset of store-gateway instances. This way, the number of store-gateway instances loading blocks of a single tenant is limited and the blast radius of any issue that could be introduced by the tenant’s workload is limited to its shard instances.

The shuffle sharding strategy can be enabled via -store-gateway.sharding-strategy=shuffle-sharding and requires the -store-gateway.tenant-shard-size flag (or their respective YAML config options) to be set to the default shard size, which is the default number of store-gateway instances each tenant should be sharded to. The shard size can then be overridden on a per-tenant basis setting the store_gateway_tenant_shard_size in the limits overrides.

Please check out the shuffle sharding documentation for more information about how it works.

Auto-forget

When a store-gateway instance cleanly shutdowns, it automatically unregisters itself from the ring. However, in the event of a crash or node failure, the instance will not be unregistered from the ring, potentially leaving a spurious entry in the ring forever.

To protect from this, when an healthy store-gateway instance finds another instance in the ring which is unhealthy for more than 10 times the configured -store-gateway.sharding-ring.heartbeat-timeout, the healthy instance forcibly removes the unhealthy one from the ring.

This feature is called auto-forget and is built into the store-gateway.

Zone-awareness

The store-gateway replication optionally supports zone-awareness. When zone-aware replication is enabled and the blocks replication factor is > 1, each block is guaranteed to be replicated across store-gateway instances running in different availability zones.

To enable the zone-aware replication for the store-gateways you should:

  1. Configure the availability zone for each store-gateway via the -store-gateway.sharding-ring.instance-availability-zone CLI flag (or its respective YAML config option)
  2. Enable blocks zone-aware replication via the -store-gateway.sharding-ring.zone-awareness-enabled CLI flag (or its respective YAML config option). Please be aware this configuration option should be set to store-gateways, queriers and rulers.
  3. Rollout store-gateways, queriers and rulers to apply the new configuration

Caching

The store-gateway supports the following caches:

Caching is optional, but highly recommended in a production environment. Please also check out the production tips for more information about configuring the cache.

Index cache

The store-gateway can use a cache to speed up lookups of postings and series from TSDB blocks indexes. Two backends are supported:

  • inmemory
  • memcached

In-memory index cache

The inmemory index cache is enabled by default and its max size can be configured through the flag -blocks-storage.bucket-store.index-cache.inmemory.max-size-bytes (or config file). The trade-off of using the in-memory index cache is:

  • Pros: zero latency
  • Cons: increased store-gateway memory usage, not shared across multiple store-gateway replicas (when sharding is disabled or replication factor > 1)

Memcached index cache

The memcached index cache allows to use Memcached as cache backend. This cache backend is configured using -blocks-storage.bucket-store.index-cache.backend=memcached and requires the Memcached server(s) addresses via -blocks-storage.bucket-store.index-cache.memcached.addresses (or config file). The addresses are resolved using the DNS service provider.

The trade-off of using the Memcached index cache is:

  • Pros: can scale beyond a single node memory (Memcached cluster), shared across multiple store-gateway instances
  • Cons: higher latency in the cache round trip compared to the in-memory one

The Memcached client uses a jump hash algorithm to shard cached entries across a cluster of Memcached servers. For this reason, you should make sure memcached servers are not behind any kind of load balancer and their address is configured so that servers are added/removed to the end of the list whenever a scale up/down occurs.

For example, if you’re running Memcached in Kubernetes, you may:

  1. Deploy your Memcached cluster using a StatefulSet
  2. Create an headless service for Memcached StatefulSet
  3. Configure the Cortex’s Memcached client address using the dnssrvnoa+ service discovery

Chunks cache

Store-gateway can also use a cache for storing chunks fetched from the storage. Chunks contain actual samples, and can be reused if user query hits the same series for the same time range.

To enable chunks cache, please set -blocks-storage.bucket-store.chunks-cache.backend. Chunks can currently only be stored into Memcached cache. Memcached client can be configured via flags with -blocks-storage.bucket-store.chunks-cache.memcached.* prefix.

There are additional low-level options for configuring chunks cache. Please refer to other flags with -blocks-storage.bucket-store.chunks-cache.* prefix.

Metadata cache

Store-gateway and querier can use memcached for caching bucket metadata:

  • List of tenants
  • List of blocks per tenant
  • Block’s meta.json content
  • Block’s deletion-mark.json existence and content

Using the metadata cache can significantly reduce the number of API calls to object storage and protects from linearly scale the number of these API calls with the number of querier and store-gateway instances (because the bucket is periodically scanned and synched by each querier and store-gateway).

To enable metadata cache, please set -blocks-storage.bucket-store.metadata-cache.backend. Only memcached backend is supported currently. Memcached client has additional configuration available via flags with -blocks-storage.bucket-store.metadata-cache.memcached.* prefix.

Additional options for configuring metadata cache have -blocks-storage.bucket-store.metadata-cache.* prefix. By configuring TTL to zero or negative value, caching of given item type is disabled.

The same memcached backend cluster should be shared between store-gateways and queriers.

Store-gateway HTTP endpoints

  • GET /store-gateway/ring
    Displays the status of the store-gateways ring, including the tokens owned by each store-gateway and an option to remove (forget) instances from the ring.

Store-gateway configuration

This section described the store-gateway configuration. For the general Cortex configuration and references to common config blocks, please refer to the configuration documentation.

store_gateway_config

The store_gateway_config configures the store-gateway service used by the blocks storage.

store_gateway:
  # Shard blocks across multiple store gateway instances. This option needs be
  # set both on the store-gateway and querier when running in microservices
  # mode.
  # CLI flag: -store-gateway.sharding-enabled
  [sharding_enabled: <boolean> | default = false]

  # The hash ring configuration. This option is required only if blocks sharding
  # is enabled.
  sharding_ring:
    # The key-value store used to share the hash ring across multiple instances.
    # This option needs be set both on the store-gateway and querier when
    # running in microservices mode.
    kvstore:
      # Backend storage to use for the ring. Supported values are: consul, etcd,
      # inmemory, memberlist, multi.
      # CLI flag: -store-gateway.sharding-ring.store
      [store: <string> | default = "consul"]

      # The prefix for the keys in the store. Should end with a /.
      # CLI flag: -store-gateway.sharding-ring.prefix
      [prefix: <string> | default = "collectors/"]

      # The consul_config configures the consul client.
      # The CLI flags prefix for this block config is:
      # store-gateway.sharding-ring
      [consul: <consul_config>]

      # The etcd_config configures the etcd client.
      # The CLI flags prefix for this block config is:
      # store-gateway.sharding-ring
      [etcd: <etcd_config>]

      multi:
        # Primary backend storage used by multi-client.
        # CLI flag: -store-gateway.sharding-ring.multi.primary
        [primary: <string> | default = ""]

        # Secondary backend storage used by multi-client.
        # CLI flag: -store-gateway.sharding-ring.multi.secondary
        [secondary: <string> | default = ""]

        # Mirror writes to secondary store.
        # CLI flag: -store-gateway.sharding-ring.multi.mirror-enabled
        [mirror_enabled: <boolean> | default = false]

        # Timeout for storing value to secondary store.
        # CLI flag: -store-gateway.sharding-ring.multi.mirror-timeout
        [mirror_timeout: <duration> | default = 2s]

    # Period at which to heartbeat to the ring.
    # CLI flag: -store-gateway.sharding-ring.heartbeat-period
    [heartbeat_period: <duration> | default = 15s]

    # The heartbeat timeout after which store gateways are considered unhealthy
    # within the ring. This option needs be set both on the store-gateway and
    # querier when running in microservices mode.
    # CLI flag: -store-gateway.sharding-ring.heartbeat-timeout
    [heartbeat_timeout: <duration> | default = 1m]

    # The replication factor to use when sharding blocks. This option needs be
    # set both on the store-gateway and querier when running in microservices
    # mode.
    # CLI flag: -store-gateway.sharding-ring.replication-factor
    [replication_factor: <int> | default = 3]

    # File path where tokens are stored. If empty, tokens are not stored at
    # shutdown and restored at startup.
    # CLI flag: -store-gateway.sharding-ring.tokens-file-path
    [tokens_file_path: <string> | default = ""]

    # True to enable zone-awareness and replicate blocks across different
    # availability zones.
    # CLI flag: -store-gateway.sharding-ring.zone-awareness-enabled
    [zone_awareness_enabled: <boolean> | default = false]

    # Name of network interface to read address from.
    # CLI flag: -store-gateway.sharding-ring.instance-interface-names
    [instance_interface_names: <list of string> | default = [eth0 en0]]

    # The availability zone where this instance is running. Required if
    # zone-awareness is enabled.
    # CLI flag: -store-gateway.sharding-ring.instance-availability-zone
    [instance_availability_zone: <string> | default = ""]

  # The sharding strategy to use. Supported values are: default,
  # shuffle-sharding.
  # CLI flag: -store-gateway.sharding-strategy
  [sharding_strategy: <string> | default = "default"]

blocks_storage_config

The blocks_storage_config configures the blocks storage.

blocks_storage:
  # Backend storage to use. Supported backends are: s3, gcs, azure, filesystem.
  # CLI flag: -blocks-storage.backend
  [backend: <string> | default = "s3"]

  s3:
    # The S3 bucket endpoint. It could be an AWS S3 endpoint listed at
    # https://docs.aws.amazon.com/general/latest/gr/s3.html or the address of an
    # S3-compatible service in hostname:port format.
    # CLI flag: -blocks-storage.s3.endpoint
    [endpoint: <string> | default = ""]

    # S3 bucket name
    # CLI flag: -blocks-storage.s3.bucket-name
    [bucket_name: <string> | default = ""]

    # S3 secret access key
    # CLI flag: -blocks-storage.s3.secret-access-key
    [secret_access_key: <string> | default = ""]

    # S3 access key ID
    # CLI flag: -blocks-storage.s3.access-key-id
    [access_key_id: <string> | default = ""]

    # If enabled, use http:// for the S3 endpoint instead of https://. This
    # could be useful in local dev/test environments while using an
    # S3-compatible backend storage, like Minio.
    # CLI flag: -blocks-storage.s3.insecure
    [insecure: <boolean> | default = false]

    http:
      # The time an idle connection will remain idle before closing.
      # CLI flag: -blocks-storage.s3.http.idle-conn-timeout
      [idle_conn_timeout: <duration> | default = 1m30s]

      # The amount of time the client will wait for a servers response headers.
      # CLI flag: -blocks-storage.s3.http.response-header-timeout
      [response_header_timeout: <duration> | default = 2m]

      # If the client connects to S3 via HTTPS and this option is enabled, the
      # client will accept any certificate and hostname.
      # CLI flag: -blocks-storage.s3.http.insecure-skip-verify
      [insecure_skip_verify: <boolean> | default = false]

  gcs:
    # GCS bucket name
    # CLI flag: -blocks-storage.gcs.bucket-name
    [bucket_name: <string> | default = ""]

    # JSON representing either a Google Developers Console
    # client_credentials.json file or a Google Developers service account key
    # file. If empty, fallback to Google default logic.
    # CLI flag: -blocks-storage.gcs.service-account
    [service_account: <string> | default = ""]

  azure:
    # Azure storage account name
    # CLI flag: -blocks-storage.azure.account-name
    [account_name: <string> | default = ""]

    # Azure storage account key
    # CLI flag: -blocks-storage.azure.account-key
    [account_key: <string> | default = ""]

    # Azure storage container name
    # CLI flag: -blocks-storage.azure.container-name
    [container_name: <string> | default = ""]

    # Azure storage endpoint suffix without schema. The account name will be
    # prefixed to this value to create the FQDN
    # CLI flag: -blocks-storage.azure.endpoint-suffix
    [endpoint_suffix: <string> | default = ""]

    # Number of retries for recoverable errors
    # CLI flag: -blocks-storage.azure.max-retries
    [max_retries: <int> | default = 20]

  filesystem:
    # Local filesystem storage directory.
    # CLI flag: -blocks-storage.filesystem.dir
    [dir: <string> | default = ""]

  # This configures how the store-gateway synchronizes blocks stored in the
  # bucket.
  bucket_store:
    # Directory to store synchronized TSDB index headers.
    # CLI flag: -blocks-storage.bucket-store.sync-dir
    [sync_dir: <string> | default = "tsdb-sync"]

    # How frequently scan the bucket to look for changes (new blocks shipped by
    # ingesters and blocks removed by retention or compaction). 0 disables it.
    # CLI flag: -blocks-storage.bucket-store.sync-interval
    [sync_interval: <duration> | default = 5m]

    # Max size - in bytes - of a per-tenant chunk pool, used to reduce memory
    # allocations.
    # CLI flag: -blocks-storage.bucket-store.max-chunk-pool-bytes
    [max_chunk_pool_bytes: <int> | default = 2147483648]

    # Max number of concurrent queries to execute against the long-term storage.
    # The limit is shared across all tenants.
    # CLI flag: -blocks-storage.bucket-store.max-concurrent
    [max_concurrent: <int> | default = 100]

    # Maximum number of concurrent tenants synching blocks.
    # CLI flag: -blocks-storage.bucket-store.tenant-sync-concurrency
    [tenant_sync_concurrency: <int> | default = 10]

    # Maximum number of concurrent blocks synching per tenant.
    # CLI flag: -blocks-storage.bucket-store.block-sync-concurrency
    [block_sync_concurrency: <int> | default = 20]

    # Number of Go routines to use when syncing block meta files from object
    # storage per tenant.
    # CLI flag: -blocks-storage.bucket-store.meta-sync-concurrency
    [meta_sync_concurrency: <int> | default = 20]

    # Minimum age of a block before it's being read. Set it to safe value (e.g
    # 30m) if your object storage is eventually consistent. GCS and S3 are
    # (roughly) strongly consistent.
    # CLI flag: -blocks-storage.bucket-store.consistency-delay
    [consistency_delay: <duration> | default = 0s]

    index_cache:
      # The index cache backend type. Supported values: inmemory, memcached.
      # CLI flag: -blocks-storage.bucket-store.index-cache.backend
      [backend: <string> | default = "inmemory"]

      inmemory:
        # Maximum size in bytes of in-memory index cache used to speed up blocks
        # index lookups (shared between all tenants).
        # CLI flag: -blocks-storage.bucket-store.index-cache.inmemory.max-size-bytes
        [max_size_bytes: <int> | default = 1073741824]

      memcached:
        # Comma separated list of memcached addresses. Supported prefixes are:
        # dns+ (looked up as an A/AAAA query), dnssrv+ (looked up as a SRV
        # query, dnssrvnoa+ (looked up as a SRV query, with no A/AAAA lookup
        # made after that).
        # CLI flag: -blocks-storage.bucket-store.index-cache.memcached.addresses
        [addresses: <string> | default = ""]

        # The socket read/write timeout.
        # CLI flag: -blocks-storage.bucket-store.index-cache.memcached.timeout
        [timeout: <duration> | default = 100ms]

        # The maximum number of idle connections that will be maintained per
        # address.
        # CLI flag: -blocks-storage.bucket-store.index-cache.memcached.max-idle-connections
        [max_idle_connections: <int> | default = 16]

        # The maximum number of concurrent asynchronous operations can occur.
        # CLI flag: -blocks-storage.bucket-store.index-cache.memcached.max-async-concurrency
        [max_async_concurrency: <int> | default = 50]

        # The maximum number of enqueued asynchronous operations allowed.
        # CLI flag: -blocks-storage.bucket-store.index-cache.memcached.max-async-buffer-size
        [max_async_buffer_size: <int> | default = 10000]

        # The maximum number of concurrent connections running get operations.
        # If set to 0, concurrency is unlimited.
        # CLI flag: -blocks-storage.bucket-store.index-cache.memcached.max-get-multi-concurrency
        [max_get_multi_concurrency: <int> | default = 100]

        # The maximum number of keys a single underlying get operation should
        # run. If more keys are specified, internally keys are splitted into
        # multiple batches and fetched concurrently, honoring the max
        # concurrency. If set to 0, the max batch size is unlimited.
        # CLI flag: -blocks-storage.bucket-store.index-cache.memcached.max-get-multi-batch-size
        [max_get_multi_batch_size: <int> | default = 0]

        # The maximum size of an item stored in memcached. Bigger items are not
        # stored. If set to 0, no maximum size is enforced.
        # CLI flag: -blocks-storage.bucket-store.index-cache.memcached.max-item-size
        [max_item_size: <int> | default = 1048576]

      # Compress postings before storing them to postings cache.
      # CLI flag: -blocks-storage.bucket-store.index-cache.postings-compression-enabled
      [postings_compression_enabled: <boolean> | default = false]

    chunks_cache:
      # Backend for chunks cache, if not empty. Supported values: memcached.
      # CLI flag: -blocks-storage.bucket-store.chunks-cache.backend
      [backend: <string> | default = ""]

      memcached:
        # Comma separated list of memcached addresses. Supported prefixes are:
        # dns+ (looked up as an A/AAAA query), dnssrv+ (looked up as a SRV
        # query, dnssrvnoa+ (looked up as a SRV query, with no A/AAAA lookup
        # made after that).
        # CLI flag: -blocks-storage.bucket-store.chunks-cache.memcached.addresses
        [addresses: <string> | default = ""]

        # The socket read/write timeout.
        # CLI flag: -blocks-storage.bucket-store.chunks-cache.memcached.timeout
        [timeout: <duration> | default = 100ms]

        # The maximum number of idle connections that will be maintained per
        # address.
        # CLI flag: -blocks-storage.bucket-store.chunks-cache.memcached.max-idle-connections
        [max_idle_connections: <int> | default = 16]

        # The maximum number of concurrent asynchronous operations can occur.
        # CLI flag: -blocks-storage.bucket-store.chunks-cache.memcached.max-async-concurrency
        [max_async_concurrency: <int> | default = 50]

        # The maximum number of enqueued asynchronous operations allowed.
        # CLI flag: -blocks-storage.bucket-store.chunks-cache.memcached.max-async-buffer-size
        [max_async_buffer_size: <int> | default = 10000]

        # The maximum number of concurrent connections running get operations.
        # If set to 0, concurrency is unlimited.
        # CLI flag: -blocks-storage.bucket-store.chunks-cache.memcached.max-get-multi-concurrency
        [max_get_multi_concurrency: <int> | default = 100]

        # The maximum number of keys a single underlying get operation should
        # run. If more keys are specified, internally keys are splitted into
        # multiple batches and fetched concurrently, honoring the max
        # concurrency. If set to 0, the max batch size is unlimited.
        # CLI flag: -blocks-storage.bucket-store.chunks-cache.memcached.max-get-multi-batch-size
        [max_get_multi_batch_size: <int> | default = 0]

        # The maximum size of an item stored in memcached. Bigger items are not
        # stored. If set to 0, no maximum size is enforced.
        # CLI flag: -blocks-storage.bucket-store.chunks-cache.memcached.max-item-size
        [max_item_size: <int> | default = 1048576]

      # Size of each subrange that bucket object is split into for better
      # caching.
      # CLI flag: -blocks-storage.bucket-store.chunks-cache.subrange-size
      [subrange_size: <int> | default = 16000]

      # Maximum number of sub-GetRange requests that a single GetRange request
      # can be split into when fetching chunks. Zero or negative value =
      # unlimited number of sub-requests.
      # CLI flag: -blocks-storage.bucket-store.chunks-cache.max-get-range-requests
      [max_get_range_requests: <int> | default = 3]

      # TTL for caching object attributes for chunks.
      # CLI flag: -blocks-storage.bucket-store.chunks-cache.attributes-ttl
      [attributes_ttl: <duration> | default = 24h]

      # TTL for caching individual chunks subranges.
      # CLI flag: -blocks-storage.bucket-store.chunks-cache.subrange-ttl
      [subrange_ttl: <duration> | default = 24h]

    metadata_cache:
      # Backend for metadata cache, if not empty. Supported values: memcached.
      # CLI flag: -blocks-storage.bucket-store.metadata-cache.backend
      [backend: <string> | default = ""]

      memcached:
        # Comma separated list of memcached addresses. Supported prefixes are:
        # dns+ (looked up as an A/AAAA query), dnssrv+ (looked up as a SRV
        # query, dnssrvnoa+ (looked up as a SRV query, with no A/AAAA lookup
        # made after that).
        # CLI flag: -blocks-storage.bucket-store.metadata-cache.memcached.addresses
        [addresses: <string> | default = ""]

        # The socket read/write timeout.
        # CLI flag: -blocks-storage.bucket-store.metadata-cache.memcached.timeout
        [timeout: <duration> | default = 100ms]

        # The maximum number of idle connections that will be maintained per
        # address.
        # CLI flag: -blocks-storage.bucket-store.metadata-cache.memcached.max-idle-connections
        [max_idle_connections: <int> | default = 16]

        # The maximum number of concurrent asynchronous operations can occur.
        # CLI flag: -blocks-storage.bucket-store.metadata-cache.memcached.max-async-concurrency
        [max_async_concurrency: <int> | default = 50]

        # The maximum number of enqueued asynchronous operations allowed.
        # CLI flag: -blocks-storage.bucket-store.metadata-cache.memcached.max-async-buffer-size
        [max_async_buffer_size: <int> | default = 10000]

        # The maximum number of concurrent connections running get operations.
        # If set to 0, concurrency is unlimited.
        # CLI flag: -blocks-storage.bucket-store.metadata-cache.memcached.max-get-multi-concurrency
        [max_get_multi_concurrency: <int> | default = 100]

        # The maximum number of keys a single underlying get operation should
        # run. If more keys are specified, internally keys are splitted into
        # multiple batches and fetched concurrently, honoring the max
        # concurrency. If set to 0, the max batch size is unlimited.
        # CLI flag: -blocks-storage.bucket-store.metadata-cache.memcached.max-get-multi-batch-size
        [max_get_multi_batch_size: <int> | default = 0]

        # The maximum size of an item stored in memcached. Bigger items are not
        # stored. If set to 0, no maximum size is enforced.
        # CLI flag: -blocks-storage.bucket-store.metadata-cache.memcached.max-item-size
        [max_item_size: <int> | default = 1048576]

      # How long to cache list of tenants in the bucket.
      # CLI flag: -blocks-storage.bucket-store.metadata-cache.tenants-list-ttl
      [tenants_list_ttl: <duration> | default = 15m]

      # How long to cache list of blocks for each tenant.
      # CLI flag: -blocks-storage.bucket-store.metadata-cache.tenant-blocks-list-ttl
      [tenant_blocks_list_ttl: <duration> | default = 5m]

      # How long to cache list of chunks for a block.
      # CLI flag: -blocks-storage.bucket-store.metadata-cache.chunks-list-ttl
      [chunks_list_ttl: <duration> | default = 24h]

      # How long to cache information that block metafile exists.
      # CLI flag: -blocks-storage.bucket-store.metadata-cache.metafile-exists-ttl
      [metafile_exists_ttl: <duration> | default = 2h]

      # How long to cache information that block metafile doesn't exist.
      # CLI flag: -blocks-storage.bucket-store.metadata-cache.metafile-doesnt-exist-ttl
      [metafile_doesnt_exist_ttl: <duration> | default = 5m]

      # How long to cache content of the metafile.
      # CLI flag: -blocks-storage.bucket-store.metadata-cache.metafile-content-ttl
      [metafile_content_ttl: <duration> | default = 24h]

      # Maximum size of metafile content to cache in bytes.
      # CLI flag: -blocks-storage.bucket-store.metadata-cache.metafile-max-size-bytes
      [metafile_max_size_bytes: <int> | default = 1048576]

    # Duration after which the blocks marked for deletion will be filtered out
    # while fetching blocks. The idea of ignore-deletion-marks-delay is to
    # ignore blocks that are marked for deletion with some delay. This ensures
    # store can still serve blocks that are meant to be deleted but do not have
    # a replacement yet. Default is 6h, half of the default value for
    # -compactor.deletion-delay.
    # CLI flag: -blocks-storage.bucket-store.ignore-deletion-marks-delay
    [ignore_deletion_mark_delay: <duration> | default = 6h]

  tsdb:
    # Local directory to store TSDBs in the ingesters.
    # CLI flag: -blocks-storage.tsdb.dir
    [dir: <string> | default = "tsdb"]

    # TSDB blocks range period.
    # CLI flag: -blocks-storage.tsdb.block-ranges-period
    [block_ranges_period: <list of duration> | default = 2h0m0s]

    # TSDB blocks retention in the ingester before a block is removed. This
    # should be larger than the block_ranges_period and large enough to give
    # store-gateways and queriers enough time to discover newly uploaded blocks.
    # CLI flag: -blocks-storage.tsdb.retention-period
    [retention_period: <duration> | default = 6h]

    # How frequently the TSDB blocks are scanned and new ones are shipped to the
    # storage. 0 means shipping is disabled.
    # CLI flag: -blocks-storage.tsdb.ship-interval
    [ship_interval: <duration> | default = 1m]

    # Maximum number of tenants concurrently shipping blocks to the storage.
    # CLI flag: -blocks-storage.tsdb.ship-concurrency
    [ship_concurrency: <int> | default = 10]

    # How frequently does Cortex try to compact TSDB head. Block is only created
    # if data covers smallest block range. Must be greater than 0 and max 5
    # minutes.
    # CLI flag: -blocks-storage.tsdb.head-compaction-interval
    [head_compaction_interval: <duration> | default = 1m]

    # Maximum number of tenants concurrently compacting TSDB head into a new
    # block
    # CLI flag: -blocks-storage.tsdb.head-compaction-concurrency
    [head_compaction_concurrency: <int> | default = 5]

    # If TSDB head is idle for this duration, it is compacted. 0 means disabled.
    # CLI flag: -blocks-storage.tsdb.head-compaction-idle-timeout
    [head_compaction_idle_timeout: <duration> | default = 1h]

    # The number of shards of series to use in TSDB (must be a power of 2).
    # Reducing this will decrease memory footprint, but can negatively impact
    # performance.
    # CLI flag: -blocks-storage.tsdb.stripe-size
    [stripe_size: <int> | default = 16384]

    # True to enable TSDB WAL compression.
    # CLI flag: -blocks-storage.tsdb.wal-compression-enabled
    [wal_compression_enabled: <boolean> | default = false]

    # True to flush blocks to storage on shutdown. If false, incomplete blocks
    # will be reused after restart.
    # CLI flag: -blocks-storage.tsdb.flush-blocks-on-shutdown
    [flush_blocks_on_shutdown: <boolean> | default = false]

    # limit the number of concurrently opening TSDB's on startup
    # CLI flag: -blocks-storage.tsdb.max-tsdb-opening-concurrency-on-startup
    [max_tsdb_opening_concurrency_on_startup: <int> | default = 10]