<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Grafana Mimir components on Grafana Labs</title><link>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/</link><description>Recent content in Grafana Mimir components on Grafana Labs</description><generator>Hugo -- gohugo.io</generator><language>en</language><atom:link href="/docs/mimir/v3.1.x/references/architecture/components/index.xml" rel="self" type="application/rss+xml"/><item><title>Grafana Mimir compactor</title><link>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/compactor/</link><pubDate>Wed, 03 Jun 2026 09:01:40 +0200</pubDate><guid>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/compactor/</guid><content><![CDATA[&lt;h1 id=&#34;grafana-mimir-compactor&#34;&gt;Grafana Mimir compactor&lt;/h1&gt;
&lt;p&gt;The compactor increases query performance and reduces long-term storage usage by combining blocks.&lt;/p&gt;
&lt;p&gt;The compactor is the component responsible for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Compacting multiple blocks of a given tenant into a single, optimized larger block. This deduplicates chunks and reduces the size of the index, resulting in reduced storage costs. Querying fewer blocks is faster, so it also increases query speed.&lt;/li&gt;
&lt;li&gt;Keeping the per-tenant bucket index updated. The &lt;a href=&#34;../../bucket-index/&#34;&gt;bucket index&lt;/a&gt; is used by &lt;a href=&#34;../querier/&#34;&gt;queriers&lt;/a&gt;, &lt;a href=&#34;../store-gateway/&#34;&gt;store-gateways&lt;/a&gt;, and &lt;a href=&#34;../ruler/&#34;&gt;rulers&lt;/a&gt; to discover both new blocks and deleted blocks in the storage.&lt;/li&gt;
&lt;li&gt;Deleting blocks that are no longer within a configurable retention period.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The compactor is stateless.&lt;/p&gt;
&lt;h2 id=&#34;how-compaction-works&#34;&gt;How compaction works&lt;/h2&gt;
&lt;p&gt;Compaction occurs on a per-tenant basis.&lt;/p&gt;
&lt;p&gt;The compactor runs at regular, configurable intervals.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vertical compaction&lt;/strong&gt; merges all the blocks of a tenant uploaded by ingesters for the same time range (2 hours ranges by default) into a single block. It also deduplicates samples that were originally written to N blocks as a result of replication. Vertical compaction reduces the number of blocks for a single time range from the quantity of ingesters down to one block per tenant.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Horizontal compaction&lt;/strong&gt; triggers after a vertical compaction. It compacts several blocks with adjacent range periods into a single larger block. The total size of the associated block chunks does not change after horizontal compaction. The horizontal compaction may significantly reduce the size of the index and the index-header kept in memory by store-gateways.&lt;/p&gt;
&lt;p&gt;&lt;img
  class=&#34;lazyload d-inline-block&#34;
  data-src=&#34;compactor-horizontal-and-vertical-compaction.png&#34;
  alt=&#34;Compactor - horizontal and vertical compaction&#34;/&gt;&lt;/p&gt;
&lt;!-- Diagram source at https://docs.google.com/presentation/d/1bHp8_zcoWCYoNU2AhO2lSagQyuIrghkCncViSqn14cU/edit --&gt;
&lt;h2 id=&#34;scaling&#34;&gt;Scaling&lt;/h2&gt;
&lt;p&gt;Compaction can be tuned for clusters with large tenants. Configuration specifies both vertical and horizontal scaling of how the compactor runs as it compacts on a per-tenant basis.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vertical scaling&lt;/strong&gt;&lt;br /&gt;
The setting &lt;code&gt;-compactor.compaction-concurrency&lt;/code&gt; configures the max number of concurrent compactions running in a single compactor instance. Each compaction uses one CPU core.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Horizontal scaling&lt;/strong&gt;&lt;br /&gt;
By default, tenant blocks can be compacted by any Grafana Mimir compactor. When you enable compactor &lt;a href=&#34;../../../../configure/configure-shuffle-sharding/&#34;&gt;shuffle sharding&lt;/a&gt; by setting &lt;code&gt;-compactor.compactor-tenant-shard-size&lt;/code&gt; (or its respective YAML configuration option) to a value higher than &lt;code&gt;0&lt;/code&gt; and lower than the number of available compactors, only the specified number of compactors are eligible to compact blocks for a given tenant.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;compaction-algorithm&#34;&gt;Compaction algorithm&lt;/h2&gt;
&lt;p&gt;Mimir uses a sophisticated compaction algorithm called split-and-merge.&lt;/p&gt;
&lt;p&gt;By design, the split-and-merge algorithm overcomes time series database (TSDB) index limitations, and it avoids situations in which compacted blocks grow indefinitely for a very large tenant at any compaction stage.&lt;/p&gt;
&lt;p&gt;This compaction strategy is a two-stage process: split and merge.
The default configuration disables the split stage.&lt;/p&gt;
&lt;p&gt;To split, the first level of compaction, for example &lt;code&gt;2h&lt;/code&gt;, the compactor divides all source blocks into &lt;em&gt;N&lt;/em&gt; (&lt;code&gt;-compactor.split-groups&lt;/code&gt;) groups. For each group, the compactor compacts the blocks, but instead of producing a single result block, it outputs &lt;em&gt;M&lt;/em&gt; (&lt;code&gt;-compactor.split-and-merge-shards&lt;/code&gt;) blocks, known as &lt;em&gt;split blocks&lt;/em&gt;. Each split block contains only a subset of the series belonging to a given shard out of &lt;em&gt;M&lt;/em&gt; shards. At the end of the split stage, the compactor produces &lt;em&gt;N * M&lt;/em&gt; blocks with a reference to their respective shard in the block’s &lt;code&gt;meta.json&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;The compactor merges the split blocks for each shard. This compacts all &lt;em&gt;N&lt;/em&gt; split blocks of a given shard. The merge reduces the number of blocks from &lt;em&gt;N * M&lt;/em&gt; to &lt;em&gt;M&lt;/em&gt;. For a given compaction time range, there will be a compacted block for each of the &lt;em&gt;M&lt;/em&gt; shards.&lt;/p&gt;
&lt;p&gt;&lt;img
  class=&#34;lazyload d-inline-block&#34;
  data-src=&#34;compactor-split-and-merge.png&#34;
  alt=&#34;Compactor - split-and-merge compaction strategy&#34;/&gt;&lt;/p&gt;
&lt;!-- Diagram source at https://docs.google.com/presentation/d/1bHp8_zcoWCYoNU2AhO2lSagQyuIrghkCncViSqn14cU/edit --&gt;
&lt;p&gt;The merge then runs on other configured compaction time ranges, for example 12h and 24h. It compacts blocks belonging to the same shard.&lt;/p&gt;
&lt;p&gt;This strategy is suitable for clusters with large tenants. The number of shards &lt;em&gt;M&lt;/em&gt; is configurable on a per-tenant basis using &lt;code&gt;-compactor.split-and-merge-shards&lt;/code&gt;, and it can be adjusted based on the number of series of each tenant. The more a tenant grows in terms of series, the more you can grow the configured number of shards. Doing so improves compaction parallelization and keeps each per-shard compacted block size under control. We recommend 1 shard per every 8 million active series in a tenant. For example, for a tenant with 100 million active series, use approximately 12 shards. Use an even number for the count.&lt;/p&gt;
&lt;p&gt;The number of split groups, &lt;em&gt;N&lt;/em&gt;, can also be adjusted per tenant using the &lt;code&gt;-compactor.split-groups&lt;/code&gt; option. Increasing this value produces more compaction jobs with fewer blocks during the split stage. This allows multiple compactors to work on these jobs, and finish the splitting stage faster. However, increasing this value also generates more intermediate blocks during the split stage, which will only be reduced later in the merge stage.&lt;/p&gt;
&lt;p&gt;If the configuration of &lt;code&gt;-compactor.split-and-merge-shards&lt;/code&gt; changes during compaction, the change will affect only the compaction of blocks which have not yet been split. Already split blocks will use the original configuration when merged. The original configuration is stored in the &lt;code&gt;meta.json&lt;/code&gt; of each split block.&lt;/p&gt;
&lt;p&gt;Splitting and merging can be horizontally scaled. Non-conflicting and non-overlapping jobs will be executed in parallel.&lt;/p&gt;
&lt;h2 id=&#34;compactor-sharding&#34;&gt;Compactor sharding&lt;/h2&gt;
&lt;p&gt;The compactor shards compaction jobs, either from a single tenant or multiple tenants. The compaction of a single tenant can be split and processed by multiple compactor instances.&lt;/p&gt;
&lt;p&gt;Whenever the pool of compactors grows or shrinks, tenants and jobs are resharded across the available compactor instances without any manual intervention.&lt;/p&gt;
&lt;p&gt;Compactor sharding uses a &lt;a href=&#34;../../hash-ring/&#34;&gt;hash ring&lt;/a&gt;. At startup, a compactor generates random tokens and registers itself to the compactor hash ring. While running, it periodically scans the storage bucket at every interval defined by &lt;code&gt;-compactor.compaction-interval&lt;/code&gt;, to discover the list of tenants in storage and to compact blocks for each tenant whose hash matches the token ranges assigned to the instance itself within the hash ring.&lt;/p&gt;
&lt;p&gt;To configure the compactors&amp;rsquo; hash ring, refer to &lt;a href=&#34;../../../../configure/configure-hash-rings/&#34;&gt;configuring hash rings&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;waiting-for-a-stable-hash-ring-at-startup&#34;&gt;Waiting for a stable hash ring at startup&lt;/h3&gt;
&lt;p&gt;A cluster cold start or an increase of two or more compactor instances at the same time may result in each new compactor instance starting at a slightly different time. Then, each compactor runs its first compaction based on a different state of the hash ring. This is not an error condition, but it may be inefficient, because multiple compactor instances may start compacting the same tenant at nearly the same time.&lt;/p&gt;
&lt;p&gt;To mitigate the issue, compactors can be configured to wait for a stable hash ring at startup. A ring is considered stable if no instance is added to or removed from the hash ring for at least &lt;code&gt;-compactor.ring.wait-stability-min-duration&lt;/code&gt;. The maximum time the compactor will wait is controlled by the flag &lt;code&gt;-compactor.ring.wait-stability-max-duration&lt;/code&gt; (or the respective YAML configuration option). Once the compactor has finished waiting, either because the ring stabilized or because the maximum wait time was reached, it will start up normally.&lt;/p&gt;
&lt;p&gt;The default value of zero for &lt;code&gt;-compactor.ring.wait-stability-min-duration&lt;/code&gt; disables waiting for ring stability.&lt;/p&gt;
&lt;h2 id=&#34;compaction-jobs-order&#34;&gt;Compaction jobs order&lt;/h2&gt;
&lt;p&gt;The compactor allows configuring of the compaction jobs order via the &lt;code&gt;-compactor.compaction-jobs-order&lt;/code&gt; flag (or its respective YAML config option). The configured ordering defines which compaction jobs should be executed first. The following values of &lt;code&gt;-compactor.compaction-jobs-order&lt;/code&gt; are supported:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;smallest-range-oldest-blocks-first&lt;/code&gt; (default)&lt;/p&gt;
&lt;p&gt;This ordering gives priority to smallest range, oldest blocks first.&lt;/p&gt;
&lt;p&gt;For example, with compaction ranges &lt;code&gt;2h, 12h, 24h&lt;/code&gt;, the compactor will compact the 2h ranges first, and among them give priority to the oldest blocks. Once all blocks in the 2h range have been compacted, it moves to the 12h range, and finally to 24h one.&lt;/p&gt;
&lt;p&gt;All split jobs are moved to the front of the work queue, because finishing all split jobs in a given time range unblocks the merge jobs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;newest-blocks-first&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This ordering gives priority to the most recent time ranges first, regardless of their compaction level.&lt;/p&gt;
&lt;p&gt;For example, with compaction ranges &lt;code&gt;2h, 12h, 24h&lt;/code&gt;, the compactor compacts the most recent blocks first (up to the 24h range), and then moves to older blocks. This policy favours the most recent blocks, assuming they are queried the most frequently.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;blocks-deletion&#34;&gt;Blocks deletion&lt;/h2&gt;
&lt;p&gt;Following a successful compaction, the original blocks are deleted from the storage. Block deletion is not immediate; it follows a two step process:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;An original block is marked for deletion; this is a soft delete&lt;/li&gt;
&lt;li&gt;Once a block has been marked for deletion for longer than the configurable &lt;code&gt;-compactor.deletion-delay&lt;/code&gt;, the block is deleted from storage; this is a hard delete&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The compactor is responsible for both marking blocks and for hard deletion.
Soft deletion is based on a small &lt;code&gt;deletion-mark.json&lt;/code&gt; file stored within the block location in the bucket.&lt;/p&gt;
&lt;p&gt;The soft delete mechanism gives queriers, rulers, and store-gateways time to discover the new compacted blocks before the original blocks are deleted. If those original blocks were immediately hard deleted, some queries involving the compacted blocks could temporarily fail or return partial results.&lt;/p&gt;
&lt;h2 id=&#34;blocks-retention&#34;&gt;Blocks retention&lt;/h2&gt;
&lt;p&gt;The compactor is responsible for enforcing the storage retention, deleting the blocks that contain samples that are older than the configured retention period from the long-term storage.
The storage retention is disabled by default, and no data will be deleted from the long-term storage unless you explicitly configure the retention period.&lt;/p&gt;
&lt;p&gt;For more information, refer to &lt;a href=&#34;../../../../configure/configure-metrics-storage-retention/&#34;&gt;Configure metrics storage retention&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;compactor-scratch-storage-volume&#34;&gt;Compactor scratch storage volume&lt;/h2&gt;
&lt;p&gt;Each compactor uses a storage device mounted at &lt;code&gt;-compactor.data-dir&lt;/code&gt; to temporarily store:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;files downloaded from object storage used as input to compaction&lt;/li&gt;
&lt;li&gt;block files produced by the compactor to be uploaded to object storage&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;While the compactor is a stateless service, it&amp;rsquo;s recommended that you configure the compactor to store its temporary files somewhere other than the root volume. This avoids I/O contention with other workloads running on the system.
Common volume types include a local SSD or a cloud provider&amp;rsquo;s block storage service.&lt;/p&gt;
&lt;p&gt;In Kubernetes, run compactors as a StatefulSet so that each Pod has a dedicated volume.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h2 id=&#34;compactor-disk-utilization&#34;&gt;Compactor disk utilization&lt;/h2&gt;
&lt;p&gt;Large tenants may require a lot of disk space. Assuming &lt;code&gt;max_compaction_range_blocks_size&lt;/code&gt; is the total block size for the largest tenant during the longest &lt;code&gt;-compactor.block-ranges&lt;/code&gt; period, the expression that estimates the minimum disk space required is:&lt;/p&gt;

&lt;div class=&#34;code-snippet code-snippet__mini&#34;&gt;&lt;div class=&#34;lang-toolbar__mini&#34;&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet code-snippet__border&#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-none&#34;&gt;compactor.compaction-concurrency * max_compaction_range_blocks_size * 2&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Alternatively, assuming the largest &lt;code&gt;-compactor.block-ranges&lt;/code&gt; is &lt;code&gt;24h&lt;/code&gt; (the default), you could estimate needing 150GB of disk space for every 10M active series owned by the largest tenant. For example, if your largest tenant has 30M active series and &lt;code&gt;-compactor.compaction-concurrency=1&lt;/code&gt;, we would recommend having a disk with at least 450GB available.&lt;/p&gt;
&lt;h2 id=&#34;compactor-configuration&#34;&gt;Compactor configuration&lt;/h2&gt;
&lt;p&gt;Refer to the &lt;a href=&#34;../../../../configure/configuration-parameters/#compactor&#34;&gt;compactor&lt;/a&gt;
block section and the &lt;a href=&#34;../../../../configure/configuration-parameters/#limits&#34;&gt;limits&lt;/a&gt; block section for details of compaction-related configuration.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;../alertmanager/&#34;&gt;alertmanager&lt;/a&gt; and &lt;a href=&#34;../ruler/&#34;&gt;ruler&lt;/a&gt; components can also use object storage to store their configurations and rules uploaded by users. In that case a separate bucket should be created to store alertmanager configurations and rules: using the same bucket between ruler/alertmanager and blocks will cause issues with the compactor.&lt;/p&gt;
]]></content><description>&lt;h1 id="grafana-mimir-compactor">Grafana Mimir compactor&lt;/h1>
&lt;p>The compactor increases query performance and reduces long-term storage usage by combining blocks.&lt;/p>
&lt;p>The compactor is the component responsible for:&lt;/p>
&lt;ul>
&lt;li>Compacting multiple blocks of a given tenant into a single, optimized larger block. This deduplicates chunks and reduces the size of the index, resulting in reduced storage costs. Querying fewer blocks is faster, so it also increases query speed.&lt;/li>
&lt;li>Keeping the per-tenant bucket index updated. The &lt;a href="../../bucket-index/">bucket index&lt;/a> is used by &lt;a href="../querier/">queriers&lt;/a>, &lt;a href="../store-gateway/">store-gateways&lt;/a>, and &lt;a href="../ruler/">rulers&lt;/a> to discover both new blocks and deleted blocks in the storage.&lt;/li>
&lt;li>Deleting blocks that are no longer within a configurable retention period.&lt;/li>
&lt;/ul>
&lt;p>The compactor is stateless.&lt;/p></description></item><item><title>Grafana Mimir distributor</title><link>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/distributor/</link><pubDate>Wed, 03 Jun 2026 09:01:40 +0200</pubDate><guid>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/distributor/</guid><content><![CDATA[&lt;h1 id=&#34;grafana-mimir-distributor&#34;&gt;Grafana Mimir distributor&lt;/h1&gt;
&lt;p&gt;The distributor is a stateless component that acts as the entry point for the Grafana Mimir write path.
It receives incoming write requests containing time series data, validates the data for correctness, enforces tenant-specific limits, and then ingests the data into Mimir.&lt;/p&gt;
&lt;p&gt;To scale beyond the limits of a single node, distributors shard incoming series across a pool of partitions or ingesters.
The details of how sharding, replication, and ingestion work differ between the ingest storage and classic architectures.
For more information, refer to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/mimir/v3.1.x/references/architecture/hash-ring/#series-sharding-in-ingest-storage-architecture&#34;&gt;Series sharding in ingest storage architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/mimir/v3.1.x/references/architecture/hash-ring/#series-sharding-in-classic-architecture&#34;&gt;Series sharding in classic architecture&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;supported-protocols&#34;&gt;Supported protocols&lt;/h2&gt;
&lt;p&gt;The distributor supports the following metrics ingestion protocols:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prometheus remote write v1&lt;/li&gt;
&lt;li&gt;Prometheus remote write v2&lt;/li&gt;
&lt;li&gt;OpenTelemetry Protocol (OTLP)&lt;/li&gt;
&lt;li&gt;Influx&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;validation&#34;&gt;Validation&lt;/h2&gt;
&lt;p&gt;The distributor cleans and validates incoming data before ingesting it into Mimir.&lt;/p&gt;
&lt;p&gt;A single request can include both valid and invalid metrics, samples, metadata, or exemplars.
The distributor ingests only the valid data and rejects any invalid entries.&lt;/p&gt;
&lt;p&gt;If invalid data is detected:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When using Prometheus remote write or Influx, the distributor returns an HTTP 400 status code.&lt;/li&gt;
&lt;li&gt;When using OTLP, it returns an HTTP 200 status code, following the OTLP specification for partial ingestion.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In both cases, the response body contains details about the first invalid item encountered.
The returned error is typically logged by the agent sending metrics to Mimir, such as Prometheus, Grafana Alloy, or the OpenTelemetry Collector.&lt;/p&gt;
&lt;p&gt;The distributor data cleanup includes the following transformation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The metric metadata &lt;code&gt;help&lt;/code&gt; is truncated to fit in the length defined via the &lt;code&gt;-validation.max-metadata-length&lt;/code&gt; flag.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The distributor validation includes the following checks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The metric metadata and labels conform to the &lt;a href=&#34;https://prometheus.io/docs/concepts/data_model/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Prometheus exposition format&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The metric metadata (&lt;code&gt;name&lt;/code&gt; and &lt;code&gt;unit&lt;/code&gt;) are not longer than what is defined via the &lt;code&gt;-validation.max-metadata-length&lt;/code&gt; flag.&lt;/li&gt;
&lt;li&gt;The number of labels of each metric is not higher than &lt;code&gt;-validation.max-label-names-per-series&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Each metric label name is not longer than &lt;code&gt;-validation.max-length-label-name&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Each metric label value is not longer than &lt;code&gt;-validation.max-length-label-value&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Each sample timestamp is not newer than &lt;code&gt;-validation.create-grace-period&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Each exemplar has a timestamp and at least one non-empty label name and value pair.&lt;/li&gt;
&lt;li&gt;Each exemplar has no more than 128 labels.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;For each tenant, you can override the validation checks by modifying the overrides section of the 
    &lt;a href=&#34;/docs/mimir/v3.1.x/configure/about-runtime-configuration/&#34;&gt;runtime configuration&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h2 id=&#34;rate-limiting&#34;&gt;Rate limiting&lt;/h2&gt;
&lt;p&gt;The distributor includes two different types of rate limiters that apply to each tenant.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Request rate&lt;/strong&gt;&lt;br /&gt;
The maximum number of requests per second that can be served across Grafana Mimir cluster for each tenant.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ingestion rate&lt;/strong&gt;&lt;br /&gt;
The maximum samples per second that can be ingested across Grafana Mimir cluster for each tenant.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If any of these rates is exceeded, the distributor drops the request and returns an HTTP 429 response code.&lt;/p&gt;
&lt;p&gt;Internally, these limits are implemented using a per-distributor local rate limiter.
The local rate limiter for each distributor is configured with a limit of &lt;code&gt;limit / N&lt;/code&gt;, where &lt;code&gt;N&lt;/code&gt; is the number of healthy distributor replicas.
The distributor automatically adjusts the request and ingestion rate limits if the number of distributor replicas change.&lt;/p&gt;
&lt;p&gt;This design uses a per-distributor local rate limiter and requires that write requests be &lt;a href=&#34;#load-balancing-across-distributors&#34;&gt;evenly distributed across the pool of distributors&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;configure-rate-limits&#34;&gt;Configure rate limits&lt;/h3&gt;
&lt;p&gt;Use the following flags to configure the rate limits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-distributor.request-rate-limit&lt;/code&gt;: Request rate limit, which is per tenant, and which is in requests per second&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-distributor.request-burst-size&lt;/code&gt;: Request burst size (in number of requests) allowed, which is per tenant&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-distributor.ingestion-rate-limit&lt;/code&gt;: Ingestion rate limit, which is per tenant, and which is in samples per second&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-distributor.ingestion-burst-size&lt;/code&gt;: Ingestion burst size (in number of samples) allowed, which is per tenant&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;You can override rate limiting on a per-tenant basis by setting &lt;code&gt;request_rate&lt;/code&gt;, &lt;code&gt;ingestion_rate&lt;/code&gt;, &lt;code&gt;request_burst_size&lt;/code&gt; and &lt;code&gt;ingestion_burst_size&lt;/code&gt; in the overrides section of the runtime configuration.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;



&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;By default, Prometheus remote write doesn&amp;rsquo;t retry requests on 429 HTTP response status code. To modify this behavior, use &lt;code&gt;retry_on_http_429: true&lt;/code&gt; in the Prometheus &lt;a href=&#34;https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;remote_write&lt;/code&gt; configuration&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h3 id=&#34;distributor-ring-and-rate-limiting&#34;&gt;Distributor ring and rate limiting&lt;/h3&gt;
&lt;p&gt;Since distributor rate limits are implemented locally, each distributor must know how many healthy distributors are running in the Mimir cluster.
To achieve this, each distributor joins a hash ring used for service discovery, which tracks the number of healthy distributor instances.&lt;/p&gt;
&lt;p&gt;By default, the distributors’ ring uses &lt;code&gt;memberlist&lt;/code&gt; as its backend.
If you want to configure a different backend, for example, &lt;code&gt;consul&lt;/code&gt; or &lt;code&gt;etcd&lt;/code&gt;, you can use the following CLI flags (and their respective YAML configuration options) to configure the distributors ring KV store:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-distributor.ring.store&lt;/code&gt;: The backend storage to use.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-distributor.ring.consul.*&lt;/code&gt;: The Consul client configuration. Set this flag only if &lt;code&gt;consul&lt;/code&gt; is the configured backend storage.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-distributor.ring.etcd.*&lt;/code&gt;: The etcd client configuration. Set this flag only if &lt;code&gt;etcd&lt;/code&gt; is the configured backend storage.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For more information, refer to 
    &lt;a href=&#34;/docs/mimir/v3.1.x/configure/configure-hash-rings/&#34;&gt;Configure hash rings&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;load-balancing-across-distributors&#34;&gt;Load balancing across distributors&lt;/h2&gt;
&lt;p&gt;As a best practice, uniformly distribute write requests across all distributor instances by placing a load balancer in front of them.
The preferred approach is a Layer 7 load balancer, which balances individual HTTP requests across distributors.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;If you run Grafana Mimir in a Kubernetes cluster and use a Kubernetes &lt;a href=&#34;https://kubernetes.io/docs/concepts/services-networking/service/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Service&lt;/a&gt; as the ingress for distributors, a Kubernetes Service balances TCP connections across endpoints but doesn&amp;rsquo;t balance HTTP requests within a single TCP connection.&lt;/p&gt;
&lt;p&gt;If you enable HTTP persistent connections, also known as HTTP keep-alive, Prometheus reuses the same TCP connection for each remote-write HTTP request of a remote-write shard.
This can cause distributors to receive an uneven distribution of remote-write HTTP requests.&lt;/p&gt;
&lt;p&gt;To improve the balancing of requests between distributors, consider increasing &lt;code&gt;min_shards&lt;/code&gt; in the Prometheus &lt;a href=&#34;https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;code&gt;remote_write&lt;/code&gt; configuration&lt;/a&gt; block.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h2 id=&#34;high-availability-tracker&#34;&gt;High-availability tracker&lt;/h2&gt;
&lt;p&gt;You can configure remote write agents, such as Prometheus or Grafana Alloy, in pairs, which means that metrics continue to be scraped and written to Grafana Mimir even when one of the remote write agents is down for maintenance or is unavailable due to a failure.
We refer to this configuration as high-availability (HA) pairs.&lt;/p&gt;
&lt;p&gt;The distributor includes an HA tracker.
When the HA tracker is enabled, the distributor deduplicates incoming series from Prometheus HA pairs.
This enables you to have multiple Prometheus HA replicas of the same server writing identical series to Mimir, which the distributor then deduplicates.&lt;/p&gt;
&lt;p&gt;For more information about HA deduplication and how to configure it, refer to 
    &lt;a href=&#34;/docs/mimir/v3.1.x/configure/configure-high-availability-deduplication/&#34;&gt;Configure high-availability deduplication&lt;/a&gt;.&lt;/p&gt;
]]></content><description>&lt;h1 id="grafana-mimir-distributor">Grafana Mimir distributor&lt;/h1>
&lt;p>The distributor is a stateless component that acts as the entry point for the Grafana Mimir write path.
It receives incoming write requests containing time series data, validates the data for correctness, enforces tenant-specific limits, and then ingests the data into Mimir.&lt;/p></description></item><item><title>Grafana Mimir ingester</title><link>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/ingester/</link><pubDate>Wed, 03 Jun 2026 09:01:40 +0200</pubDate><guid>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/ingester/</guid><content><![CDATA[&lt;h1 id=&#34;grafana-mimir-ingester&#34;&gt;Grafana Mimir ingester&lt;/h1&gt;
&lt;p&gt;The ingester is a stateful component that processes the most recently ingested samples and makes them available for querying.

    &lt;a href=&#34;/docs/mimir/v3.1.x/references/architecture/components/querier/&#34;&gt;Queriers&lt;/a&gt; read recent data from ingesters and older data from long-term object storage via 
    &lt;a href=&#34;/docs/mimir/v3.1.x/references/architecture/components/store-gateway/&#34;&gt;store-gateways&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The ingester stores data both in memory and on disk for a configurable retention period.
In-memory series are periodically compacted into an on-disk format called a TSDB block and then uploaded to object storage. This process happens every two hours by default.
When the local retention period expires and the data has been compacted and successfully uploaded, the ingester removes the local copy.&lt;/p&gt;
&lt;p&gt;At that point, queriers retrieve the data from object storage through the store-gateways.&lt;/p&gt;
&lt;p&gt;To recover its in-memory state after a crash or restart, the ingester maintains both a &lt;a href=&#34;#write-ahead-log&#34;&gt;write-ahead log&lt;/a&gt; (WAL) and a &lt;a href=&#34;#write-behind-log&#34;&gt;write-behind log&lt;/a&gt; (WBL).
The WBL is used only when out-of-order sample ingestion is enabled.&lt;/p&gt;
&lt;h2 id=&#34;series-ingestion-and-querying&#34;&gt;Series ingestion and querying&lt;/h2&gt;
&lt;p&gt;How ingesters receive series and how queriers read from them differs between the ingest storage and classic architectures.&lt;/p&gt;
&lt;h3 id=&#34;series-ingestion-and-querying-in-ingest-storage-architecture&#34;&gt;Series ingestion and querying in ingest storage architecture&lt;/h3&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;This guidance applies to ingest storage architecture. For more information about the supported architectures in Grafana Mimir, refer to 
    &lt;a href=&#34;/docs/mimir/v3.1.x/get-started/about-grafana-mimir-architecture/&#34;&gt;Grafana Mimir architecture&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;In ingest storage architecture, distributors shard incoming series across Kafka partitions, writing each series to a single partition.
A write request is considered successful once all series in the request are committed to Kafka.&lt;/p&gt;
&lt;p&gt;Ingesters are not involved in the write path, so their availability does not impact writes.
Effectively, ingesters act as pure read-path components.&lt;/p&gt;
&lt;p&gt;Each ingester owns a single Kafka partition and continuously consumes series data from that partition, making it available for querying.
As a result, data from a completed write request is not immediately queryable, but becomes available shortly afterward once the ingester has processed it.
In steady state, this latency is typically below one second.&lt;/p&gt;
&lt;p&gt;Kafka ensures high availability and durability for the most recent data.
When an ingester restarts or crashes, it quickly catches up with the backlog of series written to Kafka during its downtime.
This ensures that ingesters have gap-free series data once they are caught up.&lt;/p&gt;
&lt;p&gt;This behavior is key because it allows a read quorum of one per partition. Queriers reading the most recent data from ingesters need to query only a single ingester for the relevant partition to guarantee consistency.
Even if two random ingesters are unavailable, the read path remains healthy as long as there is at least one healthy ingester for each partition.&lt;/p&gt;
&lt;p&gt;An ingester owns exactly one Kafka partition, but a partition can be assigned to multiple ingesters for high availability. As a best practice, assign two ingesters per partition. This corresponds to a replication factor of two.&lt;/p&gt;
&lt;p&gt;For more information about sharding, refer to 
    &lt;a href=&#34;/docs/mimir/v3.1.x/references/architecture/hash-ring/#series-sharding-in-ingest-storage-architecture&#34;&gt;Series sharding in ingest storage architecture&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;series-ingestion-and-querying-in-classic-architecture&#34;&gt;Series ingestion and querying in classic architecture&lt;/h3&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;This guidance applies to classic architecture. For more information about the supported architectures in Grafana Mimir, refer to 
    &lt;a href=&#34;/docs/mimir/v3.1.x/get-started/about-grafana-mimir-architecture/&#34;&gt;Grafana Mimir architecture&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;In classic architecture, distributors shard and replicate incoming series across ingesters, writing each series to &lt;code&gt;RF&lt;/code&gt; different ingesters, where &lt;code&gt;RF&lt;/code&gt; is the replication factor, three, by default.
A write request is considered successful once all series are written to a quorum of ingesters, calculated based on the configured &lt;code&gt;RF&lt;/code&gt;.
For example, with an &lt;code&gt;RF&lt;/code&gt; of three, a write request succeeds if each series is successfully written to at least two ingesters.&lt;/p&gt;
&lt;p&gt;In this architecture, ingesters are involved in both the write and read paths.
If two or more ingesters become unavailable, the write and read quorum may be lost, potentially causing a full outage.&lt;/p&gt;
&lt;p&gt;When an ingester restarts or crashes, it cannot catch up with series that were written to its shard during downtime.
This can result in gaps in the ingester’s data.
Consequently, queriers also require a read quorum to guarantee consistency.
A query succeeds if each series can be read from at least a quorum of ingesters that own that series.
For example, with an &lt;code&gt;RF&lt;/code&gt; of three, a read request succeeds if each series is successfully read from at least two ingesters.&lt;/p&gt;
&lt;p&gt;For more information about sharding, refer to 
    &lt;a href=&#34;/docs/mimir/v3.1.x/references/architecture/hash-ring/#series-sharding-in-classic-architecture&#34;&gt;Series sharding in classic architecture&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;differences-in-read-path-availability-between-ingest-storage-and-classic-architecture&#34;&gt;Differences in read path availability between ingest storage and classic architecture&lt;/h3&gt;
&lt;p&gt;Because the read quorum behavior differs between the two architectures, ingest storage architecture is significantly more resilient to ingester failures.&lt;/p&gt;
&lt;p&gt;The following chart models the probability of a read-path outage given a variable number of random unhealthy ingesters.
We assumed 100 ingesters per zone, with three zones for the classic architecture (&lt;code&gt;RF&lt;/code&gt; = 3) and two zones for the ingest storage architecture (&lt;code&gt;RF&lt;/code&gt; = 2).&lt;/p&gt;
&lt;p&gt;Even with a lower replication factor, and therefore, fewer ingesters, ingest storage architecture is more resilient to random failures:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In classic architecture, an outage occurs as soon as two ingesters in two different zones are unhealthy.&lt;/li&gt;
&lt;li&gt;In the ingest storage architecture, an outage only occurs if two ingesters owning the same partition are simultaneously unhealthy.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img
  class=&#34;lazyload d-inline-block&#34;
  data-src=&#34;read-path-outage-probability.png&#34;
  alt=&#34;Read path outage probability&#34;/&gt;&lt;/p&gt;
&lt;h3 id=&#34;zone-aware-replication&#34;&gt;Zone-aware replication&lt;/h3&gt;
&lt;p&gt;Zone-aware replication ensures that the ingester replicas for a given time series are distributed across different zones. Zones can represent logical or physical failure domains, for example, different availability zones in the cloud. Dividing replicas across multiple zones helps prevent data loss and service interruptions during a zone-wide outage.&lt;/p&gt;
&lt;p&gt;To set up multi-zone replication, refer to 
    &lt;a href=&#34;/docs/mimir/v3.1.x/configure/configure-zone-aware-replication/&#34;&gt;Configure Grafana Mimir zone-aware replication&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;shuffle-sharding&#34;&gt;Shuffle sharding&lt;/h3&gt;
&lt;p&gt;Shuffle sharding is a technique used by Grafana Mimir to minimize the impact tenants have on each other.
It works by isolating each tenant’s data across different partitions or ingesters, reducing overlap between tenants.&lt;/p&gt;
&lt;p&gt;For more information on shuffle sharding, refer to 
    &lt;a href=&#34;/docs/mimir/v3.1.x/configure/configure-shuffle-sharding/&#34;&gt;Configuring shuffle sharding&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;ingesters-hash-ring&#34;&gt;Ingesters hash ring&lt;/h2&gt;
&lt;p&gt;Ingesters join a dedicated 
    &lt;a href=&#34;/docs/mimir/v3.1.x/references/architecture/hash-ring/&#34;&gt;hash ring&lt;/a&gt;.
In classic architecture, the ring is used for sharding and service discovery.
In ingest storage architecture, it’s used for service discovery only.&lt;/p&gt;
&lt;p&gt;Regardless of the architecture, each ingester in the ring has a state that changes throughout its lifecycle:&lt;/p&gt;
&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
  &lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;State&lt;/th&gt;
              &lt;th&gt;Description&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;PENDING&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;The ingester has started but its bootstrap phase hasn’t begun. In this state, it does not ingest series or serve read requests.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;JOINING&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;The ingester is bootstrapping and preparing to serve read requests. In classic architecture, it replays the WAL and WBL. In ingest storage architecture, it replays the WAL and WBL, then catches up with the backlog of series accumulated in its Kafka partition since the previous shutdown.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;ACTIVE&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;The ingester is fully operational. It ingests series and serves read requests.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;LEAVING&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;The ingester is shutting down. It stops ingesting series and serving read requests.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;UNHEALTHY&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;A meta state derived from heartbeat monitoring. An ingester is considered &lt;code&gt;UNHEALTHY&lt;/code&gt; if it fails to update its heartbeat timestamp within a configurable timeout. Other components avoid contacting ingesters in this state. In particular, queriers skip &lt;code&gt;UNHEALTHY&lt;/code&gt; ingesters when reading. In classic architecture, distributors avoid writing to them.&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;
&lt;/div&gt;
&lt;p&gt;To configure the ingesters hash ring, refer to 
    &lt;a href=&#34;/docs/mimir/v3.1.x/configure/configure-hash-rings/&#34;&gt;Configure Grafana Mimir hash rings&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;read-only-mode&#34;&gt;Read-only mode&lt;/h3&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;This feature is used exclusively in classic architecture. For more information about the supported architectures in Grafana Mimir, refer to 
    &lt;a href=&#34;/docs/mimir/v3.1.x/get-started/about-grafana-mimir-architecture/&#34;&gt;Grafana Mimir architecture&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;Ingesters have an additional property in the ring called &amp;ldquo;read-only&amp;rdquo; mode.
This information is stored separately from the ingester’s instance state, so an ingester can be in any supported state, for example, &lt;code&gt;ACTIVE&lt;/code&gt; or &lt;code&gt;LEAVING&lt;/code&gt;, while also being in read-only mode.&lt;/p&gt;
&lt;p&gt;When an ingester is in read-only mode, it stops receiving write requests from distributors but continues to serve read requests.
In the write path, read-only ingesters are excluded from the shard computation used for distributing tenant writes.&lt;/p&gt;
&lt;p&gt;Read-only mode is particularly useful during downscaling or as preparation for an ingester’s shutdown.
Ingesters can be placed in read-only mode using the 
    &lt;a href=&#34;/docs/mimir/v3.1.x/references/http-api/#prepare-instance-ring-downscale&#34;&gt;Prepare instance ring downscale&lt;/a&gt; API endpoint.&lt;/p&gt;
&lt;h2 id=&#34;write-ahead-and-write-behind-logs&#34;&gt;Write-ahead and write-behind logs&lt;/h2&gt;
&lt;p&gt;The ingester uses a write-ahead log (WAL) and a write-behind log (WBL) to recover its in-memory state after a restart or crash.
These logs protect against data loss caused by process restarts or failures but do not protect against disk failures.
They also do not improve availability. Replication is still required for high availability.&lt;/p&gt;
&lt;h3 id=&#34;write-ahead-log&#34;&gt;Write-ahead log&lt;/h3&gt;
&lt;p&gt;The write-ahead log (WAL) records all incoming series to persistent disk until those series are uploaded to long-term storage.
If an ingester fails, it replays the WAL on restart to restore the in-memory series and samples.&lt;/p&gt;
&lt;h3 id=&#34;write-behind-log&#34;&gt;Write-behind log&lt;/h3&gt;
&lt;p&gt;The write-behind log (WBL) functions similarly to the WAL but records only out-of-order samples to persistent storage until they are uploaded to long-term storage.
The WBL is used only when out-of-order ingestion is enabled via the CLI flag &lt;code&gt;-ingester.out-of-order-time-window&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Grafana Mimir uses a separate log for out-of-order samples because the WAL is optimized for in-order appends.
When an ingester receives a sample, it first tries to append it to in-memory data structures.
If the sample is out-of-order and out-of-order ingestion is enabled, the ingester still appends it in memory and writes it to the dedicated write-behind log.&lt;/p&gt;
&lt;p&gt;For more information about out-of-order samples ingestion, refer to 
    &lt;a href=&#34;/docs/mimir/v3.1.x/configure/configure-out-of-order-samples-ingestion/&#34;&gt;Configure out of order samples ingestion&lt;/a&gt;.&lt;/p&gt;
]]></content><description>&lt;h1 id="grafana-mimir-ingester">Grafana Mimir ingester&lt;/h1>
&lt;p>The ingester is a stateful component that processes the most recently ingested samples and makes them available for querying.
&lt;a href="/docs/mimir/v3.1.x/references/architecture/components/querier/">Queriers&lt;/a> read recent data from ingesters and older data from long-term object storage via
&lt;a href="/docs/mimir/v3.1.x/references/architecture/components/store-gateway/">store-gateways&lt;/a>.&lt;/p></description></item><item><title>Grafana Mimir querier</title><link>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/querier/</link><pubDate>Wed, 03 Jun 2026 09:01:40 +0200</pubDate><guid>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/querier/</guid><content><![CDATA[&lt;h1 id=&#34;grafana-mimir-querier&#34;&gt;Grafana Mimir querier&lt;/h1&gt;
&lt;p&gt;The querier is a stateless component that evaluates &lt;a href=&#34;https://prometheus.io/docs/prometheus/latest/querying/basics/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;PromQL&lt;/a&gt;
expressions by fetching time series and labels on the read path.&lt;/p&gt;
&lt;p&gt;The querier uses the &lt;a href=&#34;../store-gateway/&#34;&gt;store-gateway&lt;/a&gt; component to query the &lt;a href=&#34;../../../../get-started/about-grafana-mimir-architecture/#long-term-storage&#34;&gt;long-term storage&lt;/a&gt; and the &lt;a href=&#34;../ingester/&#34;&gt;ingester&lt;/a&gt; component to query recently written data.&lt;/p&gt;
&lt;h2 id=&#34;how-it-works&#34;&gt;How it works&lt;/h2&gt;
&lt;p&gt;To find the correct blocks to look up at query time, queriers lazily download the bucket index when they receive the first query for a given tenant. The querier caches the bucket index in memory and periodically keeps it up-to-date.&lt;/p&gt;
&lt;p&gt;The bucket index contains a list of blocks and block deletion marks of a tenant. The querier later uses the list of blocks and block deletion marks to locate the set of blocks that need to be queried for the given query.&lt;/p&gt;
&lt;h3 id=&#34;anatomy-of-a-query-request&#34;&gt;Anatomy of a query request&lt;/h3&gt;
&lt;p&gt;When a querier receives a query range request, the request contains the following parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;query&lt;/code&gt;: the PromQL query expression (for example, &lt;code&gt;rate(node_cpu_seconds_total[1m])&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;start&lt;/code&gt;: the start time&lt;/li&gt;
&lt;li&gt;&lt;code&gt;end&lt;/code&gt;: the end time&lt;/li&gt;
&lt;li&gt;&lt;code&gt;step&lt;/code&gt;: the query resolution (for example, &lt;code&gt;30&lt;/code&gt; yields one data point every 30 seconds)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For each query, the querier analyzes the &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt; time range to compute a list of all known blocks containing at least one sample within the time range.
For each list of blocks per query, the querier computes a list of store-gateway instances holding the blocks. The querier sends a request to each matching store-gateway instance to fetch all samples for the series matching the &lt;code&gt;query&lt;/code&gt; within the &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt; time range.&lt;/p&gt;
&lt;p&gt;The request sent to each store-gateway contains the list of block IDs that are expected to be queried, and the response sent back by the store-gateway to the querier contains the list of block IDs that were queried.
This list of block IDs might be a subset of the requested blocks, for example, when a recent blocks-resharding event occurs within the last few seconds.&lt;/p&gt;
&lt;p&gt;The querier runs a consistency check on responses received from the store-gateways to ensure all expected blocks have been queried.
If the expected blocks have not been queried, the querier retries fetching samples from missing blocks from different store-gateways up to &lt;code&gt;-store-gateway.sharding-ring.replication-factor&lt;/code&gt; (defaults to 3) times or maximum 3 times, whichever is lower.&lt;/p&gt;
&lt;p&gt;If the consistency check fails after all retry attempts, the query execution fails.
Query failure due to the querier not querying all blocks ensures the correctness of query results.&lt;/p&gt;
&lt;p&gt;If the query time range overlaps with the &lt;code&gt;-querier.query-ingesters-within&lt;/code&gt; duration, the querier also sends the request to ingesters.
The request to the ingesters fetches samples that have not yet been uploaded to the long-term storage or are not yet available for querying through the store-gateway.&lt;/p&gt;
&lt;p&gt;The configured period for &lt;code&gt;-querier.query-ingesters-within&lt;/code&gt; should be greater than both:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-querier.query-store-after&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;the estimated minimum amount of time for the oldest samples stored in a block uploaded by ingester to be discovered and available for querying.
When running Grafana Mimir with the default configuration, the estimated minimum amount of time for the oldest sample in an uploaded block to be available for querying is &lt;code&gt;3h&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After all samples have been fetched from both the store-gateways and the ingesters, the querier runs the PromQL engine to execute the query and sends back the result to the client.&lt;/p&gt;
&lt;h3 id=&#34;connecting-to-store-gateways&#34;&gt;Connecting to store-gateways&lt;/h3&gt;
&lt;p&gt;You must configure the queriers with the same &lt;code&gt;-store-gateway.sharding-ring.*&lt;/code&gt; flags (or their respective YAML configuration parameters) that you use to configure the store-gateways so that the querier can access the store-gateway hash ring and discover the addresses of the store-gateways.&lt;/p&gt;
&lt;h3 id=&#34;connecting-to-ingesters&#34;&gt;Connecting to ingesters&lt;/h3&gt;
&lt;p&gt;You must configure the querier with the same &lt;code&gt;-ingester.ring.*&lt;/code&gt; flags (or their respective YAML configuration parameters) that you use to configure the ingesters so that the querier can access the ingester hash ring and discover the addresses of the ingesters.&lt;/p&gt;
&lt;h2 id=&#34;caching&#34;&gt;Caching&lt;/h2&gt;
&lt;p&gt;The querier supports the following cache:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#metadata-cache&#34;&gt;Metadata cache&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Caching is optional, but highly recommended in a production environment.&lt;/p&gt;
&lt;h3 id=&#34;metadata-cache&#34;&gt;Metadata cache&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;../store-gateway/&#34;&gt;Store-gateways&lt;/a&gt; and queriers can use Memcached to cache the following bucket metadata:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;List of tenants&lt;/li&gt;
&lt;li&gt;List of blocks per tenant&lt;/li&gt;
&lt;li&gt;Block &lt;code&gt;meta.json&lt;/code&gt; existence and content&lt;/li&gt;
&lt;li&gt;Block &lt;code&gt;deletion-mark.json&lt;/code&gt; existence and content&lt;/li&gt;
&lt;li&gt;Tenant &lt;code&gt;bucket-index.json.gz&lt;/code&gt; content&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using the metadata cache reduces the number of API calls to long-term storage and stops the number of the API calls that scale linearly with the number of querier and store-gateway replicas.&lt;/p&gt;
&lt;p&gt;To enable the metadata cache, set &lt;code&gt;-blocks-storage.bucket-store.metadata-cache.backend&lt;/code&gt;.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;Currently, Mimir supports caching with the &lt;code&gt;memcached&lt;/code&gt; backend.&lt;/p&gt;
&lt;p&gt;The Memcached client includes additional configuration available via flags that begin with the prefix &lt;code&gt;-blocks-storage.bucket-store.metadata-cache.memcached.*&lt;/code&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;Additional flags for configuring the metadata cache begin with the prefix &lt;code&gt;-blocks-storage.bucket-store.metadata-cache.*&lt;/code&gt;. By configuring the TTL to zero or a negative value, caching of given item type is disabled.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;You should use the same Memcached backend cluster for both the store-gateways and queriers.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h2 id=&#34;querier-configuration&#34;&gt;Querier configuration&lt;/h2&gt;
&lt;p&gt;For details about querier configuration, refer to &lt;a href=&#34;../../../../configure/configuration-parameters/#querier&#34;&gt;querier&lt;/a&gt;.&lt;/p&gt;
]]></content><description>&lt;h1 id="grafana-mimir-querier">Grafana Mimir querier&lt;/h1>
&lt;p>The querier is a stateless component that evaluates &lt;a href="https://prometheus.io/docs/prometheus/latest/querying/basics/" target="_blank" rel="noopener noreferrer">PromQL&lt;/a>
expressions by fetching time series and labels on the read path.&lt;/p>
&lt;p>The querier uses the &lt;a href="../store-gateway/">store-gateway&lt;/a> component to query the &lt;a href="../../../../get-started/about-grafana-mimir-architecture/#long-term-storage">long-term storage&lt;/a> and the &lt;a href="../ingester/">ingester&lt;/a> component to query recently written data.&lt;/p></description></item><item><title>Grafana Mimir query-frontend</title><link>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/query-frontend/</link><pubDate>Wed, 03 Jun 2026 09:01:40 +0200</pubDate><guid>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/query-frontend/</guid><content><![CDATA[&lt;h1 id=&#34;grafana-mimir-query-frontend&#34;&gt;Grafana Mimir query-frontend&lt;/h1&gt;
&lt;p&gt;The query-frontend is a stateless component that provides a &lt;a href=&#34;https://prometheus.io/docs/prometheus/latest/querying/api/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Prometheus compatible API&lt;/a&gt; with a number of features to accelerate the read path.
The query-frontend is the primary entry point for the read path of Mimir.
The query-scheduler and queriers are required within the cluster to execute the queries.&lt;/p&gt;
&lt;p&gt;We recommend that you run at least two query-frontend replicas for high-availability reasons.&lt;/p&gt;
&lt;p&gt;&lt;img
  class=&#34;lazyload d-inline-block&#34;
  data-src=&#34;../query-scheduler/query-scheduler-architecture.png&#34;
  alt=&#34;Query-frontend architecture&#34;/&gt;&lt;/p&gt;
&lt;p&gt;The following flow describes how a query moves through a Grafana Mimir cluster:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The query-frontend receives queries, and then either splits and shards them, or serves them from the cache.&lt;/li&gt;
&lt;li&gt;The query-frontend enqueues the queries into a &lt;a href=&#34;../query-scheduler/&#34;&gt;query-scheduler&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The query-scheduler stores the queries in an in-memory queue where they wait for a querier to pick them up.&lt;/li&gt;
&lt;li&gt;Queriers pick up the queries, and executes them.&lt;/li&gt;
&lt;li&gt;The querier sends results back to query-frontend, which then forwards the results to the client.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;functions&#34;&gt;Functions&lt;/h2&gt;
&lt;p&gt;This section describes the functions of the query-frontend.&lt;/p&gt;
&lt;h3 id=&#34;splitting&#34;&gt;Splitting&lt;/h3&gt;
&lt;p&gt;The query-frontend can split long-range queries into multiple queries.
By default, the split interval is 24 hours.
The query-frontend executes these queries in parallel in downstream queriers and combines the results together.
Splitting prevents large multi-day or multi-month queries from causing out-of-memory errors in a querier and accelerates query execution.&lt;/p&gt;
&lt;h3 id=&#34;caching&#34;&gt;Caching&lt;/h3&gt;
&lt;p&gt;The query-frontend caches query results and reuses them on subsequent queries.
If the cached results are incomplete, the query-frontend calculates the required partial queries and executes them in parallel on downstream queriers.
The query-frontend can optionally align queries with their step parameter to improve the cacheability of the query results.
The result cache is backed by Memcached.&lt;/p&gt;
&lt;p&gt;Although aligning the step parameter to the query time range increases the performance of Grafana Mimir, it violates the &lt;a href=&#34;https://prometheus.io/blog/2021/05/03/introducing-prometheus-conformance-program/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;PromQL conformance&lt;/a&gt; of Grafana Mimir. If PromQL conformance is not a priority to you, you can enable step alignment by setting &lt;code&gt;-query-frontend.align-queries-with-step=true&lt;/code&gt; or the equivalent per-tenant setting &lt;code&gt;align_queries_with_step&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;about-query-sharding&#34;&gt;About query sharding&lt;/h3&gt;
&lt;p&gt;The query-frontend also provides &lt;a href=&#34;../../query-sharding/&#34;&gt;query sharding&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;dns-configuration-and-readiness&#34;&gt;DNS configuration and readiness&lt;/h2&gt;
&lt;p&gt;When a query-frontend starts up, it is not immediately able to serve queries.
The &lt;a href=&#34;../../../http-api/#readiness-probe&#34;&gt;&lt;code&gt;/ready&lt;/code&gt; endpoint&lt;/a&gt; reports an HTTP 200 status code only after the query-frontend connects to at least one query-scheduler, and is then ready to serve queries.
Configure the &lt;code&gt;/ready&lt;/code&gt; endpoint as a healthcheck in your load balancer; otherwise, a query-frontend scale-out event might result in failed queries or high latency until the query-frontend connects to a query-scheduler.&lt;/p&gt;
]]></content><description>&lt;h1 id="grafana-mimir-query-frontend">Grafana Mimir query-frontend&lt;/h1>
&lt;p>The query-frontend is a stateless component that provides a &lt;a href="https://prometheus.io/docs/prometheus/latest/querying/api/" target="_blank" rel="noopener noreferrer">Prometheus compatible API&lt;/a> with a number of features to accelerate the read path.
The query-frontend is the primary entry point for the read path of Mimir.
The query-scheduler and queriers are required within the cluster to execute the queries.&lt;/p></description></item><item><title>Grafana Mimir query-scheduler</title><link>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/query-scheduler/</link><pubDate>Wed, 03 Jun 2026 09:01:40 +0200</pubDate><guid>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/query-scheduler/</guid><content><![CDATA[&lt;h1 id=&#34;grafana-mimir-query-scheduler&#34;&gt;Grafana Mimir query-scheduler&lt;/h1&gt;
&lt;p&gt;The query-scheduler is stateless component that retains a queue of queries to execute, and distributes the workload to available &lt;a href=&#34;../querier/&#34;&gt;queriers&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img
  class=&#34;lazyload d-inline-block&#34;
  data-src=&#34;query-scheduler-architecture.png&#34;
  alt=&#34;Query-scheduler architecture&#34;/&gt;&lt;/p&gt;
&lt;p&gt;The following flow describes how a query moves through a Grafana Mimir cluster:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;a href=&#34;../query-frontend/&#34;&gt;query-frontend&lt;/a&gt; receives queries, and then either splits and shards them, or serves them from the cache.&lt;/li&gt;
&lt;li&gt;The query-frontend enqueues the queries into a query-scheduler.&lt;/li&gt;
&lt;li&gt;The query-scheduler stores the queries in an in-memory queue where they wait for a querier to pick them up.&lt;/li&gt;
&lt;li&gt;Queriers pick up the queries, and executes them.&lt;/li&gt;
&lt;li&gt;The querier sends results back to query-frontend, which then forwards the results to the client.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;benefits-of-using-the-query-scheduler&#34;&gt;Benefits of using the query-scheduler&lt;/h2&gt;
&lt;p&gt;Query-scheduler enables the scaling of query-frontends by moving queuing of requests to a separate component.
The query-scheduler prevents queries that only require ingesters from being affected by degradation of store-gateways and vice versa.
The query-scheduler ensures tenant fairness using a simple round-robin between all tenants with active queries.&lt;/p&gt;
&lt;h2 id=&#34;configuration&#34;&gt;Configuration&lt;/h2&gt;
&lt;p&gt;Query-frontends and queriers need to discover the addresses of query-scheduler instances.
The query-scheduler supports two service discovery mechanisms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DNS-based service discovery&lt;/li&gt;
&lt;li&gt;Ring-based service discovery&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;dns-based-service-discovery&#34;&gt;DNS-based service discovery&lt;/h3&gt;
&lt;p&gt;To use the query-scheduler with DNS-based service discovery, configure the query-frontends and queriers to connect to the query-scheduler:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Query-frontend: &lt;code&gt;-query-frontend.scheduler-address&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Querier: &lt;code&gt;-querier.scheduler-address&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;The configured query-scheduler address should be in the &lt;code&gt;host:port&lt;/code&gt; format.&lt;/p&gt;
&lt;p&gt;If multiple query-schedulers are running, the host should be a DNS name resolving to all query-scheduler instances.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h3 id=&#34;ring-based-service-discovery&#34;&gt;Ring-based service discovery&lt;/h3&gt;
&lt;p&gt;To use the query-scheduler with ring-based service discovery, configure the query-schedulers to join their hash ring, and the query-frontends and queriers to discover query-scheduler instances via the ring:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;../../../../configure/configure-hash-rings/&#34;&gt;Configure the hash ring&lt;/a&gt; for the query-scheduler.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;-query-scheduler.service-discovery-mode=ring&lt;/code&gt; (or its respective YAML configuration parameter) to query-scheduler, query-frontend and querier.&lt;/li&gt;
&lt;li&gt;Set the &lt;code&gt;-query-scheduler.ring.*&lt;/code&gt; flags (or their respective YAML configuration parameters) to query-scheduler, query-frontend and querier.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;migrate-from-dns-based-to-ring-based-service-discovery&#34;&gt;Migrate from DNS-based to ring-based service discovery&lt;/h4&gt;
&lt;p&gt;To migrate the query-scheduler from &lt;a href=&#34;#dns-based-service-discovery&#34;&gt;DNS-based service discovery&lt;/a&gt; to &lt;a href=&#34;#ring-based-service-discovery&#34;&gt;ring-based service discovery&lt;/a&gt;, perform the following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Configure the &lt;strong&gt;query-scheduler&lt;/strong&gt; instances to join a ring:&lt;/p&gt;

&lt;div class=&#34;code-snippet code-snippet__mini&#34;&gt;&lt;div class=&#34;lang-toolbar__mini&#34;&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet code-snippet__border&#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-none&#34;&gt;-query-scheduler.service-discovery-mode=ring

# Configure the query-scheduler ring backend (e.g. &amp;#34;memberlist&amp;#34;).
-query-scheduler.ring.store=&amp;lt;backend&amp;gt;

# If the configured &amp;lt;backend&amp;gt; is &amp;#34;memberlist&amp;#34;, then ensure memberlist is configured for the query-scheduler.
-memberlist.join=&amp;lt;same as other Mimir components&amp;gt;

# If the configured &amp;lt;backend&amp;gt; is &amp;#34;consul&amp;#34; or &amp;#34;etcd&amp;#34;, then set their backend configuration
# for the query-scheduler ring:
# - Consul: -query-scheduler.ring.consul.*
# - Ecd:    -query-scheduler.ring.etcd.*&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wait until the query-scheduler instances have completed rolling out.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ensure the changes have been successfully applied; open the &lt;a href=&#34;../../../http-api/#query-scheduler-ring-status&#34;&gt;query-scheduler ring status&lt;/a&gt; page and ensure all query-scheduler instances are registered to the ring.
At this point, queriers and query-frontend are still discovering query-schedulers via DNS.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure &lt;strong&gt;query-frontend&lt;/strong&gt; and &lt;strong&gt;querier&lt;/strong&gt; instances to discover query-schedulers via the ring:&lt;/p&gt;

&lt;div class=&#34;code-snippet code-snippet__mini&#34;&gt;&lt;div class=&#34;lang-toolbar__mini&#34;&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet code-snippet__border&#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-none&#34;&gt;-query-scheduler.service-discovery-mode=ring

# Remove the DNS-based service discovery configuration:
# -query-frontend.scheduler-address

# Configure the query-scheduler ring backend (e.g. &amp;#34;memberlist&amp;#34;).
-query-scheduler.ring.store=&amp;lt;backend&amp;gt;

# If the configured &amp;lt;backend&amp;gt; is &amp;#34;memberlist&amp;#34;, then ensure memberlist is configured for the query-scheduler.
-memberlist.join=&amp;lt;same as other Mimir components&amp;gt;

# If the configured &amp;lt;backend&amp;gt; is &amp;#34;consul&amp;#34; or &amp;#34;etcd&amp;#34;, then set their backend configuration
# for the query-scheduler ring:
# - Consul: -query-scheduler.ring.consul.*
# - Ecd:    -query-scheduler.ring.etcd.*&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;If you deploy your Mimir cluster with Jsonnet, refer to &lt;a href=&#34;../../../../set-up/jsonnet/migrate-query-scheduler-from-dns-to-ring-based-service-discovery/&#34;&gt;Migrate query-scheduler from DNS-based to ring-based service discovery&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h2 id=&#34;operational-considerations&#34;&gt;Operational considerations&lt;/h2&gt;
&lt;p&gt;For high-availability, run two query-scheduler replicas.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re running a Grafana Mimir cluster with a very high query throughput, you can add more query-scheduler replicas.
If you scale the query-scheduler, ensure that the number of replicas you add is less or equal than the configured &lt;code&gt;-querier.max-concurrent&lt;/code&gt;.&lt;/p&gt;
]]></content><description>&lt;h1 id="grafana-mimir-query-scheduler">Grafana Mimir query-scheduler&lt;/h1>
&lt;p>The query-scheduler is stateless component that retains a queue of queries to execute, and distributes the workload to available &lt;a href="../querier/">queriers&lt;/a>.&lt;/p>
&lt;p>&lt;img
class="lazyload d-inline-block"
data-src="query-scheduler-architecture.png"
alt="Query-scheduler architecture"/>&lt;/p></description></item><item><title>Grafana Mimir store-gateway</title><link>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/store-gateway/</link><pubDate>Wed, 03 Jun 2026 09:01:40 +0200</pubDate><guid>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/store-gateway/</guid><content><![CDATA[&lt;h1 id=&#34;grafana-mimir-store-gateway&#34;&gt;Grafana Mimir store-gateway&lt;/h1&gt;
&lt;p&gt;The store-gateway component, which is stateful, queries blocks from &lt;a href=&#34;../../../../get-started/about-grafana-mimir-architecture/#long-term-storage&#34;&gt;long-term storage&lt;/a&gt;.
On the read path, the &lt;a href=&#34;../querier/&#34;&gt;querier&lt;/a&gt; and the &lt;a href=&#34;../ruler/&#34;&gt;ruler&lt;/a&gt; use the store-gateway when handling the query, whether the query comes from a user or from when a rule is being evaluated.&lt;/p&gt;
&lt;h2 id=&#34;bucket-index&#34;&gt;Bucket index&lt;/h2&gt;
&lt;p&gt;To find the right blocks to look up at query time, the store-gateway requires a view of the bucket in long-term storage.
The store-gateway keeps the bucket view updated by periodically downloading the &lt;a href=&#34;../../bucket-index/&#34;&gt;bucket index&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To discover each tenant&amp;rsquo;s blocks and block deletion marks, at startup, store-gateways fetch the &lt;a href=&#34;../../bucket-index/&#34;&gt;bucket index&lt;/a&gt; from long-term storage for each tenant that belongs to their &lt;a href=&#34;#blocks-sharding-and-replication&#34;&gt;shard&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For each discovered block, the store-gateway downloads the &lt;a href=&#34;#blocks-index-header&#34;&gt;index header&lt;/a&gt; to the local disk.
During this initial bucket-synchronization phase, the store-gateway’s &lt;code&gt;/ready&lt;/code&gt; readiness probe endpoint reports a not-ready status.&lt;/p&gt;
&lt;p&gt;For more information about the bucket index, refer to &lt;a href=&#34;../../bucket-index/&#34;&gt;bucket index&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Store-gateways periodically re-download the bucket index to obtain an updated view of the long-term storage and discover new blocks uploaded by ingesters and compactors, or deleted by compactors.&lt;/p&gt;
&lt;p&gt;It is possible that the compactor might have deleted blocks or marked others for deletion since the store-gateway last checked the block.
The store-gateway downloads the index header for new blocks, and offloads (deletes) the local copy of index header for deleted blocks.
You can configure the &lt;code&gt;-blocks-storage.bucket-store.sync-interval&lt;/code&gt; flag to control the frequency with which the store-gateway checks for changes in the long-term storage.&lt;/p&gt;
&lt;p&gt;When a query executes, the store-gateway downloads chunks, but it does not fully download the whole block; the store-gateway downloads only the portions of index and chunks that are required to run a given query.
To avoid the store-gateway having to re-download the index header during subsequent restarts, we recommend running the store-gateway with a persistent disk.
For example, if you&amp;rsquo;re running the Grafana Mimir cluster in Kubernetes, you can use a StatefulSet with a PersistentVolumeClaim for the store-gateways.&lt;/p&gt;
&lt;p&gt;For more information about the index-header, refer to &lt;a href=&#34;../../binary-index-header/&#34;&gt;Binary index-header documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;blocks-sharding-and-replication&#34;&gt;Blocks sharding and replication&lt;/h2&gt;
&lt;p&gt;The store-gateway uses blocks sharding to horizontally scale blocks in a large cluster.&lt;/p&gt;
&lt;p&gt;Blocks are replicated across multiple store-gateway instances based on a replication factor configured via &lt;code&gt;-store-gateway.sharding-ring.replication-factor&lt;/code&gt;.
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, such as in the event of a store-gateway failure or while restarting a store-gateway instance (for example, during a rolling update).&lt;/p&gt;
&lt;p&gt;Store-gateway instances build a &lt;a href=&#34;../../hash-ring/&#34;&gt;hash ring&lt;/a&gt; and shard and replicate blocks across the pool of store-gateway instances registered in the ring.&lt;/p&gt;
&lt;p&gt;Store-gateways continuously monitor the ring state.
When the ring topology changes, for example, when a new instance is added or removed, or the instance becomes healthy or unhealthy, each store-gateway instance resynchronizes the blocks assigned to its shard.
The store-gateway resynchronization process uses the block ID hash that matches the token ranges assigned to the instance within the ring.&lt;/p&gt;
&lt;p&gt;The store-gateway loads the index-header of each block that belongs to its store-gateway shard.
After the store-gateway loads a block’s index header, the block is ready to be queried by queriers.
When the querier queries blocks via a store-gateway, the response contains the list of queried block IDs.
If a querier attempts to query a block that the store-gateway has not loaded, the querier retries the query on a different store-gateway up to the &lt;code&gt;-store-gateway.sharding-ring.replication-factor&lt;/code&gt; value, which by default is &lt;code&gt;3&lt;/code&gt;.
The query fails if the block can&amp;rsquo;t be successfully queried from any replica.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;You must configure the &lt;a href=&#34;../../hash-ring/&#34;&gt;hash ring&lt;/a&gt; via the &lt;code&gt;-store-gateway.sharding-ring.*&lt;/code&gt; flags or their respective YAML configuration parameters.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h3 id=&#34;sharding-strategy&#34;&gt;Sharding strategy&lt;/h3&gt;
&lt;p&gt;The store-gateway uses shuffle-sharding to divide the blocks of each tenant across a subset of store-gateway instances.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;When shuffle-sharding is in use, only a subset of store-gateway instances load the blocks of a tenant.&lt;/p&gt;
&lt;p&gt;This confines blast radius of issues introduced by the tenant&amp;rsquo;s workload to its shard instances.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;-store-gateway.tenant-shard-size&lt;/code&gt; flag (or their respective YAML configuration parameters) determines the default number of store-gateway instances per tenant.
The &lt;code&gt;store_gateway_tenant_shard_size&lt;/code&gt; in the limits overrides can override the shard size on a per-tenant basis.&lt;/p&gt;
&lt;p&gt;The default &lt;code&gt;-store-gateway.tenant-shard-size&lt;/code&gt; value is 0, which means that tenant&amp;rsquo;s blocks are sharded across all store-gateway instances.&lt;/p&gt;
&lt;p&gt;For more information about shuffle sharding, refer to &lt;a href=&#34;../../../../configure/configure-shuffle-sharding/&#34;&gt;configure shuffle sharding&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;auto-forget&#34;&gt;Auto-forget&lt;/h3&gt;
&lt;p&gt;Store-gateways include an auto-forget feature that they can use to unregister an instance from another store-gateway&amp;rsquo;s ring when a store-gateway does not properly shut down.
Under normal conditions, when a store-gateway instance shuts down, it automatically unregisters from the ring. However, in the event of a crash or node failure, the instance might not properly unregister, which can leave a spurious entry in the ring.&lt;/p&gt;
&lt;p&gt;The auto-forget feature works as follows: when an healthy store-gateway instance identifies an instance in the ring that is unhealthy for longer than 10 times the configured &lt;code&gt;-store-gateway.sharding-ring.heartbeat-timeout&lt;/code&gt; value, the healthy instance removes the unhealthy instance from the ring.&lt;/p&gt;
&lt;p&gt;The store-gateway auto-forget feature can be disabled by setting &lt;code&gt;-store-gateway.sharding-ring.auto-forget-enabled=false&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;zone-awareness&#34;&gt;Zone-awareness&lt;/h3&gt;
&lt;p&gt;Store-gateway replication optionally supports &lt;a href=&#34;../../../../configure/configure-zone-aware-replication/&#34;&gt;zone-awareness&lt;/a&gt;. When you enable zone-aware replication and the blocks replication factor is greater than 1, each block is replicated across store-gateway instances located in different availability zones.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;To enable zone-aware replication for the store-gateways&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Configure the availability zone for each store-gateway via the &lt;code&gt;-store-gateway.sharding-ring.instance-availability-zone&lt;/code&gt; CLI flag or its respective YAML configuration parameter.&lt;/li&gt;
&lt;li&gt;Enable blocks zone-aware replication via the &lt;code&gt;-store-gateway.sharding-ring.zone-awareness-enabled&lt;/code&gt; CLI flag or its respective YAML configuration parameter.
Set this zone-aware replication flag on store-gateways, queriers, and rulers.&lt;/li&gt;
&lt;li&gt;To apply the new configuration, roll out store-gateways, queriers, and rulers.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;waiting-for-stable-ring-at-startup&#34;&gt;Waiting for stable ring at startup&lt;/h3&gt;
&lt;p&gt;If a cluster cold starts or scales up to two or more store-gateway instances simultaneously, the store-gateways could start at different times. As a result, the store-gateway runs the initial blocks synchronization based on a different state of the hash ring.&lt;/p&gt;
&lt;p&gt;For example, in the event of a cold start, the first store-gateway that joins the ring might load all blocks because the sharding logic runs based on the current state of the ring, which contains one single store-gateway.&lt;/p&gt;
&lt;p&gt;To reduce the likelihood of store-gateways starting at different times, you can configure the store-gateway to wait for a stable ring at startup. A ring is considered stable when no instance is added or removed from the ring for the minimum duration specified in the &lt;code&gt;-store-gateway.sharding-ring.wait-stability-min-duration&lt;/code&gt; flag. If the ring continues to change after reaching the maximum duration specified in the &lt;code&gt;-store-gateway.sharding-ring.wait-stability-max-duration&lt;/code&gt; flag, the store-gateway stops waiting for a stable ring and proceeds starting up.&lt;/p&gt;
&lt;p&gt;To enable waiting for the ring to be stable at startup, start the store-gateway with &lt;code&gt;-store-gateway.sharding-ring.wait-stability-min-duration=1m&lt;/code&gt;, which is the recommended value for production systems.&lt;/p&gt;
&lt;h2 id=&#34;blocks-index-header&#34;&gt;Blocks index-header&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&#34;../../binary-index-header/&#34;&gt;index-header&lt;/a&gt; is a subset of the block index that the store-gateway downloads from long-term storage and keeps on the local disk.
Keeping the index-header on the local disk makes query execution faster.&lt;/p&gt;
&lt;h3 id=&#34;index-header-lazy-loading&#34;&gt;Index-header lazy loading&lt;/h3&gt;
&lt;p&gt;By default, a store-gateway downloads the index-headers to disk and doesn&amp;rsquo;t load them to memory until required.
When required by a query, index-headers are loaded and automatically released by the store-gateway after the amount of inactivity time you specify in &lt;code&gt;-blocks-storage.bucket-store.index-header.lazy-loading-idle-timeout&lt;/code&gt; has passed.&lt;/p&gt;
&lt;p&gt;Grafana Mimir provides a configuration flag &lt;code&gt;-blocks-storage.bucket-store.index-header.lazy-loading-enabled=false&lt;/code&gt; to disable index-header lazy loading.
When disabled, the store-gateway loads all index-headers at startup, which provides faster access to the data in the index-header when querying at the cost of longer startup times.
However, in a cluster with a large number of blocks, each store-gateway might have a large amount of loaded index-headers, regardless of how frequently they are used at query time.&lt;/p&gt;
&lt;p&gt;When the index-header is loaded, only a portion of it is kept in memory to reduce memory usage.
The rest of the index-header is read from disk as required.
This requires that store-gateways have memory available to be used by the operating system for caching disk accesses.&lt;/p&gt;
&lt;h2 id=&#34;caching&#34;&gt;Caching&lt;/h2&gt;
&lt;p&gt;The store-gateway supports the following type of caches:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#index-cache&#34;&gt;Index cache&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#chunks-cache&#34;&gt;Chunks cache&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#metadata-cache&#34;&gt;Metadata cache&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We recommend that you use caching in a production environment.
For more information about configuring the cache, refer to &lt;a href=&#34;../../../../manage/run-production-environment/production-tips/#caching&#34;&gt;production tips&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;index-cache&#34;&gt;Index cache&lt;/h3&gt;
&lt;p&gt;The store-gateway can use a cache to accelerate series and label lookups from block indexes. The store-gateway supports the following backends:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;inmemory&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;memcached&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;in-memory-index-cache&#34;&gt;In-memory index cache&lt;/h4&gt;
&lt;p&gt;By default, the &lt;code&gt;inmemory&lt;/code&gt; index cache is enabled.&lt;/p&gt;
&lt;p&gt;Consider the following trade-offs of using the in-memory index cache:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pros: There is no latency.&lt;/li&gt;
&lt;li&gt;Cons: When the replication factor is &amp;gt; 1, then the data that resides in the memory of the store-gateway will be duplicated among different instances. This leads to an increase in overall memory usage and a reduced cache hit ratio.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can configure the index cache max size using the &lt;code&gt;-blocks-storage.bucket-store.index-cache.inmemory.max-size-bytes&lt;/code&gt; flag or its respective YAML configuration parameter.&lt;/p&gt;
&lt;h4 id=&#34;memcached-index-cache&#34;&gt;Memcached index cache&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;memcached&lt;/code&gt; index cache uses &lt;a href=&#34;https://memcached.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Memcached&lt;/a&gt; as the cache backend.&lt;/p&gt;
&lt;p&gt;Consider the following trade-offs of using the Memcached index cache:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pros: You can scale beyond a single node&amp;rsquo;s memory by creating a Memcached cluster, that is shared by multiple store-gateway instances.&lt;/li&gt;
&lt;li&gt;Cons: The system experiences higher latency in the cache round trip compared to the latency experienced when using in-memory cache.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Memcached client uses a jump hash algorithm to shard cached entries across a cluster of Memcached servers.
Because the memcached client uses a jump hash algorithm, ensure that memcached servers are not located behind a load balancer, and configure the address of the memcached servers so that servers are added to or removed from the end of the list whenever a scale up or scale down occurs.&lt;/p&gt;
&lt;p&gt;For example, if you&amp;rsquo;re running Memcached in Kubernetes, you might:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Deploy your Memcached cluster using a &lt;a href=&#34;https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;StatefulSet&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Create a &lt;a href=&#34;https://kubernetes.io/docs/concepts/services-networking/service/#headless-services&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;headless service&lt;/a&gt; for Memcached StatefulSet.&lt;/li&gt;
&lt;li&gt;Configure the Mimir&amp;rsquo;s Memcached client address using the &lt;code&gt;dnssrvnoa&#43;&lt;/code&gt; &lt;a href=&#34;../../../../configure/about-dns-service-discovery/&#34;&gt;service discovery&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;To configure the Memcached backend&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;-blocks-storage.bucket-store.index-cache.backend=memcached&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use the &lt;code&gt;-blocks-storage.bucket-store.index-cache.memcached.addresses&lt;/code&gt; flag to set the address of the Memcached service.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&#34;../../../../configure/about-dns-service-discovery/&#34;&gt;DNS service discovery&lt;/a&gt; resolves the addresses of the Memcached servers.&lt;/p&gt;
&lt;h3 id=&#34;chunks-cache&#34;&gt;Chunks cache&lt;/h3&gt;
&lt;p&gt;The store-gateway can also use a cache to store &lt;a href=&#34;../../../glossary/#chunk&#34;&gt;chunks&lt;/a&gt; that are fetched from long-term storage.
Chunks contain actual samples, and can be reused if a query hits the same series for the same time range.
Chunks can only be cached in Memcached.&lt;/p&gt;
&lt;p&gt;To enable chunks cache, set &lt;code&gt;-blocks-storage.bucket-store.chunks-cache.backend=memcached&lt;/code&gt;.
You can configure the Memcached client via flags that include the prefix &lt;code&gt;-blocks-storage.bucket-store.chunks-cache.memcached.*&lt;/code&gt;.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;There are additional low-level flags that begin with the prefix &lt;code&gt;-blocks-storage.bucket-store.chunks-cache.*&lt;/code&gt; that you can use to configure chunks cache.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h3 id=&#34;metadata-cache&#34;&gt;Metadata cache&lt;/h3&gt;
&lt;p&gt;Store-gateways and &lt;a href=&#34;../querier/&#34;&gt;queriers&lt;/a&gt; can use memcached to cache the following bucket metadata:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;List of tenants&lt;/li&gt;
&lt;li&gt;List of blocks per tenant&lt;/li&gt;
&lt;li&gt;Block &lt;code&gt;meta.json&lt;/code&gt; existence and content&lt;/li&gt;
&lt;li&gt;Block &lt;code&gt;deletion-mark.json&lt;/code&gt; existence and content&lt;/li&gt;
&lt;li&gt;Tenant &lt;code&gt;bucket-index.json.gz&lt;/code&gt; content&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using the metadata cache reduces the number of API calls to long-term storage and eliminates API calls that scale linearly as the number of querier and store-gateway replicas increases.&lt;/p&gt;
&lt;p&gt;To enable metadata cache, set &lt;code&gt;-blocks-storage.bucket-store.metadata-cache.backend&lt;/code&gt;.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;Mimir only supports the &lt;code&gt;memcached&lt;/code&gt; backend for the metadata cache.&lt;/p&gt;
&lt;p&gt;The Memcached client includes additional configuration available via flags that begin with the prefix &lt;code&gt;-blocks-storage.bucket-store.metadata-cache.memcached.*&lt;/code&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;Additional flags for configuring metadata cache begin with the prefix &lt;code&gt;-blocks-storage.bucket-store.metadata-cache.*&lt;/code&gt;. By configuring TTL to zero or a negative value, caching of given item type is disabled.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;You should use the same Memcached backend cluster for both the store-gateways and queriers.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h2 id=&#34;store-gateway-http-endpoints&#34;&gt;Store-gateway HTTP endpoints&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /store-gateway/ring&lt;/code&gt;&lt;br /&gt;
Displays the status of the store-gateways ring, including the tokens owned by each store-gateway and an option to remove (or forget) instances from the ring.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;store-gateway-configuration&#34;&gt;Store-gateway configuration&lt;/h2&gt;
&lt;p&gt;For more information about store-gateway configuration, refer to &lt;a href=&#34;../../../../configure/configuration-parameters/#store_gateway&#34;&gt;store_gateway&lt;/a&gt;.&lt;/p&gt;
]]></content><description>&lt;h1 id="grafana-mimir-store-gateway">Grafana Mimir store-gateway&lt;/h1>
&lt;p>The store-gateway component, which is stateful, queries blocks from &lt;a href="../../../../get-started/about-grafana-mimir-architecture/#long-term-storage">long-term storage&lt;/a>.
On the read path, the &lt;a href="../querier/">querier&lt;/a> and the &lt;a href="../ruler/">ruler&lt;/a> use the store-gateway when handling the query, whether the query comes from a user or from when a rule is being evaluated.&lt;/p></description></item><item><title>(Optional) Grafana Mimir Alertmanager</title><link>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/alertmanager/</link><pubDate>Wed, 03 Jun 2026 09:01:40 +0200</pubDate><guid>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/alertmanager/</guid><content><![CDATA[&lt;h1 id=&#34;optional-grafana-mimir-alertmanager&#34;&gt;(Optional) Grafana Mimir Alertmanager&lt;/h1&gt;
&lt;p&gt;The Mimir Alertmanager adds multi-tenancy support and horizontal scalability to the &lt;a href=&#34;https://prometheus.io/docs/alerting/alertmanager/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Prometheus Alertmanager&lt;/a&gt;.
The Mimir Alertmanager is an optional component that accepts alert notifications from the &lt;a href=&#34;../ruler/&#34;&gt;Mimir ruler&lt;/a&gt;.
The Alertmanager deduplicates and groups alert notifications, and routes them to a notification channel, such as email, PagerDuty, or OpsGenie.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;To run Mimir Alertmanager as a part of &lt;a href=&#34;../../deployment-modes/#monolithic-mode&#34;&gt;monolithic deployment&lt;/a&gt;, run Mimir with the option &lt;code&gt;-target=all,alertmanager&lt;/code&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h2 id=&#34;multi-tenancy&#34;&gt;Multi-tenancy&lt;/h2&gt;
&lt;p&gt;Like other Mimir components, multi-tenancy in the Mimir Alertmanager uses the tenant ID header.
Each tenant has an isolated alert routing configuration and Alertmanager UI.&lt;/p&gt;
&lt;h3 id=&#34;tenant-configurations&#34;&gt;Tenant configurations&lt;/h3&gt;
&lt;p&gt;Each tenant has an Alertmanager configuration that defines notifications receivers and alerting routes.
The Mimir Alertmanager uses the same &lt;a href=&#34;https://prometheus.io/docs/alerting/latest/configuration/#configuration-file&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;configuration file&lt;/a&gt; that the Prometheus Alertmanager uses.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;The Mimir Alertmanager exposes the configuration API according to the path set by the &lt;code&gt;-server.path-prefix&lt;/code&gt; flag.
It doesn&amp;rsquo;t use the path set by the &lt;code&gt;-http.alertmanager-http-prefix&lt;/code&gt; flag.&lt;/p&gt;
&lt;p&gt;If you run Mimir with the default configuration, &lt;code&gt;-server.path-prefix&lt;/code&gt;, where the default value is &lt;code&gt;/&lt;/code&gt;, then only set the hostname for the &lt;code&gt;--address&lt;/code&gt; flag of the &lt;code&gt;mimirtool&lt;/code&gt; command; don&amp;rsquo;t set a path-specific address.
For example, &lt;code&gt;/&lt;/code&gt; is correct, and &lt;code&gt;/alertmanager&lt;/code&gt; is incorrect.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;You can validate a configuration file using the &lt;code&gt;mimirtool&lt;/code&gt; command:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;mimirtool alertmanager verify &amp;lt;ALERTMANAGER CONFIGURATION FILE&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The following sample command shows how to upload a tenant&amp;rsquo;s Alertmanager configuration using &lt;code&gt;mimirtool&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;mimirtool alertmanager load &amp;lt;ALERTMANAGER CONFIGURATION FILE&amp;gt;  \
  --address=&amp;lt;ALERTMANAGER URL&amp;gt;
  --id=&amp;lt;TENANT ID&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The following sample command shows how to retrieve a tenant&amp;rsquo;s Alertmanager configuration using &lt;code&gt;mimirtool&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;mimirtool alertmanager get \
  --address=&amp;lt;ALERTMANAGER URL&amp;gt;
  --id=&amp;lt;TENANT ID&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The following sample commands shows how to delete a tenant&amp;rsquo;s Alertmanager configuration using &lt;code&gt;mimirtool&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;mimirtool alertmanager delete \
  --address=&amp;lt;ALERTMANAGER URL&amp;gt;
  --id=&amp;lt;TENANT ID&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;After the tenant uploads an Alertmanager configuration, the tenant can access the Alertmanager UI at the &lt;code&gt;/alertmanager&lt;/code&gt; endpoint.&lt;/p&gt;
&lt;h4 id=&#34;fallback-configuration&#34;&gt;Fallback configuration&lt;/h4&gt;
&lt;p&gt;When a tenant doesn&amp;rsquo;t have a Alertmanager configuration, the Grafana Mimir Alertmanager uses a fallback configuration.
By default, there is always a fallback configuration set.
You can overwrite the default fallback configuration via the &lt;code&gt;-alertmanager.configs.fallback&lt;/code&gt; command-line flag.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-warning&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Warning&lt;/p&gt;&lt;p&gt;Without a fallback configuration or a tenant specific configuration, the Alertmanager UI is inaccessible and ruler notifications for that tenant fail.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h3 id=&#34;tenant-limits&#34;&gt;Tenant limits&lt;/h3&gt;
&lt;p&gt;The Grafana Mimir Alertmanager has a number of per-tenant limits documented in &lt;a href=&#34;../../../../configure/configuration-parameters/#limits&#34;&gt;&lt;code&gt;limits&lt;/code&gt;&lt;/a&gt;.
Each Mimir Alertmanager limit configuration parameter has an &lt;code&gt;alertmanager&lt;/code&gt; prefix.&lt;/p&gt;
&lt;h2 id=&#34;alertmanager-ui&#34;&gt;Alertmanager UI&lt;/h2&gt;
&lt;p&gt;The Mimir Alertmanager exposes the same web UI as the Prometheus Alertmanager at the &lt;code&gt;/alertmanager&lt;/code&gt; endpoint.&lt;/p&gt;
&lt;p&gt;When running Grafana Mimir with multi-tenancy enabled, the Alertmanager requires that any HTTP request include the tenant ID header.
Tenants only see alerts sent to their Alertmanager.&lt;/p&gt;
&lt;p&gt;For a complete reference of the tenant ID header and Alertmanager endpoints, refer to &lt;a href=&#34;../../../http-api/&#34;&gt;HTTP API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can configure the HTTP path prefix for the UI and the HTTP API:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-http.alertmanager-http-prefix&lt;/code&gt; configures the path prefix for Alertmanager endpoints.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-alertmanager.web.external-url&lt;/code&gt; configures the source URLs generated in Alertmanager alerts and from where to fetch web assets.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;Unless you are using a reverse proxy in front of the Alertmanager API that rewrites routes, the path prefix set in &lt;code&gt;-alertmanager.web.external-url&lt;/code&gt; must match the path prefix set in &lt;code&gt;-http.alertmanager-http-prefix&lt;/code&gt; which is &lt;code&gt;/alertmanager&lt;/code&gt; by default.&lt;/p&gt;
&lt;p&gt;If the path prefixes don&amp;rsquo;t match, HTTP requests routing might not work as expected.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h3 id=&#34;using-a-reverse-proxy&#34;&gt;Using a reverse proxy&lt;/h3&gt;
&lt;p&gt;When using a reverse proxy, use the following settings when you configure the HTTP path:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;-http.alertmanager-http-prefix&lt;/code&gt; to match the proxy path in your reverse proxy configuration.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;-alertmanager.web.external-url&lt;/code&gt; to the URL served by your reverse proxy.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;templating&#34;&gt;Templating&lt;/h2&gt;
&lt;p&gt;The Mimir Alertmanager adds some custom template functions to the default ones of the Prometheus Alertmanager.&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Function&lt;/th&gt;
              &lt;th&gt;Params&lt;/th&gt;
              &lt;th&gt;Description&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;tenantID&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;-&lt;/td&gt;
              &lt;td&gt;Returns ID of the tenant the alert belongs to.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;queryFromGeneratorURL&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;generator_url&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;Returns the URL decoded query from &lt;code&gt;GeneratorURL&lt;/code&gt; of an alert set by a Prometheus. Example: &lt;code&gt;{{ queryFromGeneratorURL (index .Alerts 0).GeneratorURL }}&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;grafanaExploreURL&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;grafana_URL&lt;/code&gt;,&lt;code&gt;datasource&lt;/code&gt;,&lt;code&gt;from&lt;/code&gt;,&lt;code&gt;to&lt;/code&gt;,&lt;code&gt;expr&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;Returns link to Grafana explore with range query based on the input parameters. Example: &lt;code&gt;{{ grafanaExploreURL &amp;quot;https://foo.bar&amp;quot; &amp;quot;xyz&amp;quot; &amp;quot;now-12h&amp;quot; &amp;quot;now&amp;quot; (queryFromGeneratorURL (index .Alerts 0).GeneratorURL) }}&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;h2 id=&#34;sharding-and-replication&#34;&gt;Sharding and replication&lt;/h2&gt;
&lt;p&gt;The Alertmanager shards and replicates alerts by tenant.
Sharding requires that the number of Alertmanager replicas is greater-than or equal-to the replication factor configured by the &lt;code&gt;-alertmanager.sharding-ring.replication-factor&lt;/code&gt; flag.&lt;/p&gt;
&lt;p&gt;Grafana Mimir Alertmanager replicas use a &lt;a href=&#34;../../hash-ring/&#34;&gt;hash ring&lt;/a&gt; that is stored in the KV store to discover their peers.
This means that any Mimir Alertmanager replica can respond to any API or UI request for any tenant.
If the Mimir Alertmanager replica receiving the HTTP request doesn&amp;rsquo;t own the tenant to which the request belongs, the request is internally routed to the appropriate replica.&lt;/p&gt;
&lt;p&gt;To configure the Alertmanagers&amp;rsquo; hash ring, refer to &lt;a href=&#34;../../../../configure/configure-hash-rings/&#34;&gt;configuring hash rings&lt;/a&gt;.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;When running with a single tenant, scaling the number of replicas to be greater than the replication factor offers no benefits as the Mimir Alertmanager shards by tenant and not individual alerts.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h3 id=&#34;state&#34;&gt;State&lt;/h3&gt;
&lt;p&gt;The Mimir Alertmanager stores the alerts state on local disk at the location configured using &lt;code&gt;-alertmanager.storage.path&lt;/code&gt;.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-warning&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Warning&lt;/p&gt;&lt;p&gt;When running the Mimir Alertmanager without replication, ensure persistence of the &lt;code&gt;-alertmanager.storage.path&lt;/code&gt; directory to avoid losing alert state.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;The Mimir Alertmanager also periodically stores the alert state in the storage backend configured with &lt;code&gt;-alertmanager-storage.backend&lt;/code&gt;.
When an Alertmanager starts, it attempts to load the alerts state for a given tenant from other Alertmanager replicas. If the load from other Alertmanager replicas fails, the Alertmanager falls back to the state that is periodically stored in the storage backend.&lt;/p&gt;
&lt;p&gt;In the event of a cluster outage, this fallback mechanism recovers the backup of the previous state. Because backups are taken periodically, this fallback mechanism does not guarantee that the most recent state is restored.&lt;/p&gt;
&lt;h2 id=&#34;ruler-configuration&#34;&gt;Ruler configuration&lt;/h2&gt;
&lt;p&gt;You must configure the &lt;a href=&#34;../ruler/&#34;&gt;ruler&lt;/a&gt; with the addresses of Alertmanagers via the &lt;code&gt;-ruler.alertmanager-url&lt;/code&gt; flag.&lt;/p&gt;
&lt;p&gt;Point the address to Alertmanager’s API.
You can configure Alertmanager’s API prefix via the &lt;code&gt;-http.alertmanager-http-prefix&lt;/code&gt; flag, which defaults to &lt;code&gt;/alertmanager&lt;/code&gt;.
For example, if Alertmanager is listening at &lt;code&gt;http://mimir-alertmanager.namespace.svc.cluster.local&lt;/code&gt; and it is using the default API prefix, set &lt;code&gt;-ruler.alertmanager-url&lt;/code&gt; to &lt;code&gt;http://mimir-alertmanager.namespace.svc.cluster.local/alertmanager&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;enable-utf-8&#34;&gt;Enable UTF-8&lt;/h2&gt;
&lt;p&gt;In effort to support alerts from &lt;a href=&#34;https://opentelemetry.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;OpenTelemetry&lt;/a&gt; (OTel) data, &lt;a href=&#34;https://prometheus.io/docs/alerting/alertmanager/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Prometheus Alertmanager&lt;/a&gt; has added support for UTF-8. This is supported as an opt-in feature for the Grafana Mimir Alertmanager in Mimir versions 2.12 and later.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-warning&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Warning&lt;/p&gt;&lt;p&gt;Enabling and then disabling UTF-8 strict mode can break existing tenant configurations if tenants added UTF-8 characters to their Alertmanager configuration while it was enabled. Once enabled, disable UTF-8 strict mode with caution.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;For new Mimir installations, enable support for UTF-8 before creating any tenant configurations. You can do this by changing &lt;a href=&#34;../../../../configure/configuration-parameters/#alertmanager&#34;&gt;&lt;code&gt;utf8-strict-mode-enabled&lt;/code&gt;&lt;/a&gt; to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For existing Mimir installations, there are a number of breaking changes that might affect existing tenant configurations. Follow these instructions to ensure all existing tenant configurations are compatible with UTF-8 before enabling it.&lt;/p&gt;
&lt;h3 id=&#34;what-are-the-breaking-changes&#34;&gt;What are the breaking changes?&lt;/h3&gt;
&lt;p&gt;In order to support UTF-8, Alertmanager has added a new parser for label matchers (often abbreviated as matchers), which has a number of breaking changes.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;If you are unfamiliar with what matchers are or how they are used in a tenant configuration, you can find more information about them in the &lt;a href=&#34;https://prometheus.io/docs/alerting/latest/configuration&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Prometheus Alertmanager documentation&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;Grafana Mimir provides a number of tools to help you identify whether any existing tenant configurations are affected by these breaking changes, and to migrate any affected tenant configurations in a way that is backwards-compatible, doesn&amp;rsquo;t change the behavior of existing matchers, and works even in Mimir installations that do not have UTF-8 enabled.&lt;/p&gt;
&lt;h3 id=&#34;identify-affected-tenant-configurations&#34;&gt;Identify affected tenant configurations&lt;/h3&gt;
&lt;p&gt;To identify affected tenant configurations, take the following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Make sure Mimir is running version 2.12 or later.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enable &lt;a href=&#34;../../../../configure/configuration-parameters/#alertmanager&#34;&gt;&lt;code&gt;utf8-migration-logging-enabled&lt;/code&gt;&lt;/a&gt; and set &lt;a href=&#34;../../../../configure/configuration-parameters/#server&#34;&gt;&lt;code&gt;log_level&lt;/code&gt;&lt;/a&gt; to &lt;code&gt;debug&lt;/code&gt;. You must restart Mimir for the changes to take effect.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To identify any tenant configurations that are incompatible with UTF-8 (meaning the tenant configuration fails to load and the &lt;a href=&#34;#fallback-configuration&#34;&gt;fallback configuration&lt;/a&gt; is used instead), search Mimir server logs for lines containing &lt;code&gt;Alertmanager is moving to a new parser for labels and matchers, and this input is incompatible&lt;/code&gt;. Each log line includes the invalid matcher from the tenant configuration and the ID of the affected tenant. For example:&lt;/p&gt;

&lt;div class=&#34;code-snippet code-snippet__mini&#34;&gt;&lt;div class=&#34;lang-toolbar__mini&#34;&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet code-snippet__border&#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-none&#34;&gt;msg=&amp;#34;Alertmanager is moving to a new parser for labels and matchers, and this input is incompatible. Alertmanager has instead parsed the input using the classic matchers parser as a fallback. To make this input compatible with the UTF-8 matchers parser please make sure all regular expressions and values are double-quoted. If you are still seeing this message please open an issue.&amp;#34; input=&amp;#34;foo=&amp;#34; err=&amp;#34;end of input: expected label value&amp;#34; suggestion=&amp;#34;foo=\&amp;#34;\&amp;#34;&amp;#34; user=&amp;#34;1&amp;#34;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In this example, the tenant with User ID &lt;code&gt;1&lt;/code&gt; has an incompatible matcher in their tenant configuration &lt;code&gt;foo=&lt;/code&gt; and should to be changed to the suggestion &lt;code&gt;foo=&amp;quot;&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To identify any tenant configurations that are compatible with UTF-8 but contain matchers that might change in behavior when its enabled, search Mimir server logs for lines containing &lt;code&gt;Matchers input has disagreement&lt;/code&gt;. Disagreement occurs when a matcher is valid, but due to adding support for UTF-8, it can behave differently when UTF-8 is enabled.&lt;/p&gt;

&lt;div class=&#34;code-snippet code-snippet__mini&#34;&gt;&lt;div class=&#34;lang-toolbar__mini&#34;&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet code-snippet__border&#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-none&#34;&gt;msg=&amp;#34;Matchers input has disagreement&amp;#34; input=&amp;#34;foo=\&amp;#34;\\xf0\\x9f\\x99\\x82\&amp;#34;&amp;#34; user=&amp;#34;1&amp;#34;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;It is possible for a tenant configuration to be both incompatible with UTF-8 and have disagreement, as an individual tenant configuration can contain a large number of matchers across different routes and inhibition rules.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h3 id=&#34;fix-tenant-configurations&#34;&gt;Fix tenant configurations&lt;/h3&gt;
&lt;p&gt;To fix any identified tenant configurations, take the following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Use the &lt;code&gt;migrate-utf8&lt;/code&gt; &lt;a href=&#34;../../../../manage/tools/mimirtool/#migrate-alertmanager-configuration-for-utf-8-in-mimir-212-and-later&#34;&gt;command&lt;/a&gt; in mimirtool to fix any tenant configurations that are incompatible with UTF-8. This command can migrate existing tenant configurations in a way that is backwards-compatible, doesn&amp;rsquo;t change the behavior of existing matchers, and works even in Mimir installations that don&amp;rsquo;t have UTF-8 enabled. If you cannot use mimirtool, you can edit tenant configurations by hand through applying each suggestion from the Mimir server logs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You must look at tenant configurations that have disagreement on a case-by-case basis. Depending on the nature of the disagreement, you might not need to fix a matcher with disagreement. For example &lt;code&gt;\xf0\x9f\x99\x82&lt;/code&gt; is the byte sequence for the 🙂 emoji. If the intention is to match a literal 🙂 emoji then no change is required. However, if the intention is to match the literal &lt;code&gt;\xf0\x9f\x99\x82&lt;/code&gt; then you need to change the matcher to use &lt;code&gt;\\xf0\\x9f\\x99\\x82&lt;/code&gt; instead.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;It&amp;rsquo;s rare to find cases of disagreement in a tenant configuration, as most tenants do not need to match alerts that contain literal UTF-8 byte sequences in their labels.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h3 id=&#34;final-steps&#34;&gt;Final steps&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;After identifying and fixing all affected tenant configurations, check the Mimir server logs again to make sure you haven&amp;rsquo;t missed any tenant configurations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To enable UTF-8, set &lt;a href=&#34;../../../../configure/configuration-parameters/#alertmanager&#34;&gt;&lt;code&gt;utf8-strict-mode-enabled&lt;/code&gt;&lt;/a&gt; to &lt;code&gt;true&lt;/code&gt;. You must restart Mimir for the changes to take effect.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To confirm UTF-8 is enabled, search for &lt;code&gt;Starting Alertmanager in UTF-8 strict mode&lt;/code&gt; in the Mimir server logs. If you find &lt;code&gt;Starting Alertmanager in classic mode&lt;/code&gt; instead then UTF-8 is not enabled.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Any incompatible tenant configurations will fail to load. To identify if any tenant configurations are failing to load, search the Mimir server logs for lines containing &lt;code&gt;error applying config&lt;/code&gt;, or query the &lt;code&gt;cortex_alertmanager_config_last_reload_successful&lt;/code&gt; gauge for &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You can disable &lt;a href=&#34;../../../../configure/configuration-parameters/#alertmanager&#34;&gt;&lt;code&gt;utf8-migration-logging-enabled&lt;/code&gt;&lt;/a&gt; and set &lt;a href=&#34;../../../../configure/configuration-parameters/#server&#34;&gt;&lt;code&gt;log_level&lt;/code&gt;&lt;/a&gt; back to its previous value.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
]]></content><description>&lt;h1 id="optional-grafana-mimir-alertmanager">(Optional) Grafana Mimir Alertmanager&lt;/h1>
&lt;p>The Mimir Alertmanager adds multi-tenancy support and horizontal scalability to the &lt;a href="https://prometheus.io/docs/alerting/alertmanager/" target="_blank" rel="noopener noreferrer">Prometheus Alertmanager&lt;/a>.
The Mimir Alertmanager is an optional component that accepts alert notifications from the &lt;a href="../ruler/">Mimir ruler&lt;/a>.
The Alertmanager deduplicates and groups alert notifications, and routes them to a notification channel, such as email, PagerDuty, or OpsGenie.&lt;/p></description></item><item><title>(Optional) Grafana Mimir overrides-exporter</title><link>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/overrides-exporter/</link><pubDate>Wed, 03 Jun 2026 09:01:40 +0200</pubDate><guid>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/overrides-exporter/</guid><content><![CDATA[&lt;h1 id=&#34;optional-grafana-mimir-overrides-exporter&#34;&gt;(Optional) Grafana Mimir overrides-exporter&lt;/h1&gt;
&lt;p&gt;Grafana Mimir supports applying overrides on a per-tenant basis.
A number of overrides configure limits that prevent a single tenant from using too many resources.
The overrides-exporter component exposes limits as Prometheus metrics so that operators can understand how close tenants are to their limits.&lt;/p&gt;
&lt;p&gt;For more information about configuring overrides, refer to &lt;a href=&#34;../../../../configure/about-runtime-configuration/&#34;&gt;Runtime configuration file&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;running-the-overrides-exporter&#34;&gt;Running the overrides-exporter&lt;/h2&gt;
&lt;p&gt;The overrides-exporter must be explicitly enabled.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-warning&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Warning&lt;/p&gt;&lt;p&gt;The metrics emitted by the overrides-exporter have high cardinality.
It&amp;rsquo;s recommended to run only a single replica of the overrides-exporter to limit that cardinality.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;With a &lt;code&gt;runtime.yaml&lt;/code&gt; file as follows:&lt;/p&gt;
&lt;!-- prettier-ignore-start --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;YAML&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-yaml&#34;&gt;# file: runtime.yaml
# In this example, we&amp;#39;re overriding ingestion limits for a single tenant.
overrides:
  &amp;#34;user1&amp;#34;:
    ingestion_burst_size: 350000
    ingestion_rate: 350000
    max_global_series_per_metric: 300000
    max_global_series_per_user: 300000&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;!-- prettier-ignore-end --&gt;
&lt;p&gt;Run the overrides-exporter by providing the &lt;code&gt;-target&lt;/code&gt;, and &lt;code&gt;-runtime-config.file&lt;/code&gt; flags:&lt;/p&gt;

&lt;div class=&#34;code-snippet code-snippet__mini&#34;&gt;&lt;div class=&#34;lang-toolbar__mini&#34;&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet code-snippet__border&#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-none&#34;&gt;mimir -target=overrides-exporter -runtime-config.file=runtime.yaml&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;After the overrides-exporter starts, you can to use &lt;code&gt;curl&lt;/code&gt; to inspect the tenant overrides:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;curl -s http://localhost:8080/metrics | grep cortex_limits_overrides&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The output metrics look similar to the following:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;console&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-console&#34;&gt;# HELP cortex_limits_overrides Resource limit overrides applied to tenants
# TYPE cortex_limits_overrides gauge
cortex_limits_overrides{limit_name=&amp;#34;ingestion_burst_size&amp;#34;,user=&amp;#34;user1&amp;#34;} 350000
cortex_limits_overrides{limit_name=&amp;#34;ingestion_rate&amp;#34;,user=&amp;#34;user1&amp;#34;} 350000
cortex_limits_overrides{limit_name=&amp;#34;max_global_series_per_metric&amp;#34;,user=&amp;#34;user1&amp;#34;} 300000
cortex_limits_overrides{limit_name=&amp;#34;max_global_series_per_user&amp;#34;,user=&amp;#34;user1&amp;#34;} 300000&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;With these metrics, you can set up alerts to know when tenants are close to hitting their limits
before they exceed them.&lt;/p&gt;
]]></content><description>&lt;h1 id="optional-grafana-mimir-overrides-exporter">(Optional) Grafana Mimir overrides-exporter&lt;/h1>
&lt;p>Grafana Mimir supports applying overrides on a per-tenant basis.
A number of overrides configure limits that prevent a single tenant from using too many resources.
The overrides-exporter component exposes limits as Prometheus metrics so that operators can understand how close tenants are to their limits.&lt;/p></description></item><item><title>(Optional) Grafana Mimir ruler</title><link>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/ruler/</link><pubDate>Wed, 03 Jun 2026 09:01:40 +0200</pubDate><guid>https://grafana.com/docs/mimir/v3.1.x/references/architecture/components/ruler/</guid><content><![CDATA[&lt;h1 id=&#34;optional-grafana-mimir-ruler&#34;&gt;(Optional) Grafana Mimir ruler&lt;/h1&gt;
&lt;p&gt;The ruler is an optional component that evaluates PromQL expressions defined in recording and alerting rules.
Each tenant has a set of recording and alerting rules and can group those rules into namespaces.&lt;/p&gt;
&lt;p&gt;Evaluating rules generates new samples. Those samples are then passed to an in-process &lt;a href=&#34;../distributor&#34;&gt;distributor&lt;/a&gt; to be ingested and made available for further queries.
Configuration of the built-in distributor uses &lt;a href=&#34;../../../../configure/configuration-parameters/#distributor&#34;&gt;its configuration parameters&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;operational-modes&#34;&gt;Operational modes&lt;/h2&gt;
&lt;p&gt;The ruler supports two different rule evaluation modes:&lt;/p&gt;
&lt;h3 id=&#34;internal&#34;&gt;Internal&lt;/h3&gt;
&lt;p&gt;This is the default mode. The ruler internally runs a querier, and evaluates recording and alerting rules in the ruler process itself.
To evaluate rules, the ruler connects directly to ingesters and store-gateways, and writes any resulting series to the ingesters.&lt;/p&gt;
&lt;p&gt;Configuration of the built-in querier uses &lt;a href=&#34;../../../../configure/configuration-parameters/#querier&#34;&gt;its configuration parameters&lt;/a&gt;.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;When you use the internal mode, the ruler uses no query acceleration techniques and the evaluation of very high cardinality queries could take longer than the evaluation interval, which may lead to missing data points in the evaluated recording rules.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;&lt;img
  class=&#34;lazyload d-inline-block&#34;
  data-src=&#34;ruler-internal.svg&#34;
  alt=&#34;Architecture of Grafana Mimir&amp;rsquo;s ruler component in internal mode&#34;/&gt;&lt;/p&gt;
&lt;h3 id=&#34;remote&#34;&gt;Remote&lt;/h3&gt;
&lt;p&gt;In this mode the ruler delegates rules evaluation to the query-frontend. When enabled, the ruler leverages all the query acceleration techniques employed by the query-frontend, such as &lt;a href=&#34;../../query-sharding/&#34;&gt;query sharding&lt;/a&gt;.
To enable the remote operational mode, set the &lt;code&gt;-ruler.query-frontend.address&lt;/code&gt; CLI flag or its respective YAML configuration parameter for the ruler.
Communication between ruler and query-frontend is established over gRPC, so you can make use of client-side load balancing by prefixing the query-frontend address URL with &lt;code&gt;dns:///&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img
  class=&#34;lazyload d-inline-block&#34;
  data-src=&#34;ruler-remote.svg&#34;
  alt=&#34;Architecture of Grafana Mimir&amp;rsquo;s ruler component in remote mode&#34;/&gt;&lt;/p&gt;
&lt;h3 id=&#34;remote-over-httphttps&#34;&gt;Remote over HTTP/HTTPS&lt;/h3&gt;
&lt;p&gt;When the query-frontend address set via the &lt;code&gt;-ruler.query-frontend.address&lt;/code&gt; CLI flag or its respective YAML configuration parameter starts with &lt;code&gt;http://&lt;/code&gt; or &lt;code&gt;https://&lt;/code&gt;, the ruler delegates rule evaluation to a Prometheus-compatible server. One use case for this feature is to use a proxy to federate data from multiple Mimir instances.&lt;/p&gt;
&lt;h2 id=&#34;recording-rules&#34;&gt;Recording rules&lt;/h2&gt;
&lt;p&gt;The ruler evaluates the expressions in the &lt;a href=&#34;https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/#recording-rules&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;recording rules&lt;/a&gt; at regular intervals and writes the results back to the ingesters.&lt;/p&gt;
&lt;h2 id=&#34;alerting-rules&#34;&gt;Alerting rules&lt;/h2&gt;
&lt;p&gt;The ruler evaluates the expressions in &lt;a href=&#34;https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/#alerting-rules&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;alerting rules&lt;/a&gt; at regular intervals and if the result includes any series, the alert becomes active.
If an alerting rule has a defined &lt;code&gt;for&lt;/code&gt; duration, it enters the &lt;strong&gt;PENDING&lt;/strong&gt; (&lt;code&gt;pending&lt;/code&gt;) state.
After the alert has been active for the entire &lt;code&gt;for&lt;/code&gt; duration, it enters the &lt;strong&gt;FIRING&lt;/strong&gt; (&lt;code&gt;firing&lt;/code&gt;) state.
The ruler then notifies Alertmanagers of any &lt;strong&gt;FIRING&lt;/strong&gt; (&lt;code&gt;firing&lt;/code&gt;) alerts.&lt;/p&gt;
&lt;p&gt;Configure the addresses of Alertmanagers with the &lt;code&gt;-ruler.alertmanager-url&lt;/code&gt; flag. This flag supports the DNS service discovery format.
For more information about DNS service discovery, refer to &lt;a href=&#34;../../../../configure/about-dns-service-discovery/&#34;&gt;Supported discovery modes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re using &lt;a href=&#34;../alertmanager/&#34;&gt;Mimir&amp;rsquo;s Alertmanager&lt;/a&gt;, point the address to Alertmanager&amp;rsquo;s API.
You can configure Alertmanager’s API prefix via the &lt;code&gt;-http.alertmanager-http-prefix&lt;/code&gt; flag, which defaults to &lt;code&gt;/alertmanager&lt;/code&gt;.
For example, if Alertmanager is listening at &lt;code&gt;http://mimir-alertmanager.namespace.svc.cluster.local&lt;/code&gt; and it is using the default API prefix, set &lt;code&gt;-ruler.alertmanager-url&lt;/code&gt; to &lt;code&gt;http://mimir-alertmanager.namespace.svc.cluster.local/alertmanager&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;federated-rule-groups&#34;&gt;Federated rule groups&lt;/h2&gt;
&lt;p&gt;A federated rule group is a rule group with a non-empty &lt;code&gt;source_tenants&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;source_tenants&lt;/code&gt; field allows aggregating data from multiple tenants while evaluating a rule group. The expressions
of each rule in the group will be evaluated against the data of all tenants in &lt;code&gt;source_tenants&lt;/code&gt;. If &lt;code&gt;source_tenants&lt;/code&gt; is
empty or omitted, then the tenant under which the group is created will be treated as the &lt;code&gt;source_tenant&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Below is an example of how a federated rule group would look like:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;YAML&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-yaml&#34;&gt;name: MyGroupName
source_tenants: [&amp;#34;tenant-a&amp;#34;, &amp;#34;tenant-b&amp;#34;]
rules:
  - record: sum:metric
    expr: sum(metric)&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;In this example &lt;code&gt;MyGroupName&lt;/code&gt; rules will be evaluated against &lt;code&gt;tenant-a&lt;/code&gt; and &lt;code&gt;tenant-b&lt;/code&gt; tenants.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Federated rule groups are skipped during evaluation by default. This feature depends on
the cross-tenant query federation feature. To enable federated rules
set &lt;code&gt;-ruler.tenant-federation.enabled=true&lt;/code&gt; and &lt;code&gt;-tenant-federation.enabled=true&lt;/code&gt; CLI flags (or their respective YAML
config options).&lt;/p&gt;
&lt;p&gt;During evaluation query limits applied to single tenants are also applied to each query in the rule group. For example,
if &lt;code&gt;tenant-a&lt;/code&gt; has a federated rule group with &lt;code&gt;source_tenants: [tenant-b, tenant-c]&lt;/code&gt;, then query limits for &lt;code&gt;tenant-b&lt;/code&gt;
and &lt;code&gt;tenant-c&lt;/code&gt; will be applied. If any of these limits is exceeded, the whole evaluation will fail. No partial results
will be saved. The same &amp;ldquo;no partial results&amp;rdquo; guarantee applies to queries failing for other reasons (e.g. ingester
unavailability).&lt;/p&gt;
&lt;p&gt;The time series used during evaluation of federated rules will have the &lt;code&gt;__tenant_id__&lt;/code&gt; label, similar to how it is
present on series returned with cross-tenant query federation.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;Federated rule groups allow data from multiple source tenants to be written into a single destination tenant.
This makes the separation of tenants&amp;rsquo; data less clear.&lt;/p&gt;
&lt;p&gt;For example, &lt;code&gt;tenant-a&lt;/code&gt; has a federated rule group that aggregates over &lt;code&gt;tenant-b&lt;/code&gt;&amp;rsquo;s data like &lt;code&gt;sum(metric_b)&lt;/code&gt; and writes the result back into &lt;code&gt;tenant-a&lt;/code&gt;&amp;rsquo;s storage as the metric &lt;code&gt;sum:metric_b&lt;/code&gt;.
Now &lt;code&gt;tenant-a&lt;/code&gt; contains some of &lt;code&gt;tenant-b&lt;/code&gt;&amp;rsquo;s data.&lt;/p&gt;
&lt;p&gt;Have this in mind when configuring the access control layer in front of Mimir and when enabling federated rules via &lt;code&gt;-ruler.tenant-federation.enabled&lt;/code&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h2 id=&#34;sharding&#34;&gt;Sharding&lt;/h2&gt;
&lt;p&gt;The ruler supports multi-tenancy and horizontal scalability.
To achieve horizontal scalability, the ruler shards the execution of rules by rule groups.
Ruler replicas form their own &lt;a href=&#34;../../hash-ring/&#34;&gt;hash ring&lt;/a&gt; stored in the &lt;a href=&#34;../../key-value-store/&#34;&gt;KV store&lt;/a&gt; to divide the work of the executing rules.&lt;/p&gt;
&lt;p&gt;To configure the rulers&amp;rsquo; hash ring, refer to &lt;a href=&#34;../../../../configure/configure-hash-rings/&#34;&gt;configuring hash rings&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;manage-alerting-and-recording-rules&#34;&gt;Manage alerting and recording rules&lt;/h2&gt;
&lt;p&gt;There is more than one way to manage alerting and recording rules.&lt;/p&gt;
&lt;h3 id=&#34;via-the-mimirtool-cli-tool&#34;&gt;Via the &lt;code&gt;mimirtool&lt;/code&gt; CLI tool&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;mimirtool rules&lt;/code&gt; command offers utility subcommands for linting, formatting, and uploading rules to Grafana Mimir.
For more information, refer to the &lt;a href=&#34;../../../../manage/tools/mimirtool/#rules&#34;&gt;&lt;code&gt;mimirtool rules&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;via-the-grafanamimiroperationsmimir-rules-action-github-action&#34;&gt;Via the &lt;code&gt;grafana/mimir/operations/mimir-rules-action&lt;/code&gt; GitHub Action&lt;/h3&gt;
&lt;p&gt;The GitHub Action &lt;code&gt;mimir-rules-action&lt;/code&gt; wraps some of the functionality of &lt;code&gt;mimirtool rules&lt;/code&gt;.
For more information, refer to the &lt;a href=&#34;https://github.com/grafana/mimir/blob/main/operations/mimir-rules-action/README.md&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;documentation of the action&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;via-the-http-configuration-api&#34;&gt;Via the HTTP configuration API&lt;/h3&gt;
&lt;p&gt;The ruler HTTP configuration API enables tenants to create, update, and delete rule groups.
For a complete list of endpoints and example requests, refer to &lt;a href=&#34;../../../http-api/#ruler&#34;&gt;ruler&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;state&#34;&gt;State&lt;/h2&gt;
&lt;p&gt;The ruler uses the backend configured via &lt;code&gt;-ruler-storage.backend&lt;/code&gt;.
The ruler supports the following backends:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://aws.amazon.com/s3&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Amazon S3&lt;/a&gt;: &lt;code&gt;-ruler-storage.backend=s3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://cloud.google.com/storage/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Google Cloud Storage&lt;/a&gt;: &lt;code&gt;-ruler-storage.backend=gcs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://azure.microsoft.com/en-us/services/storage/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Microsoft Azure Storage&lt;/a&gt;: &lt;code&gt;-ruler-storage.backend=azure&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://wiki.openstack.org/wiki/Swift&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;OpenStack Swift&lt;/a&gt;: &lt;code&gt;-ruler-storage.backend=swift&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#local-storage&#34;&gt;Local storage&lt;/a&gt;: &lt;code&gt;-ruler-storage.backend=local&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;local-storage&#34;&gt;Local storage&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;local&lt;/code&gt; storage backend reads &lt;a href=&#34;https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Prometheus recording rules&lt;/a&gt; from the local filesystem.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;Local storage is a read-only backend that doesn&amp;rsquo;t support the creation and deletion of rules through the &lt;a href=&#34;#via-the-http-configuration-api&#34;&gt;Configuration API&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;When all rulers have the same rule files, local storage supports ruler sharding.
To facilitate sharding in Kubernetes, mount a &lt;a href=&#34;https://kubernetes.io/docs/concepts/configuration/configmap/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Kubernetes ConfigMap&lt;/a&gt; into every ruler pod.&lt;/p&gt;
&lt;p&gt;The following example shows a local storage definition:&lt;/p&gt;

&lt;div class=&#34;code-snippet code-snippet__mini&#34;&gt;&lt;div class=&#34;lang-toolbar__mini&#34;&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet code-snippet__border&#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-none&#34;&gt;-ruler-storage.backend=local
-ruler-storage.local.directory=/tmp/rules&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The ruler looks for tenant rules in the &lt;code&gt;/tmp/rules/&amp;lt;TENANT ID&amp;gt;&lt;/code&gt; directory.
The ruler requires rule files to be in the &lt;a href=&#34;https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/#recording-rules&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Prometheus format&lt;/a&gt;.&lt;/p&gt;
]]></content><description>&lt;h1 id="optional-grafana-mimir-ruler">(Optional) Grafana Mimir ruler&lt;/h1>
&lt;p>The ruler is an optional component that evaluates PromQL expressions defined in recording and alerting rules.
Each tenant has a set of recording and alerting rules and can group those rules into namespaces.&lt;/p></description></item></channel></rss>