diff --git a/CHANGELOG.md b/CHANGELOG.md index e061f082e65..0bf32df4d62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ * [CHANGE] Query-frontend: Remove deprecated `frontend.align_queries_with_step` YAML configuration. The configuration option has been moved to per-tenant and default `limits` since Mimir 2.12. #8733 #8735 * [CHANGE] Store-gateway: Change default of `-blocks-storage.bucket-store.max-concurrent` to 200. #8768 * [CHANGE] Added new metric `cortex_compactor_disk_out_of_space_errors_total` which counts how many times a compaction failed due to the compactor being out of disk, alert if there is a single increase. #8237 #8278 +* [CHANGE] Store-gateway: Remove experimental parameter `-blocks-storage.bucket-store.series-selection-strategy`. The default strategy is now `worst-case`. #8702 +* [CHANGE] Store-gateway: Rename `-blocks-storage.bucket-store.series-selection-strategies.worst-case-series-preference` to `-blocks-storage.bucket-store.series-fetch-preference` and promote to stable. #8702 +* [CHANGE] Querier, store-gateway: remove deprecated `-querier.prefer-streaming-chunks-from-store-gateways=true`. Streaming from store-gateways is now always enabled. #8696 +* [CHANGE] Ingester: remove deprecated `-ingester.return-only-grpc-errors`. #8699 * [FEATURE] Querier: add experimental streaming PromQL engine, enabled with `-querier.query-engine=mimir`. #8422 #8430 #8454 #8455 #8360 #8490 #8508 #8577 #8671 * [FEATURE] Experimental Kafka-based ingest storage. #6888 #6894 #6929 #6940 #6951 #6974 #6982 #7029 #7030 #7091 #7142 #7147 #7148 #7153 #7160 #7193 #7349 #7376 #7388 #7391 #7393 #7394 #7402 #7404 #7423 #7424 #7437 #7486 #7503 #7508 #7540 #7621 #7682 #7685 #7694 #7695 #7696 #7697 #7701 #7733 #7734 #7741 #7752 #7838 #7851 #7871 #7877 #7880 #7882 #7887 #7891 #7925 #7955 #7967 #8031 #8063 #8077 #8088 #8135 #8176 #8184 #8194 #8216 #8217 #8222 #8233 #8503 #8542 #8579 #8657 #8686 #8688 #8703 #8706 #8708 #8738 #8750 * What it is: @@ -67,7 +71,10 @@ * Overview dashboard: status, read/write latency and queries/ingestion per sec panels, `cortex_request_duration_seconds` metric. #7674 #8502 #8791 * Writes dashboard: `cortex_request_duration_seconds` metric. #8757 #8791 * Reads dashboard: `cortex_request_duration_seconds` metric. #8752 - * Rollout progress dashboard. #8779 + * Rollout progress dashboard: `cortex_request_duration_seconds` metric. #8779 + * Alertmanager dashboard: `cortex_request_duration_seconds` metric. #8792 + * Ruler dashboard: `cortex_request_duration_seconds` metric. #8795 + * Queries dashboard: `cortex_request_duration_seconds` metric. #8800 * Remote ruler reads dashboard: `cortex_request_duration_seconds` metric. * [ENHANCEMENT] Alerts: `MimirRunningIngesterReceiveDelayTooHigh` alert has been tuned to be more reactive to high receive delay. #8538 * [ENHANCEMENT] Dashboards: improve end-to-end latency and strong read consistency panels when experimental ingest storage is enabled. #8543 @@ -75,6 +82,8 @@ * [ENHANCEMENT] Dashboards: add panels to show writes to experimental ingest storage backend in the "Mimir / Ruler" dashboard, when `_config.show_ingest_storage_panels` is enabled. #8732 * [ENHANCEMENT] Dashboards: show all series in tooltips on time series dashboard panels. #8748 * [ENHANCEMENT] Dashboards: add compactor autoscaling panels to "Mimir / Compactor" dashboard. The panels are disabled by default, but can be enabled setting `_config.autoscaling.compactor.enabled` to `true`. #8777 +* [ENHANCEMENT] Alerts: added `MimirKafkaClientBufferedProduceBytesTooHigh` alert. #8763 +* [ENHANCEMENT] Dashboards: added "Kafka produced records / sec" panel to "Mimir / Writes" dashboard. #8763 * [BUGFIX] Dashboards: fix "current replicas" in autoscaling panels when HPA is not active. #8566 * [BUGFIX] Alerts: do not fire `MimirRingMembersMismatch` during the migration to experimental ingest storage. #8727 @@ -94,6 +103,12 @@ ### Mimirtool * [CHANGE] Analyze Rules: Count recording rules used in rules group as used. #6133 +* [CHANGE] Remove deprecated `--rule-files` flag in favor of CLI arguments for the following commands: #8701 + * `mimirtool rules load` + * `mimirtool rules sync` + * `mimirtool rules diff` + * `mimirtool rules check` + * `mimirtool rules prepare` ### Mimir Continuous Test diff --git a/cmd/mimir/config-descriptor.json b/cmd/mimir/config-descriptor.json index f40a9a62e04..5881fade08e 100644 --- a/cmd/mimir/config-descriptor.json +++ b/cmd/mimir/config-descriptor.json @@ -1865,17 +1865,6 @@ "fieldType": "boolean", "fieldCategory": "advanced" }, - { - "kind": "field", - "name": "prefer_streaming_chunks_from_store_gateways", - "required": false, - "desc": "Request store-gateways stream chunks. Store-gateways will only respond with a stream of chunks if the target store-gateway supports this, and this preference will be ignored by store-gateways that do not support this.", - "fieldValue": null, - "fieldDefaultValue": true, - "fieldFlag": "querier.prefer-streaming-chunks-from-store-gateways", - "fieldType": "boolean", - "fieldCategory": "experimental" - }, { "kind": "field", "name": "streaming_chunks_per_ingester_series_buffer_size", @@ -3469,17 +3458,6 @@ "fieldType": "int", "fieldCategory": "advanced" }, - { - "kind": "field", - "name": "return_only_grpc_errors", - "required": false, - "desc": "When enabled only gRPC errors will be returned by the ingester.", - "fieldValue": null, - "fieldDefaultValue": true, - "fieldFlag": "ingester.return-only-grpc-errors", - "fieldType": "boolean", - "fieldCategory": "deprecated" - }, { "kind": "field", "name": "use_ingester_owned_series_for_limits", @@ -9492,35 +9470,14 @@ }, { "kind": "field", - "name": "series_selection_strategy", - "required": false, - "desc": "This option controls the strategy to selection of series and deferring application of matchers. A more aggressive strategy will fetch less posting lists at the cost of more series. This is useful when querying large blocks in which many series share the same label name and value. Supported values (most aggressive to least aggressive): speculative, worst-case, worst-case-small-posting-lists, all.", - "fieldValue": null, - "fieldDefaultValue": "worst-case", - "fieldFlag": "blocks-storage.bucket-store.series-selection-strategy", - "fieldType": "string", - "fieldCategory": "experimental" - }, - { - "kind": "block", - "name": "series_selection_strategies", + "name": "series_fetch_preference", "required": false, - "desc": "", - "blockEntries": [ - { - "kind": "field", - "name": "worst_case_series_preference", - "required": false, - "desc": "This option is only used when blocks-storage.bucket-store.series-selection-strategy=worst-case. Increasing the series preference results in fetching more series than postings. Must be a positive floating point number.", - "fieldValue": null, - "fieldDefaultValue": 0.75, - "fieldFlag": "blocks-storage.bucket-store.series-selection-strategies.worst-case-series-preference", - "fieldType": "float", - "fieldCategory": "experimental" - } - ], + "desc": "This parameter controls the trade-off in fetching series versus fetching postings to fulfill a series request. Increasing the series preference results in fetching more series and reducing the volume of postings fetched. Reducing the series preference results in the opposite. Increase this parameter to reduce the rate of fetched series bytes (see \"Mimir / Queries\" dashboard) or API calls to the object store. Must be a positive floating point number.", "fieldValue": null, - "fieldDefaultValue": null + "fieldDefaultValue": 0.75, + "fieldFlag": "blocks-storage.bucket-store.series-fetch-preference", + "fieldType": "float", + "fieldCategory": "advanced" } ], "fieldValue": null, diff --git a/cmd/mimir/help-all.txt.tmpl b/cmd/mimir/help-all.txt.tmpl index ab36ea1c1dd..2f7c5e61d2c 100644 --- a/cmd/mimir/help-all.txt.tmpl +++ b/cmd/mimir/help-all.txt.tmpl @@ -671,12 +671,10 @@ Usage of ./cmd/mimir/mimir: Max size - in bytes - of a gap for which the partitioner aggregates together two bucket GET object requests. (default 524288) -blocks-storage.bucket-store.posting-offsets-in-mem-sampling int Controls what is the ratio of postings offsets that the store will hold in memory. (default 32) + -blocks-storage.bucket-store.series-fetch-preference float + This parameter controls the trade-off in fetching series versus fetching postings to fulfill a series request. Increasing the series preference results in fetching more series and reducing the volume of postings fetched. Reducing the series preference results in the opposite. Increase this parameter to reduce the rate of fetched series bytes (see "Mimir / Queries" dashboard) or API calls to the object store. Must be a positive floating point number. (default 0.75) -blocks-storage.bucket-store.series-hash-cache-max-size-bytes uint Max size - in bytes - of the in-memory series hash cache. The cache is shared across all tenants and it's used only when query sharding is enabled. (default 1073741824) - -blocks-storage.bucket-store.series-selection-strategies.worst-case-series-preference float - [experimental] This option is only used when blocks-storage.bucket-store.series-selection-strategy=worst-case. Increasing the series preference results in fetching more series than postings. Must be a positive floating point number. (default 0.75) - -blocks-storage.bucket-store.series-selection-strategy string - [experimental] This option controls the strategy to selection of series and deferring application of matchers. A more aggressive strategy will fetch less posting lists at the cost of more series. This is useful when querying large blocks in which many series share the same label name and value. Supported values (most aggressive to least aggressive): speculative, worst-case, worst-case-small-posting-lists, all. (default "worst-case") -blocks-storage.bucket-store.sync-dir string Directory to store synchronized TSDB index headers. This directory is not required to be persisted between restarts, but it's highly recommended in order to improve the store-gateway startup time. (default "./tsdb-sync/") -blocks-storage.bucket-store.sync-interval duration @@ -1553,8 +1551,6 @@ Usage of ./cmd/mimir/mimir: [experimental] CPU utilization limit, as CPU cores, for CPU/memory utilization based read request limiting. Use 0 to disable it. -ingester.read-path-memory-utilization-limit uint [experimental] Memory limit, in bytes, for CPU/memory utilization based read request limiting. Use 0 to disable it. - -ingester.return-only-grpc-errors - [deprecated] When enabled only gRPC errors will be returned by the ingester. (default true) -ingester.ring.consul.acl-token string ACL Token used to interact with Consul. -ingester.ring.consul.cas-retry-delay duration @@ -1913,8 +1909,6 @@ Usage of ./cmd/mimir/mimir: If true, when querying ingesters, only the minimum required ingesters required to reach quorum will be queried initially, with other ingesters queried only if needed due to failures from the initial set of ingesters. Enabling this option reduces resource consumption for the happy path at the cost of increased latency for the unhappy path. (default true) -querier.minimize-ingester-requests-hedging-delay duration Delay before initiating requests to further ingesters when request minimization is enabled and the initially selected set of ingesters have not all responded. Ignored if -querier.minimize-ingester-requests is not enabled. (default 3s) - -querier.prefer-streaming-chunks-from-store-gateways - [experimental] Request store-gateways stream chunks. Store-gateways will only respond with a stream of chunks if the target store-gateway supports this, and this preference will be ignored by store-gateways that do not support this. (default true) -querier.promql-experimental-functions-enabled [experimental] Enable experimental PromQL functions. This config option should be set on query-frontend too when query sharding is enabled. -querier.query-engine string diff --git a/docs/sources/mimir/configure/about-versioning.md b/docs/sources/mimir/configure/about-versioning.md index adbea3c54c6..8a93facca6b 100644 --- a/docs/sources/mimir/configure/about-versioning.md +++ b/docs/sources/mimir/configure/about-versioning.md @@ -146,7 +146,6 @@ The following features are currently experimental: - `-ingester.client.circuit-breaker.cooldown-period` - Querier - Use of Redis cache backend (`-blocks-storage.bucket-store.metadata-cache.backend=redis`) - - Streaming chunks from store-gateway to querier (`-querier.prefer-streaming-chunks-from-store-gateways`) - Limiting queries based on the estimated number of chunks that will be used (`-querier.max-estimated-fetched-chunks-per-query-multiplier`) - Max concurrency for tenant federated queries (`-tenant-federation.max-concurrent`) - Maximum response size for active series queries (`-querier.active-series-results-max-size-bytes`) @@ -167,7 +166,6 @@ The following features are currently experimental: - `-query-scheduler.querier-forget-delay` - Store-gateway - Use of Redis cache backend (`-blocks-storage.bucket-store.chunks-cache.backend=redis`, `-blocks-storage.bucket-store.index-cache.backend=redis`, `-blocks-storage.bucket-store.metadata-cache.backend=redis`) - - `-blocks-storage.bucket-store.series-selection-strategy` - Eagerly loading some blocks on startup even when lazy loading is enabled `-blocks-storage.bucket-store.index-header.eager-loading-startup-enabled` - Read-write deployment mode - API endpoints: @@ -212,14 +210,8 @@ For details about what _deprecated_ means, see [Parameter lifecycle]({{< relref The following features or configuration parameters are currently deprecated and will be **removed in Mimir 2.14**: -- Ingester - - `-ingester.return-only-grpc-errors` - Ingester client - `-ingester.client.report-grpc-codes-in-instrumentation-label-enabled` -- Mimirtool - - the flag `--rule-files` -- Querier - - the flag `-querier.prefer-streaming-chunks-from-store-gateways` The following features or configuration parameters are currently deprecated and will be **removed in a future release (to be announced)**: diff --git a/docs/sources/mimir/configure/configuration-parameters/index.md b/docs/sources/mimir/configure/configuration-parameters/index.md index 23492cd634a..63dee6ddd2a 100644 --- a/docs/sources/mimir/configure/configuration-parameters/index.md +++ b/docs/sources/mimir/configure/configuration-parameters/index.md @@ -1265,10 +1265,6 @@ instance_limits: # CLI flag: -ingester.error-sample-rate [error_sample_rate: | default = 10] -# (deprecated) When enabled only gRPC errors will be returned by the ingester. -# CLI flag: -ingester.return-only-grpc-errors -[return_only_grpc_errors: | default = true] - # (experimental) When enabled, only series currently owned by ingester according # to the ring are used when checking user per-tenant series limit. # CLI flag: -ingester.use-ingester-owned-series-for-limits @@ -1452,12 +1448,6 @@ store_gateway_client: # CLI flag: -querier.shuffle-sharding-ingesters-enabled [shuffle_sharding_ingesters_enabled: | default = true] -# (experimental) Request store-gateways stream chunks. Store-gateways will only -# respond with a stream of chunks if the target store-gateway supports this, and -# this preference will be ignored by store-gateways that do not support this. -# CLI flag: -querier.prefer-streaming-chunks-from-store-gateways -[prefer_streaming_chunks_from_store_gateways: | default = true] - # (advanced) Number of series to buffer per ingester when streaming chunks from # ingesters. # CLI flag: -querier.streaming-chunks-per-ingester-buffer-size @@ -4151,22 +4141,15 @@ bucket_store: # CLI flag: -blocks-storage.bucket-store.batch-series-size [streaming_series_batch_size: | default = 5000] - # (experimental) This option controls the strategy to selection of series and - # deferring application of matchers. A more aggressive strategy will fetch - # less posting lists at the cost of more series. This is useful when querying - # large blocks in which many series share the same label name and value. - # Supported values (most aggressive to least aggressive): speculative, - # worst-case, worst-case-small-posting-lists, all. - # CLI flag: -blocks-storage.bucket-store.series-selection-strategy - [series_selection_strategy: | default = "worst-case"] - - series_selection_strategies: - # (experimental) This option is only used when - # blocks-storage.bucket-store.series-selection-strategy=worst-case. - # Increasing the series preference results in fetching more series than - # postings. Must be a positive floating point number. - # CLI flag: -blocks-storage.bucket-store.series-selection-strategies.worst-case-series-preference - [worst_case_series_preference: | default = 0.75] + # (advanced) This parameter controls the trade-off in fetching series versus + # fetching postings to fulfill a series request. Increasing the series + # preference results in fetching more series and reducing the volume of + # postings fetched. Reducing the series preference results in the opposite. + # Increase this parameter to reduce the rate of fetched series bytes (see + # "Mimir / Queries" dashboard) or API calls to the object store. Must be a + # positive floating point number. + # CLI flag: -blocks-storage.bucket-store.series-fetch-preference + [series_fetch_preference: | default = 0.75] tsdb: # Directory to store TSDBs (including WAL) in the ingesters. This directory is diff --git a/docs/sources/mimir/manage/mimir-runbooks/_index.md b/docs/sources/mimir/manage/mimir-runbooks/_index.md index a4e55b831d4..6987cc0d7e9 100644 --- a/docs/sources/mimir/manage/mimir-runbooks/_index.md +++ b/docs/sources/mimir/manage/mimir-runbooks/_index.md @@ -1485,6 +1485,24 @@ How to **investigate**: - Check if ingesters are processing too many records, and they need to be scaled up (vertically or horizontally). - Check actual error in logs to see whether the `-ingest-storage.kafka.wait-strong-read-consistency-timeout` or the request timeout has been hit first. +### MimirKafkaClientBufferedProduceBytesTooHigh + +This alert fires when the Kafka client buffer, used to write incoming write requests to Kafka, is getting full. + +How it **works**: + +- Distributor and ruler encapsulate write requests into Kafka records and send them to Kafka. +- The Kafka client has a limit on the total byte size of buffered records either sent to Kafka or sent to Kafka but not acknowledged yet. +- When the limit is reached, the Kafka client stops producing more records and fast fails. +- The limit is configured via `-ingest-storage.kafka.producer-max-buffered-bytes`. +- The default limit is configured intentionally high, so that when the buffer utilization gets close to the limit, this indicates that there's probably an issue. + +How to **investigate**: + +- Query `cortex_ingest_storage_writer_buffered_produce_bytes{quantile="1.0"}` metrics to see the actual buffer utilization peaks. + - If the high buffer utilization is isolated to a small set of pods, then there might be an issue in the client pods. + - If the high buffer utilization is spread across all or most pods, then there might be an issue in Kafka. + ### Ingester is overloaded when consuming from Kafka This runbook covers the case an ingester is overloaded when ingesting metrics data (consuming) from Kafka. diff --git a/go.mod b/go.mod index 138e2d7b878..423317181e6 100644 --- a/go.mod +++ b/go.mod @@ -20,11 +20,11 @@ require ( github.com/golang/snappy v0.0.4 github.com/google/gopacket v1.1.19 github.com/gorilla/mux v1.8.1 - github.com/grafana/dskit v0.0.0-20240718080635-f5bd38371e1c + github.com/grafana/dskit v0.0.0-20240719153732-6e8a03e781de github.com/grafana/e2e v0.1.2-0.20240118170847-db90b84177fc github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/json-iterator/go v1.1.12 - github.com/minio/minio-go/v7 v7.0.72 + github.com/minio/minio-go/v7 v7.0.74 github.com/mitchellh/go-wordwrap v1.0.1 github.com/oklog/ulid v1.3.1 github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e @@ -102,6 +102,7 @@ require ( github.com/Masterminds/sprig/v3 v3.2.1 // indirect github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 // indirect github.com/cenkalti/backoff/v3 v3.2.2 // indirect + github.com/go-ini/ini v1.67.0 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-test/deep v1.1.0 // indirect github.com/goccy/go-json v0.10.3 // indirect @@ -160,7 +161,6 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.13.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect - github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect @@ -270,7 +270,6 @@ require ( google.golang.org/genproto v0.0.0-20240528184218-531527333157 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d - gopkg.in/ini.v1 v1.67.0 // indirect k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/go.sum b/go.sum index 7c729100658..e2cb3045101 100644 --- a/go.sum +++ b/go.sum @@ -101,8 +101,6 @@ github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jB github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OneOfOne/xxhash v1.2.6 h1:U68crOE3y3MPttCMQGywZOLrTeF5HHJ3/vDBCJn9/bA= -github.com/OneOfOne/xxhash v1.2.6/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink= github.com/alecthomas/assert/v2 v2.2.1/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= @@ -182,7 +180,6 @@ github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4r github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -306,6 +303,8 @@ github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3Bop github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= +github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= @@ -515,8 +514,8 @@ github.com/grafana-tools/sdk v0.0.0-20220919052116-6562121319fc h1:PXZQA2WCxe85T github.com/grafana-tools/sdk v0.0.0-20220919052116-6562121319fc/go.mod h1:AHHlOEv1+GGQ3ktHMlhuTUwo3zljV3QJbC0+8o2kn+4= github.com/grafana/alerting v0.0.0-20240708204730-284b8fe16cff h1:okOj0w7kyIfrENSFGVXTjn3aSiS2QUcqwDozQkoKdH0= github.com/grafana/alerting v0.0.0-20240708204730-284b8fe16cff/go.mod h1:DLj8frbtCaITljC2jc0L85JQViPF3mPfOSiYhm1osso= -github.com/grafana/dskit v0.0.0-20240718080635-f5bd38371e1c h1:rKnsl5RKCI7kFC3ORBZLYwS6AulFpJ3yv6c0pSH7aKQ= -github.com/grafana/dskit v0.0.0-20240718080635-f5bd38371e1c/go.mod h1:UA1BG0yY/B7lTcdeqoud+3/TglKmPL88OM5qCeRs8BU= +github.com/grafana/dskit v0.0.0-20240719153732-6e8a03e781de h1:wrFSxd0CUyluyAPfWpVipKSLZDsTYqrCArS4TrQzGpQ= +github.com/grafana/dskit v0.0.0-20240719153732-6e8a03e781de/go.mod h1:lcjGB6SuaZ2o44A9nD6p/tR4QXSPbzViRY520Gy6pTQ= github.com/grafana/e2e v0.1.2-0.20240118170847-db90b84177fc h1:BW+LjKJDz0So5LI8UZfW5neWeKpSkWqhmGjQFzcFfLM= github.com/grafana/e2e v0.1.2-0.20240118170847-db90b84177fc/go.mod h1:JVmqPBe8A/pZWwRoJW5ZjyALeY5OXMzPl7LrVXOdZAI= github.com/grafana/goautoneg v0.0.0-20240607115440-f335c04c58ce h1:WI1olbgS+sEl77qxEYbmt9TgRUz7iLqmjh8lYPpGlKQ= @@ -721,8 +720,8 @@ github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= -github.com/minio/minio-go/v7 v7.0.72 h1:ZSbxs2BfJensLyHdVOgHv+pfmvxYraaUy07ER04dWnA= -github.com/minio/minio-go/v7 v7.0.72/go.mod h1:4yBA8v80xGA30cfM3fz0DKYMXunWl/AV/6tWEs9ryzo= +github.com/minio/minio-go/v7 v7.0.74 h1:fTo/XlPBTSpo3BAMshlwKL5RspXRv9us5UeHEGYCFe0= +github.com/minio/minio-go/v7 v7.0.74/go.mod h1:qydcVzV8Hqtj1VtEocfxbmVFa2siu6HGa+LDEPogjD8= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= @@ -891,8 +890,6 @@ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg= github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= -github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= diff --git a/integration/querier_test.go b/integration/querier_test.go index 1f19bbb46f8..ba26267d8a7 100644 --- a/integration/querier_test.go +++ b/integration/querier_test.go @@ -28,22 +28,14 @@ import ( ) func TestQuerierWithBlocksStorageRunningInMicroservicesMode(t *testing.T) { - for _, streamingEnabled := range []bool{true, false} { - t.Run(fmt.Sprintf("streaming=%t", streamingEnabled), func(t *testing.T) { - testQuerierWithBlocksStorageRunningInMicroservicesMode(t, streamingEnabled, generateFloatSeries) - }) - } + testQuerierWithBlocksStorageRunningInMicroservicesMode(t, generateFloatSeries) } func TestQuerierWithBlocksStorageRunningInMicroservicesModeWithHistograms(t *testing.T) { - for _, streamingEnabled := range []bool{true, false} { - t.Run(fmt.Sprintf("streaming=%t", streamingEnabled), func(t *testing.T) { - testQuerierWithBlocksStorageRunningInMicroservicesMode(t, streamingEnabled, generateHistogramSeries) - }) - } + testQuerierWithBlocksStorageRunningInMicroservicesMode(t, generateHistogramSeries) } -func testQuerierWithBlocksStorageRunningInMicroservicesMode(t *testing.T, streamingEnabled bool, seriesGenerator func(name string, ts time.Time, additionalLabels ...prompb.Label) (series []prompb.TimeSeries, vector model.Vector, matrix model.Matrix)) { +func testQuerierWithBlocksStorageRunningInMicroservicesMode(t *testing.T, seriesGenerator func(name string, ts time.Time, additionalLabels ...prompb.Label) (series []prompb.TimeSeries, vector model.Vector, matrix model.Matrix)) { tests := map[string]struct { tenantShardSize int indexCacheBackend string @@ -158,7 +150,6 @@ func testQuerierWithBlocksStorageRunningInMicroservicesMode(t *testing.T, stream "-store-gateway.tenant-shard-size": fmt.Sprintf("%d", testCfg.tenantShardSize), "-query-frontend.query-stats-enabled": "true", "-query-frontend.parallelize-shardable-queries": strconv.FormatBool(testCfg.queryShardingEnabled), - "-querier.prefer-streaming-chunks-from-store-gateways": strconv.FormatBool(streamingEnabled), }) // Start store-gateways. @@ -234,21 +225,15 @@ func testQuerierWithBlocksStorageRunningInMicroservicesMode(t *testing.T, stream // Make sure the querier is using the bucket index blocks finder. require.NoError(t, querier.WaitSumMetrics(e2e.Greater(0), "cortex_bucket_index_loads_total")) - comparingFunction := e2e.Equals - if streamingEnabled { - // Some metrics can be higher when streaming is enabled. The exact number is not deterministic in every case. - comparingFunction = e2e.GreaterOrEqual - } - // Check the in-memory index cache metrics (in the store-gateway). - require.NoError(t, storeGateways.WaitSumMetrics(comparingFunction(9), "thanos_store_index_cache_requests_total")) // 5 + 2 + 2 - require.NoError(t, storeGateways.WaitSumMetrics(comparingFunction(0), "thanos_store_index_cache_hits_total")) // no cache hit cause the cache was empty + require.NoError(t, storeGateways.WaitSumMetrics(e2e.Equals(9), "thanos_store_index_cache_requests_total")) // 5 + 2 + 2 + require.NoError(t, storeGateways.WaitSumMetrics(e2e.Equals(0), "thanos_store_index_cache_hits_total")) // no cache hit cause the cache was empty if testCfg.indexCacheBackend == tsdb.IndexCacheBackendInMemory { require.NoError(t, storeGateways.WaitSumMetrics(e2e.Equals(2*2+2+3), "thanos_store_index_cache_items")) // 2 series both for postings and series cache, 2 expanded postings on one block, 3 on another one require.NoError(t, storeGateways.WaitSumMetrics(e2e.Equals(2*2+2+3), "thanos_store_index_cache_items_added_total")) // 2 series both for postings and series cache, 2 expanded postings on one block, 3 on another one } else if testCfg.indexCacheBackend == tsdb.IndexCacheBackendMemcached { - require.NoError(t, storeGateways.WaitSumMetrics(comparingFunction(9*2), "thanos_cache_operations_total")) // one set for each get + require.NoError(t, storeGateways.WaitSumMetrics(e2e.Equals(9*2), "thanos_cache_operations_total")) // one set for each get } // Query back again the 1st series from storage. This time it should use the index cache. @@ -258,14 +243,14 @@ func testQuerierWithBlocksStorageRunningInMicroservicesMode(t *testing.T, stream assert.Equal(t, expectedVector1, result.(model.Vector)) expectedFetchedSeries++ // Storage only. - require.NoError(t, storeGateways.WaitSumMetrics(comparingFunction(9+2), "thanos_store_index_cache_requests_total")) - require.NoError(t, storeGateways.WaitSumMetrics(comparingFunction(2), "thanos_store_index_cache_hits_total")) // this time has used the index cache + require.NoError(t, storeGateways.WaitSumMetrics(e2e.Equals(9+2), "thanos_store_index_cache_requests_total")) + require.NoError(t, storeGateways.WaitSumMetrics(e2e.Equals(2), "thanos_store_index_cache_hits_total")) // this time has used the index cache if testCfg.indexCacheBackend == tsdb.IndexCacheBackendInMemory { require.NoError(t, storeGateways.WaitSumMetrics(e2e.Equals(2*2+2+3), "thanos_store_index_cache_items")) // as before require.NoError(t, storeGateways.WaitSumMetrics(e2e.Equals(2*2+2+3), "thanos_store_index_cache_items_added_total")) // as before } else if testCfg.indexCacheBackend == tsdb.IndexCacheBackendMemcached { - require.NoError(t, storeGateways.WaitSumMetrics(comparingFunction(9*2+2), "thanos_cache_operations_total")) // as before + 2 gets (expanded postings and series) + require.NoError(t, storeGateways.WaitSumMetrics(e2e.Equals(9*2+2), "thanos_cache_operations_total")) // as before + 2 gets (expanded postings and series) } // Query range. We expect 1 data point with a value of 3 (number of series). @@ -899,82 +884,77 @@ func TestQuerierWithBlocksStorageOnMissingBlocksFromStorage(t *testing.T) { func TestQueryLimitsWithBlocksStorageRunningInMicroServices(t *testing.T) { const blockRangePeriod = 5 * time.Second - for _, streamingEnabled := range []bool{true, false} { - t.Run(fmt.Sprintf("store-gateway streaming enabled: %v", streamingEnabled), func(t *testing.T) { - s, err := e2e.NewScenario(networkName) - require.NoError(t, err) - defer s.Close() + s, err := e2e.NewScenario(networkName) + require.NoError(t, err) + defer s.Close() - // Configure the blocks storage to frequently compact TSDB head - // and ship blocks to the storage. - flags := mergeFlags(BlocksStorageFlags(), BlocksStorageS3Flags(), map[string]string{ - "-blocks-storage.tsdb.block-ranges-period": blockRangePeriod.String(), - "-blocks-storage.tsdb.ship-interval": "1s", - "-blocks-storage.bucket-store.sync-interval": "1s", - "-blocks-storage.tsdb.retention-period": ((blockRangePeriod * 2) - 1).String(), - "-querier.max-fetched-series-per-query": "3", - "-querier.prefer-streaming-chunks-from-store-gateways": strconv.FormatBool(streamingEnabled), - }) + // Configure the blocks storage to frequently compact TSDB head + // and ship blocks to the storage. + flags := mergeFlags(BlocksStorageFlags(), BlocksStorageS3Flags(), map[string]string{ + "-blocks-storage.tsdb.block-ranges-period": blockRangePeriod.String(), + "-blocks-storage.tsdb.ship-interval": "1s", + "-blocks-storage.bucket-store.sync-interval": "1s", + "-blocks-storage.tsdb.retention-period": ((blockRangePeriod * 2) - 1).String(), + "-querier.max-fetched-series-per-query": "3", + }) - // Start dependencies. - consul := e2edb.NewConsul() - minio := e2edb.NewMinio(9000, flags["-blocks-storage.s3.bucket-name"]) - memcached := e2ecache.NewMemcached() - require.NoError(t, s.StartAndWaitReady(consul, minio, memcached)) + // Start dependencies. + consul := e2edb.NewConsul() + minio := e2edb.NewMinio(9000, flags["-blocks-storage.s3.bucket-name"]) + memcached := e2ecache.NewMemcached() + require.NoError(t, s.StartAndWaitReady(consul, minio, memcached)) - // Add the memcached address to the flags. - flags["-blocks-storage.bucket-store.index-cache.memcached.addresses"] = "dns+" + memcached.NetworkEndpoint(e2ecache.MemcachedPort) + // Add the memcached address to the flags. + flags["-blocks-storage.bucket-store.index-cache.memcached.addresses"] = "dns+" + memcached.NetworkEndpoint(e2ecache.MemcachedPort) - // Start Mimir components. - distributor := e2emimir.NewDistributor("distributor", consul.NetworkHTTPEndpoint(), flags) - ingester := e2emimir.NewIngester("ingester", consul.NetworkHTTPEndpoint(), flags) - storeGateway := e2emimir.NewStoreGateway("store-gateway", consul.NetworkHTTPEndpoint(), flags) - require.NoError(t, s.StartAndWaitReady(distributor, ingester, storeGateway)) + // Start Mimir components. + distributor := e2emimir.NewDistributor("distributor", consul.NetworkHTTPEndpoint(), flags) + ingester := e2emimir.NewIngester("ingester", consul.NetworkHTTPEndpoint(), flags) + storeGateway := e2emimir.NewStoreGateway("store-gateway", consul.NetworkHTTPEndpoint(), flags) + require.NoError(t, s.StartAndWaitReady(distributor, ingester, storeGateway)) - querier := e2emimir.NewQuerier("querier", consul.NetworkHTTPEndpoint(), flags) - require.NoError(t, s.StartAndWaitReady(querier)) + querier := e2emimir.NewQuerier("querier", consul.NetworkHTTPEndpoint(), flags) + require.NoError(t, s.StartAndWaitReady(querier)) - c, err := e2emimir.NewClient(distributor.HTTPEndpoint(), querier.HTTPEndpoint(), "", "", "user-1") - require.NoError(t, err) + c, err := e2emimir.NewClient(distributor.HTTPEndpoint(), querier.HTTPEndpoint(), "", "", "user-1") + require.NoError(t, err) - // Push some series to Mimir. - series1Name := "series_1" - series2Name := "series_2" - series3Name := "series_3" - series4Name := "series_4" - series1Timestamp := time.Now() - series2Timestamp := series1Timestamp.Add(blockRangePeriod * 2) - series3Timestamp := series1Timestamp.Add(blockRangePeriod * 2) - series4Timestamp := series1Timestamp.Add(blockRangePeriod * 3) + // Push some series to Mimir. + series1Name := "series_1" + series2Name := "series_2" + series3Name := "series_3" + series4Name := "series_4" + series1Timestamp := time.Now() + series2Timestamp := series1Timestamp.Add(blockRangePeriod * 2) + series3Timestamp := series1Timestamp.Add(blockRangePeriod * 2) + series4Timestamp := series1Timestamp.Add(blockRangePeriod * 3) - series1, _, _ := generateFloatSeries(series1Name, series1Timestamp, prompb.Label{Name: series1Name, Value: series1Name}) - series2, _, _ := generateHistogramSeries(series2Name, series2Timestamp, prompb.Label{Name: series2Name, Value: series2Name}) - series3, _, _ := generateFloatSeries(series3Name, series3Timestamp, prompb.Label{Name: series3Name, Value: series3Name}) - series4, _, _ := generateHistogramSeries(series4Name, series4Timestamp, prompb.Label{Name: series4Name, Value: series4Name}) + series1, _, _ := generateFloatSeries(series1Name, series1Timestamp, prompb.Label{Name: series1Name, Value: series1Name}) + series2, _, _ := generateHistogramSeries(series2Name, series2Timestamp, prompb.Label{Name: series2Name, Value: series2Name}) + series3, _, _ := generateFloatSeries(series3Name, series3Timestamp, prompb.Label{Name: series3Name, Value: series3Name}) + series4, _, _ := generateHistogramSeries(series4Name, series4Timestamp, prompb.Label{Name: series4Name, Value: series4Name}) - res, err := c.Push(series1) - require.NoError(t, err) - require.Equal(t, 200, res.StatusCode) - res, err = c.Push(series2) - require.NoError(t, err) - require.Equal(t, 200, res.StatusCode) + res, err := c.Push(series1) + require.NoError(t, err) + require.Equal(t, 200, res.StatusCode) + res, err = c.Push(series2) + require.NoError(t, err) + require.Equal(t, 200, res.StatusCode) - result, err := c.QueryRange("{__name__=~\"series_.+\"}", series1Timestamp, series2Timestamp.Add(1*time.Hour), blockRangePeriod) - require.NoError(t, err) - require.Equal(t, model.ValMatrix, result.Type()) + result, err := c.QueryRange("{__name__=~\"series_.+\"}", series1Timestamp, series2Timestamp.Add(1*time.Hour), blockRangePeriod) + require.NoError(t, err) + require.Equal(t, model.ValMatrix, result.Type()) - res, err = c.Push(series3) - require.NoError(t, err) - require.Equal(t, 200, res.StatusCode) - res, err = c.Push(series4) - require.NoError(t, err) - require.Equal(t, 200, res.StatusCode) + res, err = c.Push(series3) + require.NoError(t, err) + require.Equal(t, 200, res.StatusCode) + res, err = c.Push(series4) + require.NoError(t, err) + require.Equal(t, 200, res.StatusCode) - _, err = c.QueryRange("{__name__=~\"series_.+\"}", series1Timestamp, series4Timestamp.Add(1*time.Hour), blockRangePeriod) - require.Error(t, err) - assert.ErrorContains(t, err, "the query exceeded the maximum number of series") - }) - } + _, err = c.QueryRange("{__name__=~\"series_.+\"}", series1Timestamp, series4Timestamp.Add(1*time.Hour), blockRangePeriod) + require.Error(t, err) + assert.ErrorContains(t, err, "the query exceeded the maximum number of series") } func TestHashCollisionHandling(t *testing.T) { diff --git a/operations/helm/charts/mimir-distributed/CHANGELOG.md b/operations/helm/charts/mimir-distributed/CHANGELOG.md index bb3e01ce94e..db169edd96d 100644 --- a/operations/helm/charts/mimir-distributed/CHANGELOG.md +++ b/operations/helm/charts/mimir-distributed/CHANGELOG.md @@ -33,12 +33,17 @@ Entries should include a reference to the Pull Request that introduced the chang * Overview dashboard: status, read/write latency and queries/ingestion per sec panels, `cortex_request_duration_seconds` metric. #7674 * Writes dashboard: `cortex_request_duration_seconds` metric. #8757 * Reads dashboard: `cortex_request_duration_seconds` metric. #8752 - * Rollout progress dashboard. #8779 + * Rollout progress dashboard: `cortex_request_duration_seconds` metric. #8779 + * Alertmanager dashboard: `cortex_request_duration_seconds` metric. #8792 + * Ruler dashboard: `cortex_request_duration_seconds` metric. #8795 + * Queries dashboard: `cortex_request_duration_seconds` metric. #8800 * Remote ruler reads dashboard: `cortex_request_duration_seconds` metric. * [ENHANCEMENT] Memcached: Update to Memcached 1.6.28 and memcached-exporter 0.14.4. #8557 * [ENHANCEMENT] Add missing fields in multiple topology spread constraints. #8533 * [ENHANCEMENT] Add support for setting the image pull secrets, node selectors, tolerations and topology spread constraints for the Grafana Agent pods used for metamonitoring. #8670 * [BUGFIX] Add missing container security context to run `continuous-test` under the restricted security policy. #8653 +* [BUGFIX] Add `global.extraVolumeMounts` to the exporter container on memcached statefulsets #8787 +* [BUGFIX] Fix helm releases failing when `querier.kedaAutoscaling.predictiveScalingEnabled=true`. #8731 ## 5.4.0 diff --git a/operations/helm/charts/mimir-distributed/Chart.yaml b/operations/helm/charts/mimir-distributed/Chart.yaml index 11357003e3d..6c7e4e1e88c 100644 --- a/operations/helm/charts/mimir-distributed/Chart.yaml +++ b/operations/helm/charts/mimir-distributed/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 -version: 5.4.0 -appVersion: 2.13.0 +version: 5.5.0-weekly.300 +appVersion: r300 description: "Grafana Mimir" home: https://grafana.com/docs/helm-charts/mimir-distributed/latest/ icon: https://grafana.com/static/img/logos/logo-mimir.svg diff --git a/operations/helm/charts/mimir-distributed/README.md b/operations/helm/charts/mimir-distributed/README.md index a9918cf9284..140b7832ab5 100644 --- a/operations/helm/charts/mimir-distributed/README.md +++ b/operations/helm/charts/mimir-distributed/README.md @@ -4,7 +4,7 @@ Helm chart for deploying [Grafana Mimir](https://grafana.com/docs/mimir/latest/) For the full documentation, visit [Grafana mimir-distributed Helm chart documentation](https://grafana.com/docs/helm-charts/mimir-distributed/latest/). -> **Note:** The documentation version is derived from the Helm chart version which is 5.4.0. +> **Note:** The documentation version is derived from the Helm chart version which is 5.5.0-weekly.300. When upgrading from Helm chart version 4.X, please see [Migrate the Helm chart from version 4.x to 5.0](https://grafana.com/docs/helm-charts/mimir-distributed/latest/migration-guides/migrate-helm-chart-4.x-to-5.0/). When upgrading from Helm chart version 3.x, please see [Migrate from single zone to zone-aware replication with Helm](https://grafana.com/docs/helm-charts/mimir-distributed/latest/migration-guides/migrate-from-single-zone-with-helm/). @@ -14,7 +14,7 @@ When upgrading from Helm chart version 2.1, please see [Upgrade the Grafana Mimi # mimir-distributed -![Version: 5.4.0](https://img.shields.io/badge/Version-5.4.0-informational?style=flat-square) ![AppVersion: 2.13.0](https://img.shields.io/badge/AppVersion-2.13.0-informational?style=flat-square) +![Version: 5.5.0-weekly.300](https://img.shields.io/badge/Version-5.5.0--weekly.300-informational?style=flat-square) ![AppVersion: r300](https://img.shields.io/badge/AppVersion-r300-informational?style=flat-square) Grafana Mimir diff --git a/operations/helm/charts/mimir-distributed/templates/memcached/_memcached-statefulset.tpl b/operations/helm/charts/mimir-distributed/templates/memcached/_memcached-statefulset.tpl index dae54837f1d..9ebb45aa631 100644 --- a/operations/helm/charts/mimir-distributed/templates/memcached/_memcached-statefulset.tpl +++ b/operations/helm/charts/mimir-distributed/templates/memcached/_memcached-statefulset.tpl @@ -78,7 +78,7 @@ spec: {{- end }} {{- with $.ctx.Values.global.extraVolumes }} {{- toYaml . | nindent 8 }} - {{- end}} + {{- end }} containers: {{- if .extraContainers }} {{ toYaml .extraContainers | nindent 8 }} @@ -129,7 +129,7 @@ spec: {{- end }} {{- with $.ctx.Values.global.extraVolumeMounts }} {{- toYaml . | nindent 12 }} - {{- end}} + {{- end }} {{- if $.ctx.Values.memcachedExporter.enabled }} - name: exporter @@ -150,9 +150,14 @@ spec: {{- toYaml $.ctx.Values.memcachedExporter.resources | nindent 12 }} securityContext: {{- toYaml $.ctx.Values.memcachedExporter.containerSecurityContext | nindent 12 }} - {{- if .extraVolumeMounts }} + {{- if or .extraVolumeMounts $.ctx.Values.global.extraVolumeMounts }} volumeMounts: - {{- toYaml .extraVolumeMounts | nindent 12 }} + {{- with .extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with $.ctx.Values.global.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} {{- end }} {{- end }} {{- end -}} diff --git a/operations/helm/charts/mimir-distributed/templates/querier/querier-so.yaml b/operations/helm/charts/mimir-distributed/templates/querier/querier-so.yaml index 8e4ac43f92c..6d12dc1beef 100644 --- a/operations/helm/charts/mimir-distributed/templates/querier/querier-so.yaml +++ b/operations/helm/charts/mimir-distributed/templates/querier/querier-so.yaml @@ -53,7 +53,7 @@ spec: {{- if .Values.kedaAutoscaling.customHeaders }} customHeaders: {{ (include "mimir.lib.mapToCSVString" (dict "map" .Values.kedaAutoscaling.customHeaders)) | quote }} {{- end }} - name: cortex_querier_hpa_default + name: cortex_querier_hpa_default_predictive type: prometheus {{- end }} {{- end }} diff --git a/operations/helm/charts/mimir-distributed/values.yaml b/operations/helm/charts/mimir-distributed/values.yaml index fb41b79f67b..cdb36bb07be 100644 --- a/operations/helm/charts/mimir-distributed/values.yaml +++ b/operations/helm/charts/mimir-distributed/values.yaml @@ -34,7 +34,7 @@ image: # -- Grafana Mimir container image repository. Note: for Grafana Enterprise Metrics use the value 'enterprise.image.repository' repository: grafana/mimir # -- Grafana Mimir container image tag. Note: for Grafana Enterprise Metrics use the value 'enterprise.image.tag' - tag: 2.13.0 + tag: r300-e243636 # -- Container pull policy - shared between Grafana Mimir and Grafana Enterprise Metrics pullPolicy: IfNotPresent # -- Optionally specify an array of imagePullSecrets - shared between Grafana Mimir and Grafana Enterprise Metrics @@ -3828,7 +3828,7 @@ enterprise: # -- Grafana Enterprise Metrics container image repository. Note: for Grafana Mimir use the value 'image.repository' repository: grafana/enterprise-metrics # -- Grafana Enterprise Metrics container image tag. Note: for Grafana Mimir use the value 'image.tag' - tag: v2.13.0 + tag: r300-f8726ed0 # Note: pullPolicy and optional pullSecrets are set in toplevel 'image' section, not here # In order to use Grafana Enterprise Metrics features, you will need to provide the contents of your Grafana Enterprise Metrics diff --git a/operations/helm/tests/metamonitoring-values-generated/mimir-distributed/templates/metamonitoring/grafana-dashboards.yaml b/operations/helm/tests/metamonitoring-values-generated/mimir-distributed/templates/metamonitoring/grafana-dashboards.yaml index f772a41b3dd..2787479de40 100644 --- a/operations/helm/tests/metamonitoring-values-generated/mimir-distributed/templates/metamonitoring/grafana-dashboards.yaml +++ b/operations/helm/tests/metamonitoring-values-generated/mimir-distributed/templates/metamonitoring/grafana-dashboards.yaml @@ -1175,7 +1175,13 @@ data: "span": 6, "targets": [ { - "expr": "sum by (status) (\n label_replace(label_replace(rate(cortex_request_duration_seconds_count{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"}[$__rate_interval]),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n \"status\", \"${1}\", \"status_code\", \"([a-zA-Z]+)\"))\n", + "expr": "sum by (status) (\n label_replace(label_replace(rate(cortex_request_duration_seconds_count{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"}[$__rate_interval]),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n \"status\", \"${1}\", \"status_code\", \"([a-zA-Z]+)\"))\n < ($latency_metrics * +Inf)", + "format": "time_series", + "legendFormat": "{{status}}", + "refId": "A_classic" + }, + { + "expr": "sum by (status) (\n label_replace(label_replace(histogram_count(rate(cortex_request_duration_seconds{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"}[$__rate_interval])),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n \"status\", \"${1}\", \"status_code\", \"([a-zA-Z]+)\"))\n < ($latency_metrics * -Inf)", "format": "time_series", "legendFormat": "{{status}}", "refId": "A" @@ -1224,22 +1230,40 @@ data: "span": 6, "targets": [ { - "expr": "histogram_quantile(0.99, sum by (le) (cluster_job_route:cortex_request_duration_seconds_bucket:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) * 1e3", + "expr": "histogram_quantile(0.99, sum by (le) (cluster_job_route:cortex_request_duration_seconds_bucket:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) * 1e3 < ($latency_metrics * +Inf)", "format": "time_series", "legendFormat": "99th percentile", - "refId": "A" + "refId": "A_classic" }, { - "expr": "histogram_quantile(0.50, sum by (le) (cluster_job_route:cortex_request_duration_seconds_bucket:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) * 1e3", + "expr": "histogram_quantile(0.99, sum (cluster_job_route:cortex_request_duration_seconds:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) * 1e3 < ($latency_metrics * -Inf)", + "format": "time_series", + "legendFormat": "99th percentile", + "refId": "A_native" + }, + { + "expr": "histogram_quantile(0.50, sum by (le) (cluster_job_route:cortex_request_duration_seconds_bucket:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) * 1e3 < ($latency_metrics * +Inf)", "format": "time_series", "legendFormat": "50th percentile", - "refId": "B" + "refId": "B_classic" }, { - "expr": "1e3 * sum(cluster_job_route:cortex_request_duration_seconds_sum:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"}) / sum(cluster_job_route:cortex_request_duration_seconds_count:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})", + "expr": "histogram_quantile(0.50, sum (cluster_job_route:cortex_request_duration_seconds:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) * 1e3 < ($latency_metrics * -Inf)", + "format": "time_series", + "legendFormat": "50th percentile", + "refId": "B_native" + }, + { + "expr": "1e3 * sum(cluster_job_route:cortex_request_duration_seconds_sum:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"}) /\nsum(cluster_job_route:cortex_request_duration_seconds_count:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})\n < ($latency_metrics * +Inf)", "format": "time_series", "legendFormat": "Average", - "refId": "C" + "refId": "C_classic" + }, + { + "expr": "1e3 * sum(histogram_sum(cluster_job_route:cortex_request_duration_seconds:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) /\nsum(histogram_count(cluster_job_route:cortex_request_duration_seconds:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"}))\n < ($latency_metrics * -Inf)", + "format": "time_series", + "legendFormat": "Average", + "refId": "C_native" } ], "title": "Latency", @@ -3134,6 +3158,35 @@ data: "tagsQuery": "", "type": "query", "useTags": false + }, + { + "current": { + "selected": true, + "text": "classic", + "value": "1" + }, + "description": "Choose between showing latencies based on low precision classic or high precision native histogram metrics.", + "hide": 0, + "includeAll": false, + "label": "Latency metrics", + "multi": false, + "name": "latency_metrics", + "options": [ + { + "selected": false, + "text": "native", + "value": "-1" + }, + { + "selected": true, + "text": "classic", + "value": "1" + } + ], + "query": "native : -1,classic : 1", + "skipUrlSync": false, + "type": "custom", + "useTags": false } ] }, @@ -13583,6 +13636,35 @@ data: "tagsQuery": "", "type": "query", "useTags": false + }, + { + "current": { + "selected": true, + "text": "classic", + "value": "1" + }, + "description": "Choose between showing latencies based on low precision classic or high precision native histogram metrics.", + "hide": 0, + "includeAll": false, + "label": "Latency metrics", + "multi": false, + "name": "latency_metrics", + "options": [ + { + "selected": false, + "text": "native", + "value": "-1" + }, + { + "selected": true, + "text": "classic", + "value": "1" + } + ], + "query": "native : -1,classic : 1", + "skipUrlSync": false, + "type": "custom", + "useTags": false } ] }, @@ -30478,6 +30560,35 @@ data: "tagsQuery": "", "type": "query", "useTags": false + }, + { + "current": { + "selected": true, + "text": "classic", + "value": "1" + }, + "description": "Choose between showing latencies based on low precision classic or high precision native histogram metrics.", + "hide": 0, + "includeAll": false, + "label": "Latency metrics", + "multi": false, + "name": "latency_metrics", + "options": [ + { + "selected": false, + "text": "native", + "value": "-1" + }, + { + "selected": true, + "text": "classic", + "value": "1" + } + ], + "query": "native : -1,classic : 1", + "skipUrlSync": false, + "type": "custom", + "useTags": false } ] }, diff --git a/operations/helm/tests/metamonitoring-values-generated/mimir-distributed/templates/metamonitoring/mixin-alerts.yaml b/operations/helm/tests/metamonitoring-values-generated/mimir-distributed/templates/metamonitoring/mixin-alerts.yaml index 5cbd9b38364..b7f45732d39 100644 --- a/operations/helm/tests/metamonitoring-values-generated/mimir-distributed/templates/metamonitoring/mixin-alerts.yaml +++ b/operations/helm/tests/metamonitoring-values-generated/mimir-distributed/templates/metamonitoring/mixin-alerts.yaml @@ -1047,6 +1047,18 @@ spec: for: 5m labels: severity: critical + - alert: MimirKafkaClientBufferedProduceBytesTooHigh + annotations: + message: Mimir {{ $labels.pod }} in {{ $labels.cluster }}/{{ $labels.namespace }} Kafka client produce buffer utilization is {{ printf "%.2f" $value }}%. + runbook_url: https://grafana.com/docs/mimir/latest/operators-guide/mimir-runbooks/#mimirkafkaclientbufferedproducebytestoohigh + expr: | + max by(cluster, namespace, pod) (max_over_time(cortex_ingest_storage_writer_buffered_produce_bytes{quantile="1.0"}[1m])) + / + min by(cluster, namespace, pod) (min_over_time(cortex_ingest_storage_writer_buffered_produce_bytes_limit[1m])) + * 100 > 50 + for: 5m + labels: + severity: critical - name: mimir_continuous_test rules: - alert: MimirContinuousTestNotRunningOnWrites diff --git a/operations/mimir-mixin-compiled-baremetal/alerts.yaml b/operations/mimir-mixin-compiled-baremetal/alerts.yaml index cebc6c7349b..50c03c26c39 100644 --- a/operations/mimir-mixin-compiled-baremetal/alerts.yaml +++ b/operations/mimir-mixin-compiled-baremetal/alerts.yaml @@ -1021,6 +1021,18 @@ groups: for: 5m labels: severity: critical + - alert: MimirKafkaClientBufferedProduceBytesTooHigh + annotations: + message: Mimir {{ $labels.instance }} in {{ $labels.cluster }}/{{ $labels.namespace }} Kafka client produce buffer utilization is {{ printf "%.2f" $value }}%. + runbook_url: https://grafana.com/docs/mimir/latest/operators-guide/mimir-runbooks/#mimirkafkaclientbufferedproducebytestoohigh + expr: | + max by(cluster, namespace, instance) (max_over_time(cortex_ingest_storage_writer_buffered_produce_bytes{quantile="1.0"}[1m])) + / + min by(cluster, namespace, instance) (min_over_time(cortex_ingest_storage_writer_buffered_produce_bytes_limit[1m])) + * 100 > 50 + for: 5m + labels: + severity: critical - name: mimir_continuous_test rules: - alert: MimirContinuousTestNotRunningOnWrites diff --git a/operations/mimir-mixin-compiled-baremetal/dashboards/mimir-alertmanager.json b/operations/mimir-mixin-compiled-baremetal/dashboards/mimir-alertmanager.json index d0d2c28b438..e81fc6e248d 100644 --- a/operations/mimir-mixin-compiled-baremetal/dashboards/mimir-alertmanager.json +++ b/operations/mimir-mixin-compiled-baremetal/dashboards/mimir-alertmanager.json @@ -446,7 +446,13 @@ "span": 6, "targets": [ { - "expr": "sum by (status) (\n label_replace(label_replace(rate(cortex_request_duration_seconds_count{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"}[$__rate_interval]),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n \"status\", \"${1}\", \"status_code\", \"([a-zA-Z]+)\"))\n", + "expr": "sum by (status) (\n label_replace(label_replace(rate(cortex_request_duration_seconds_count{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"}[$__rate_interval]),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n \"status\", \"${1}\", \"status_code\", \"([a-zA-Z]+)\"))\n < ($latency_metrics * +Inf)", + "format": "time_series", + "legendFormat": "{{status}}", + "refId": "A_classic" + }, + { + "expr": "sum by (status) (\n label_replace(label_replace(histogram_count(rate(cortex_request_duration_seconds{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"}[$__rate_interval])),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n \"status\", \"${1}\", \"status_code\", \"([a-zA-Z]+)\"))\n < ($latency_metrics * -Inf)", "format": "time_series", "legendFormat": "{{status}}", "refId": "A" @@ -495,22 +501,40 @@ "span": 6, "targets": [ { - "expr": "histogram_quantile(0.99, sum by (le) (cluster_job_route:cortex_request_duration_seconds_bucket:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) * 1e3", + "expr": "histogram_quantile(0.99, sum by (le) (cluster_job_route:cortex_request_duration_seconds_bucket:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) * 1e3 < ($latency_metrics * +Inf)", "format": "time_series", "legendFormat": "99th percentile", - "refId": "A" + "refId": "A_classic" + }, + { + "expr": "histogram_quantile(0.99, sum (cluster_job_route:cortex_request_duration_seconds:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) * 1e3 < ($latency_metrics * -Inf)", + "format": "time_series", + "legendFormat": "99th percentile", + "refId": "A_native" }, { - "expr": "histogram_quantile(0.50, sum by (le) (cluster_job_route:cortex_request_duration_seconds_bucket:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) * 1e3", + "expr": "histogram_quantile(0.50, sum by (le) (cluster_job_route:cortex_request_duration_seconds_bucket:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) * 1e3 < ($latency_metrics * +Inf)", "format": "time_series", "legendFormat": "50th percentile", - "refId": "B" + "refId": "B_classic" + }, + { + "expr": "histogram_quantile(0.50, sum (cluster_job_route:cortex_request_duration_seconds:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) * 1e3 < ($latency_metrics * -Inf)", + "format": "time_series", + "legendFormat": "50th percentile", + "refId": "B_native" }, { - "expr": "1e3 * sum(cluster_job_route:cortex_request_duration_seconds_sum:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"}) / sum(cluster_job_route:cortex_request_duration_seconds_count:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})", + "expr": "1e3 * sum(cluster_job_route:cortex_request_duration_seconds_sum:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"}) /\nsum(cluster_job_route:cortex_request_duration_seconds_count:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})\n < ($latency_metrics * +Inf)", "format": "time_series", "legendFormat": "Average", - "refId": "C" + "refId": "C_classic" + }, + { + "expr": "1e3 * sum(histogram_sum(cluster_job_route:cortex_request_duration_seconds:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) /\nsum(histogram_count(cluster_job_route:cortex_request_duration_seconds:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"}))\n < ($latency_metrics * -Inf)", + "format": "time_series", + "legendFormat": "Average", + "refId": "C_native" } ], "title": "Latency", @@ -2405,6 +2429,35 @@ "tagsQuery": "", "type": "query", "useTags": false + }, + { + "current": { + "selected": true, + "text": "classic", + "value": "1" + }, + "description": "Choose between showing latencies based on low precision classic or high precision native histogram metrics.", + "hide": 0, + "includeAll": false, + "label": "Latency metrics", + "multi": false, + "name": "latency_metrics", + "options": [ + { + "selected": false, + "text": "native", + "value": "-1" + }, + { + "selected": true, + "text": "classic", + "value": "1" + } + ], + "query": "native : -1,classic : 1", + "skipUrlSync": false, + "type": "custom", + "useTags": false } ] }, diff --git a/operations/mimir-mixin-compiled-baremetal/dashboards/mimir-queries.json b/operations/mimir-mixin-compiled-baremetal/dashboards/mimir-queries.json index 45f4fdebc57..d4921f3c52f 100644 --- a/operations/mimir-mixin-compiled-baremetal/dashboards/mimir-queries.json +++ b/operations/mimir-mixin-compiled-baremetal/dashboards/mimir-queries.json @@ -2496,6 +2496,35 @@ "tagsQuery": "", "type": "query", "useTags": false + }, + { + "current": { + "selected": true, + "text": "classic", + "value": "1" + }, + "description": "Choose between showing latencies based on low precision classic or high precision native histogram metrics.", + "hide": 0, + "includeAll": false, + "label": "Latency metrics", + "multi": false, + "name": "latency_metrics", + "options": [ + { + "selected": false, + "text": "native", + "value": "-1" + }, + { + "selected": true, + "text": "classic", + "value": "1" + } + ], + "query": "native : -1,classic : 1", + "skipUrlSync": false, + "type": "custom", + "useTags": false } ] }, diff --git a/operations/mimir-mixin-compiled-baremetal/dashboards/mimir-ruler.json b/operations/mimir-mixin-compiled-baremetal/dashboards/mimir-ruler.json index 50301fd2866..e1701f00841 100644 --- a/operations/mimir-mixin-compiled-baremetal/dashboards/mimir-ruler.json +++ b/operations/mimir-mixin-compiled-baremetal/dashboards/mimir-ruler.json @@ -2578,6 +2578,35 @@ "tagsQuery": "", "type": "query", "useTags": false + }, + { + "current": { + "selected": true, + "text": "classic", + "value": "1" + }, + "description": "Choose between showing latencies based on low precision classic or high precision native histogram metrics.", + "hide": 0, + "includeAll": false, + "label": "Latency metrics", + "multi": false, + "name": "latency_metrics", + "options": [ + { + "selected": false, + "text": "native", + "value": "-1" + }, + { + "selected": true, + "text": "classic", + "value": "1" + } + ], + "query": "native : -1,classic : 1", + "skipUrlSync": false, + "type": "custom", + "useTags": false } ] }, diff --git a/operations/mimir-mixin-compiled/alerts.yaml b/operations/mimir-mixin-compiled/alerts.yaml index 20df4924ad5..def38904949 100644 --- a/operations/mimir-mixin-compiled/alerts.yaml +++ b/operations/mimir-mixin-compiled/alerts.yaml @@ -1035,6 +1035,18 @@ groups: for: 5m labels: severity: critical + - alert: MimirKafkaClientBufferedProduceBytesTooHigh + annotations: + message: Mimir {{ $labels.pod }} in {{ $labels.cluster }}/{{ $labels.namespace }} Kafka client produce buffer utilization is {{ printf "%.2f" $value }}%. + runbook_url: https://grafana.com/docs/mimir/latest/operators-guide/mimir-runbooks/#mimirkafkaclientbufferedproducebytestoohigh + expr: | + max by(cluster, namespace, pod) (max_over_time(cortex_ingest_storage_writer_buffered_produce_bytes{quantile="1.0"}[1m])) + / + min by(cluster, namespace, pod) (min_over_time(cortex_ingest_storage_writer_buffered_produce_bytes_limit[1m])) + * 100 > 50 + for: 5m + labels: + severity: critical - name: mimir_continuous_test rules: - alert: MimirContinuousTestNotRunningOnWrites diff --git a/operations/mimir-mixin-compiled/dashboards/mimir-alertmanager.json b/operations/mimir-mixin-compiled/dashboards/mimir-alertmanager.json index ea0407cce05..0ef14b435ab 100644 --- a/operations/mimir-mixin-compiled/dashboards/mimir-alertmanager.json +++ b/operations/mimir-mixin-compiled/dashboards/mimir-alertmanager.json @@ -446,7 +446,13 @@ "span": 6, "targets": [ { - "expr": "sum by (status) (\n label_replace(label_replace(rate(cortex_request_duration_seconds_count{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"}[$__rate_interval]),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n \"status\", \"${1}\", \"status_code\", \"([a-zA-Z]+)\"))\n", + "expr": "sum by (status) (\n label_replace(label_replace(rate(cortex_request_duration_seconds_count{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"}[$__rate_interval]),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n \"status\", \"${1}\", \"status_code\", \"([a-zA-Z]+)\"))\n < ($latency_metrics * +Inf)", + "format": "time_series", + "legendFormat": "{{status}}", + "refId": "A_classic" + }, + { + "expr": "sum by (status) (\n label_replace(label_replace(histogram_count(rate(cortex_request_duration_seconds{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"}[$__rate_interval])),\n \"status\", \"${1}xx\", \"status_code\", \"([0-9])..\"),\n \"status\", \"${1}\", \"status_code\", \"([a-zA-Z]+)\"))\n < ($latency_metrics * -Inf)", "format": "time_series", "legendFormat": "{{status}}", "refId": "A" @@ -495,22 +501,40 @@ "span": 6, "targets": [ { - "expr": "histogram_quantile(0.99, sum by (le) (cluster_job_route:cortex_request_duration_seconds_bucket:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) * 1e3", + "expr": "histogram_quantile(0.99, sum by (le) (cluster_job_route:cortex_request_duration_seconds_bucket:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) * 1e3 < ($latency_metrics * +Inf)", "format": "time_series", "legendFormat": "99th percentile", - "refId": "A" + "refId": "A_classic" + }, + { + "expr": "histogram_quantile(0.99, sum (cluster_job_route:cortex_request_duration_seconds:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) * 1e3 < ($latency_metrics * -Inf)", + "format": "time_series", + "legendFormat": "99th percentile", + "refId": "A_native" }, { - "expr": "histogram_quantile(0.50, sum by (le) (cluster_job_route:cortex_request_duration_seconds_bucket:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) * 1e3", + "expr": "histogram_quantile(0.50, sum by (le) (cluster_job_route:cortex_request_duration_seconds_bucket:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) * 1e3 < ($latency_metrics * +Inf)", "format": "time_series", "legendFormat": "50th percentile", - "refId": "B" + "refId": "B_classic" + }, + { + "expr": "histogram_quantile(0.50, sum (cluster_job_route:cortex_request_duration_seconds:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) * 1e3 < ($latency_metrics * -Inf)", + "format": "time_series", + "legendFormat": "50th percentile", + "refId": "B_native" }, { - "expr": "1e3 * sum(cluster_job_route:cortex_request_duration_seconds_sum:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"}) / sum(cluster_job_route:cortex_request_duration_seconds_count:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})", + "expr": "1e3 * sum(cluster_job_route:cortex_request_duration_seconds_sum:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"}) /\nsum(cluster_job_route:cortex_request_duration_seconds_count:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})\n < ($latency_metrics * +Inf)", "format": "time_series", "legendFormat": "Average", - "refId": "C" + "refId": "C_classic" + }, + { + "expr": "1e3 * sum(histogram_sum(cluster_job_route:cortex_request_duration_seconds:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"})) /\nsum(histogram_count(cluster_job_route:cortex_request_duration_seconds:sum_rate{cluster=~\"$cluster\", job=~\"($namespace)/((alertmanager|cortex|mimir|mimir-backend.*))\", route=~\"/alertmanagerpb.Alertmanager/HandleRequest\"}))\n < ($latency_metrics * -Inf)", + "format": "time_series", + "legendFormat": "Average", + "refId": "C_native" } ], "title": "Latency", @@ -2405,6 +2429,35 @@ "tagsQuery": "", "type": "query", "useTags": false + }, + { + "current": { + "selected": true, + "text": "classic", + "value": "1" + }, + "description": "Choose between showing latencies based on low precision classic or high precision native histogram metrics.", + "hide": 0, + "includeAll": false, + "label": "Latency metrics", + "multi": false, + "name": "latency_metrics", + "options": [ + { + "selected": false, + "text": "native", + "value": "-1" + }, + { + "selected": true, + "text": "classic", + "value": "1" + } + ], + "query": "native : -1,classic : 1", + "skipUrlSync": false, + "type": "custom", + "useTags": false } ] }, diff --git a/operations/mimir-mixin-compiled/dashboards/mimir-queries.json b/operations/mimir-mixin-compiled/dashboards/mimir-queries.json index 1913205929a..01b96aec49f 100644 --- a/operations/mimir-mixin-compiled/dashboards/mimir-queries.json +++ b/operations/mimir-mixin-compiled/dashboards/mimir-queries.json @@ -2496,6 +2496,35 @@ "tagsQuery": "", "type": "query", "useTags": false + }, + { + "current": { + "selected": true, + "text": "classic", + "value": "1" + }, + "description": "Choose between showing latencies based on low precision classic or high precision native histogram metrics.", + "hide": 0, + "includeAll": false, + "label": "Latency metrics", + "multi": false, + "name": "latency_metrics", + "options": [ + { + "selected": false, + "text": "native", + "value": "-1" + }, + { + "selected": true, + "text": "classic", + "value": "1" + } + ], + "query": "native : -1,classic : 1", + "skipUrlSync": false, + "type": "custom", + "useTags": false } ] }, diff --git a/operations/mimir-mixin-compiled/dashboards/mimir-ruler.json b/operations/mimir-mixin-compiled/dashboards/mimir-ruler.json index 50301fd2866..e1701f00841 100644 --- a/operations/mimir-mixin-compiled/dashboards/mimir-ruler.json +++ b/operations/mimir-mixin-compiled/dashboards/mimir-ruler.json @@ -2578,6 +2578,35 @@ "tagsQuery": "", "type": "query", "useTags": false + }, + { + "current": { + "selected": true, + "text": "classic", + "value": "1" + }, + "description": "Choose between showing latencies based on low precision classic or high precision native histogram metrics.", + "hide": 0, + "includeAll": false, + "label": "Latency metrics", + "multi": false, + "name": "latency_metrics", + "options": [ + { + "selected": false, + "text": "native", + "value": "-1" + }, + { + "selected": true, + "text": "classic", + "value": "1" + } + ], + "query": "native : -1,classic : 1", + "skipUrlSync": false, + "type": "custom", + "useTags": false } ] }, diff --git a/operations/mimir-mixin/alerts/ingest-storage.libsonnet b/operations/mimir-mixin/alerts/ingest-storage.libsonnet index 03fa9d1c772..156444bbda2 100644 --- a/operations/mimir-mixin/alerts/ingest-storage.libsonnet +++ b/operations/mimir-mixin/alerts/ingest-storage.libsonnet @@ -165,6 +165,24 @@ message: '%(product)s {{ $labels.%(per_instance_label)s }} in %(alert_aggregation_variables)s fails to enforce strong-consistency on read-path.' % $._config, }, }, + + // Alert firing if the Kafka client produce buffer utilization is consistently high. + { + alert: $.alertName('KafkaClientBufferedProduceBytesTooHigh'), + 'for': '5m', + expr: ||| + max by(%(alert_aggregation_labels)s, %(per_instance_label)s) (max_over_time(cortex_ingest_storage_writer_buffered_produce_bytes{quantile="1.0"}[1m])) + / + min by(%(alert_aggregation_labels)s, %(per_instance_label)s) (min_over_time(cortex_ingest_storage_writer_buffered_produce_bytes_limit[1m])) + * 100 > 50 + ||| % $._config, + labels: { + severity: 'critical', + }, + annotations: { + message: '%(product)s {{ $labels.%(per_instance_label)s }} in %(alert_aggregation_variables)s Kafka client produce buffer utilization is {{ printf "%%.2f" $value }}%%.' % $._config, + }, + }, ], }, ], diff --git a/operations/mimir-mixin/dashboards/alertmanager.libsonnet b/operations/mimir-mixin/dashboards/alertmanager.libsonnet index 4c9f081c1d3..4d001ce2528 100644 --- a/operations/mimir-mixin/dashboards/alertmanager.libsonnet +++ b/operations/mimir-mixin/dashboards/alertmanager.libsonnet @@ -9,6 +9,7 @@ local filename = 'mimir-alertmanager.json'; assert std.md5(filename) == 'b0d38d318bbddd80476246d4930f9e55' : 'UID of the dashboard has changed, please update references to dashboard.'; ($.dashboard('Alertmanager') + { uid: std.md5(filename) }) .addClusterSelectorTemplates() + .addShowNativeLatencyVariable() .addRow( ($.row('Headlines') + { height: '100px', @@ -28,14 +29,15 @@ local filename = 'mimir-alertmanager.json'; ) ) .addRow( + local alertmanagerGRPCRoutesRegex = utils.selector.re('route', '%s' % $.queries.alertmanager_grpc_routes_regex); $.row('Alertmanager Distributor') .addPanel( $.timeseriesPanel('QPS') + - $.qpsPanel('cortex_request_duration_seconds_count{%s, route=~"/alertmanagerpb.Alertmanager/HandleRequest"}' % $.jobMatcher($._config.job_names.alertmanager)) + $.qpsPanelNativeHistogram($.queries.alertmanager.requestsPerSecondMetric, utils.toPrometheusSelectorNaked($.jobSelector($._config.job_names.alertmanager) + [alertmanagerGRPCRoutesRegex])) ) .addPanel( $.timeseriesPanel('Latency') + - $.latencyRecordingRulePanel('cortex_request_duration_seconds', $.jobSelector($._config.job_names.alertmanager) + [utils.selector.re('route', '/alertmanagerpb.Alertmanager/HandleRequest')]) + $.latencyRecordingRulePanelNativeHistogram($.queries.alertmanager.requestsPerSecondMetric, $.jobSelector($._config.job_names.alertmanager) + [alertmanagerGRPCRoutesRegex]) ) ) .addRow( @@ -111,11 +113,11 @@ local filename = 'mimir-alertmanager.json'; $.row('Configuration API (gateway) + Alertmanager UI') .addPanel( $.timeseriesPanel('QPS') + - $.qpsPanel('cortex_request_duration_seconds_count{%s, route=~"api_v1_alerts|alertmanager"}' % $.jobMatcher($._config.job_names.gateway)) + $.qpsPanelNativeHistogram($.queries.alertmanager.requestsPerSecondMetric, utils.toPrometheusSelectorNaked($.jobSelector($._config.job_names.gateway) + [utils.selector.re('route', '%s' % $.queries.alertmanager_http_routes_regex)])) ) .addPanel( $.timeseriesPanel('Latency') + - utils.latencyRecordingRulePanel('cortex_request_duration_seconds', $.jobSelector($._config.job_names.gateway) + [utils.selector.re('route', 'api_v1_alerts|alertmanager')]) + $.latencyRecordingRulePanelNativeHistogram($.queries.gateway.requestsPerSecondMetric, $.jobSelector($._config.job_names.gateway) + [utils.selector.re('route', '%s' % $.queries.alertmanager_http_routes_regex)]) ) ) .addRows( diff --git a/operations/mimir-mixin/dashboards/dashboard-queries.libsonnet b/operations/mimir-mixin/dashboards/dashboard-queries.libsonnet index e94e82a4848..13a2a313d98 100644 --- a/operations/mimir-mixin/dashboards/dashboard-queries.libsonnet +++ b/operations/mimir-mixin/dashboards/dashboard-queries.libsonnet @@ -113,6 +113,8 @@ local utils = import 'mixin-utils/utils.libsonnet'; read_grpc_ingester_route: $._config.ingester_read_path_routes_regex, read_grpc_store_gateway_route: $._config.store_gateway_read_path_routes_regex, query_http_routes_regex: '(prometheus|api_prom)_api_v1_query(_range)?', + alertmanager_http_routes_regex: 'api_v1_alerts|alertmanager', + alertmanager_grpc_routes_regex: '/alertmanagerpb.Alertmanager/HandleRequest', // Both support gRPC and HTTP requests. HTTP request is used when rule evaluation query requests go through the query-tee. ruler_query_frontend_routes_regex: '/httpgrpc.HTTP/Handle|.*api_v1_query', @@ -257,6 +259,7 @@ local utils = import 'mixin-utils/utils.libsonnet'; }, alertmanager: { + requestsPerSecondMetric: $.queries.requests_per_second_metric, notifications: { // Notifications / sec attempted to deliver by the Alertmanager to the receivers. totalPerSecond: ||| diff --git a/operations/mimir-mixin/dashboards/dashboard-utils.libsonnet b/operations/mimir-mixin/dashboards/dashboard-utils.libsonnet index a03a9560e48..34c0d513a28 100644 --- a/operations/mimir-mixin/dashboards/dashboard-utils.libsonnet +++ b/operations/mimir-mixin/dashboards/dashboard-utils.libsonnet @@ -260,14 +260,15 @@ local utils = import 'mixin-utils/utils.libsonnet'; ], }, - perInstanceLatencyPanelNativeHistogram(quantile, metric, selector, instanceLabel=$._config.per_instance_label):: - $.hiddenLegendQueryPanel( - [ - utils.showClassicHistogramQuery(utils.ncHistogramQuantile(quantile, metric, utils.toPrometheusSelectorNaked(selector), [instanceLabel])), - utils.showNativeHistogramQuery(utils.ncHistogramQuantile(quantile, metric, utils.toPrometheusSelectorNaked(selector), [instanceLabel])), - ], - ['', ''] - ), + perInstanceLatencyPanelNativeHistogram(quantile, metric, selector, legends=null, instanceLabel=$._config.per_instance_label, from_recording=false):: + local queries = [ + utils.showClassicHistogramQuery(utils.ncHistogramQuantile(quantile, metric, utils.toPrometheusSelectorNaked(selector), [instanceLabel], from_recording=from_recording)), + utils.showNativeHistogramQuery(utils.ncHistogramQuantile(quantile, metric, utils.toPrometheusSelectorNaked(selector), [instanceLabel], from_recording=from_recording)), + ]; + if legends == null then + $.hiddenLegendQueryPanel(queries, ['', '']) + else + $.queryPanel(queries, legends), // Creates a panel like queryPanel() but if the legend contains only 1 entry, // than it configures the series alias color to the one used to display failures. @@ -1784,4 +1785,55 @@ local utils = import 'mixin-utils/utils.libsonnet'; defaults+: { unit: 's' }, }, }, + + ingestStorageKafkaProducedRecordsRatePanel(jobName):: + $.timeseriesPanel('Kafka produced records / sec') + + $.panelDescription( + 'Kafka produced records / sec', + 'Rate of records synchronously produced to Kafka.', + ) + + $.queryPanel([ + ||| + sum(rate(cortex_ingest_storage_writer_produce_requests_total{%(job_matcher)s}[$__rate_interval])) + - + (sum(rate(cortex_ingest_storage_writer_produce_failures_total{%(job_matcher)s}[$__rate_interval])) or vector(0)) + ||| % { job_matcher: $.jobMatcher($._config.job_names[jobName]) }, + ||| + sum by(reason) (rate(cortex_ingest_storage_writer_produce_failures_total{%(job_matcher)s}[$__rate_interval])) + ||| % { job_matcher: $.jobMatcher($._config.job_names[jobName]) }, + ], [ + 'success', + 'failed - {{ reason }}', + ]) + + $.stack + + $.aliasColors({ + success: $._colors.success, + }), + + ingestStorageKafkaProducedRecordsLatencyPanel(jobName):: + $.timeseriesPanel('Kafka produced records latency') + + $.panelDescription( + 'Kafka produced records latency', + ||| + Latency of records synchronously produced to Kafka. + ||| + ) + + $.queryPanel( + [ + 'histogram_avg(sum(rate(cortex_ingest_storage_writer_latency_seconds{%s}[$__rate_interval])))' % [$.jobMatcher($._config.job_names[jobName])], + 'histogram_quantile(0.99, sum(rate(cortex_ingest_storage_writer_latency_seconds{%s}[$__rate_interval])))' % [$.jobMatcher($._config.job_names[jobName])], + 'histogram_quantile(0.999, sum(rate(cortex_ingest_storage_writer_latency_seconds{%s}[$__rate_interval])))' % [$.jobMatcher($._config.job_names[jobName])], + 'histogram_quantile(1.0, sum(rate(cortex_ingest_storage_writer_latency_seconds{%s}[$__rate_interval])))' % [$.jobMatcher($._config.job_names[jobName])], + ], + [ + 'avg', + '99th percentile', + '99.9th percentile', + '100th percentile', + ], + ) + { + fieldConfig+: { + defaults+: { unit: 's' }, + }, + }, } diff --git a/operations/mimir-mixin/dashboards/queries.libsonnet b/operations/mimir-mixin/dashboards/queries.libsonnet index 64c325600e2..011d6d39e9b 100644 --- a/operations/mimir-mixin/dashboards/queries.libsonnet +++ b/operations/mimir-mixin/dashboards/queries.libsonnet @@ -6,6 +6,7 @@ local filename = 'mimir-queries.json'; assert std.md5(filename) == 'b3abe8d5c040395cc36615cb4334c92d' : 'UID of the dashboard has changed, please update references to dashboard.'; ($.dashboard('Queries') + { uid: std.md5(filename) }) .addClusterSelectorTemplates() + .addShowNativeLatencyVariable() .addRow( $.row('Query-frontend') .addPanel( @@ -235,23 +236,27 @@ local filename = 'mimir-queries.json'; ||| ) + $.queryPanel( - [ + local ncSumRate = utils.ncHistogramSumBy(utils.ncHistogramCountRate($.queries.ingester.requestsPerSecondMetric, $.queries.ingester.readRequestsPerSecondSelector)); + local scSuccessful = ||| ( sum(rate(cortex_ingest_storage_strong_consistency_requests_total{%s}[$__rate_interval])) - sum(rate(cortex_ingest_storage_strong_consistency_failures_total{%s}[$__rate_interval])) ) - / - sum(rate(cortex_request_duration_seconds_count{%s,route=~"%s"}[$__rate_interval])) - ||| % [$.jobMatcher($._config.job_names.ingester), $.jobMatcher($._config.job_names.ingester), $.jobMatcher($._config.job_names.ingester), $._config.ingester_read_path_routes_regex], + ||| % [$.jobMatcher($._config.job_names.ingester), $.jobMatcher($._config.job_names.ingester)]; + local scFailed = ||| sum(rate(cortex_ingest_storage_strong_consistency_failures_total{%s}[$__rate_interval])) - / - sum(rate(cortex_request_duration_seconds_count{%s,route=~"%s"}[$__rate_interval])) - ||| % [$.jobMatcher($._config.job_names.ingester), $.jobMatcher($._config.job_names.ingester), $._config.ingester_read_path_routes_regex], + ||| % [$.jobMatcher($._config.job_names.ingester)]; + local scRate(sc, rate) = std.join(' / ', [sc, rate]); + [ + scRate(scSuccessful, utils.showClassicHistogramQuery(ncSumRate)), + scRate(scSuccessful, utils.showNativeHistogramQuery(ncSumRate)), + scRate(scFailed, utils.showClassicHistogramQuery(ncSumRate)), + scRate(scFailed, utils.showNativeHistogramQuery(ncSumRate)), ], - ['successful', 'failed'], + ['successful', 'successful', 'failed', 'failed'], ) + $.aliasColors({ failed: $._colors.failed, successful: $._colors.success }) + { fieldConfig+: { defaults+: { unit: 'percentunit', min: 0, max: 1 } } } diff --git a/operations/mimir-mixin/dashboards/ruler.libsonnet b/operations/mimir-mixin/dashboards/ruler.libsonnet index e979f6e99c4..4c15d54e240 100644 --- a/operations/mimir-mixin/dashboards/ruler.libsonnet +++ b/operations/mimir-mixin/dashboards/ruler.libsonnet @@ -14,6 +14,7 @@ local filename = 'mimir-ruler.json'; assert std.md5(filename) == '631e15d5d85afb2ca8e35d62984eeaa0' : 'UID of the dashboard has changed, please update references to dashboard.'; ($.dashboard('Ruler') + { uid: std.md5(filename) }) .addClusterSelectorTemplates() + .addShowNativeLatencyVariable() .addRow( ($.row('Headlines') + { height: '100px', @@ -94,20 +95,18 @@ local filename = 'mimir-ruler.json'; $.row('Configuration API (gateway)') .addPanel( $.timeseriesPanel('QPS') + - $.qpsPanel('cortex_request_duration_seconds_count{%s, route=~"%s"}' % [$.jobMatcher($._config.job_names.gateway), ruler_config_api_routes_re]) + $.qpsPanelNativeHistogram($.queries.ruler.requestsPerSecondMetric, utils.toPrometheusSelectorNaked($.jobSelector($._config.job_names.gateway) + [utils.selector.re('route', ruler_config_api_routes_re)])) ) .addPanel( $.timeseriesPanel('Latency') + - $.latencyRecordingRulePanel('cortex_request_duration_seconds', $.jobSelector($._config.job_names.gateway) + [utils.selector.re('route', ruler_config_api_routes_re)]) + $.latencyRecordingRulePanelNativeHistogram($.queries.gateway.requestsPerSecondMetric, $.jobSelector($._config.job_names.gateway) + [utils.selector.re('route', ruler_config_api_routes_re)]) ) .addPanel( local selectors = $.jobSelector($._config.job_names.gateway) + [utils.selector.re('route', ruler_config_api_routes_re)]; + local labels = std.join('_', [matcher.label for matcher in selectors]); + local metricStr = '%(labels)s:%(metric)s' % { labels: labels, metric: $.queries.gateway.requestsPerSecondMetric }; $.timeseriesPanel('Per route p99 latency') + - $.queryPanel( - 'histogram_quantile(0.99, sum by (route, le) (%s:cortex_request_duration_seconds_bucket:sum_rate%s))' % - [$.recordingRulePrefix(selectors), utils.toPrometheusSelector(selectors)], - '{{ route }}' - ) + + $.perInstanceLatencyPanelNativeHistogram('0.99', metricStr, selectors, legends=['{{ route }}', '{{ route }}'], instanceLabel='route', from_recording=true) + { fieldConfig+: { defaults+: { unit: 's' } } }, ) ) @@ -126,53 +125,10 @@ local filename = 'mimir-ruler.json'; $._config.show_ingest_storage_panels, $.row('Writes (ingest storage)') .addPanel( - $.timeseriesPanel('Requests / sec') + - $.panelDescription( - 'Requests / sec', - 'Rate of synchronous write operation from ruler to Kafka backend.', - ) + - $.queryPanel([ - ||| - sum(rate(cortex_ingest_storage_writer_produce_requests_total{%(job_matcher)s}[$__rate_interval])) - - - (sum(rate(cortex_ingest_storage_writer_produce_failures_total{%(job_matcher)s}[$__rate_interval])) or vector(0)) - ||| % { job_matcher: $.jobMatcher($._config.job_names.ruler) }, - ||| - sum by(reason) (rate(cortex_ingest_storage_writer_produce_failures_total{%(job_matcher)s}[$__rate_interval])) - ||| % { job_matcher: $.jobMatcher($._config.job_names.ruler) }, - ], [ - 'success', - 'failed - {{ reason }}', - ]) + - $.stack + - $.aliasColors({ - success: $._colors.success, - }) + $.ingestStorageKafkaProducedRecordsRatePanel('ruler') ) .addPanel( - $.timeseriesPanel('Latency') + - $.panelDescription( - 'Latency', - 'Latency of synchronous write operation from ruler to Kafka backend.', - ) + - $.queryPanel( - [ - 'histogram_avg(sum(rate(cortex_ingest_storage_writer_latency_seconds{%s}[$__rate_interval])))' % [$.jobMatcher($._config.job_names.ruler)], - 'histogram_quantile(0.99, sum(rate(cortex_ingest_storage_writer_latency_seconds{%s}[$__rate_interval])))' % [$.jobMatcher($._config.job_names.ruler)], - 'histogram_quantile(0.999, sum(rate(cortex_ingest_storage_writer_latency_seconds{%s}[$__rate_interval])))' % [$.jobMatcher($._config.job_names.ruler)], - 'histogram_quantile(1.0, sum(rate(cortex_ingest_storage_writer_latency_seconds{%s}[$__rate_interval])))' % [$.jobMatcher($._config.job_names.ruler)], - ], - [ - 'avg', - '99th percentile', - '99.9th percentile', - '100th percentile', - ], - ) + { - fieldConfig+: { - defaults+: { unit: 's' }, - }, - }, + $.ingestStorageKafkaProducedRecordsLatencyPanel('ruler') ) ) .addRow( diff --git a/operations/mimir-mixin/dashboards/writes.libsonnet b/operations/mimir-mixin/dashboards/writes.libsonnet index e05bb840648..06cbc277a8f 100644 --- a/operations/mimir-mixin/dashboards/writes.libsonnet +++ b/operations/mimir-mixin/dashboards/writes.libsonnet @@ -156,33 +156,15 @@ local filename = 'mimir-writes.json'; $.timeseriesPanel('Per %s p99 latency' % $._config.per_instance_label) + $.perInstanceLatencyPanelNativeHistogram('0.99', $.queries.distributor.requestsPerSecondMetric, $.jobSelector($._config.job_names.distributor) + [utils.selector.re('route', '%s' % $.queries.distributor.writeRequestsPerSecondRouteRegex)]) ) - .addPanelIf( - $._config.show_ingest_storage_panels, - $.timeseriesPanel('Sync write to Kafka latency (ingest storage)') + - $.panelDescription( - 'Sync write to Kafka latency (ingest storage)', - ||| - Latency of synchronous write operation used to store data into Kafka. - ||| - ) + - $.queryPanel( - [ - 'histogram_avg(sum(rate(cortex_ingest_storage_writer_latency_seconds{%s}[$__rate_interval])))' % [$.jobMatcher($._config.job_names.distributor)], - 'histogram_quantile(0.99, sum(rate(cortex_ingest_storage_writer_latency_seconds{%s}[$__rate_interval])))' % [$.jobMatcher($._config.job_names.distributor)], - 'histogram_quantile(0.999, sum(rate(cortex_ingest_storage_writer_latency_seconds{%s}[$__rate_interval])))' % [$.jobMatcher($._config.job_names.distributor)], - 'histogram_quantile(1.0, sum(rate(cortex_ingest_storage_writer_latency_seconds{%s}[$__rate_interval])))' % [$.jobMatcher($._config.job_names.distributor)], - ], - [ - 'avg', - '99th percentile', - '99.9th percentile', - '100th percentile', - ], - ) + { - fieldConfig+: { - defaults+: { unit: 's' }, - }, - }, + ) + .addRowIf( + $._config.show_ingest_storage_panels, + $.row('Distributor (ingest storage)') + .addPanel( + $.ingestStorageKafkaProducedRecordsRatePanel('distributor') + ) + .addPanel( + $.ingestStorageKafkaProducedRecordsLatencyPanel('distributor') ) ) .addRowsIf(std.objectHasAll($._config.injectRows, 'postDistributor'), $._config.injectRows.postDistributor($)) diff --git a/pkg/ingester/errors.go b/pkg/ingester/errors.go index c7447b55787..305f6c491a3 100644 --- a/pkg/ingester/errors.go +++ b/pkg/ingester/errors.go @@ -614,24 +614,3 @@ func mapReadErrorToErrorWithStatus(err error) error { } return newErrorWithStatus(err, errCode) } - -// mapReadErrorToErrorWithHTTPOrGRPCStatus maps ingesterError objects to an appropriate -// globalerror.ErrorWithStatus, which may contain both HTTP and gRPC error codes. -func mapReadErrorToErrorWithHTTPOrGRPCStatus(err error) error { - var ( - ingesterErr ingesterError - ) - if errors.As(err, &ingesterErr) { - switch ingesterErr.errorCause() { - case mimirpb.TOO_BUSY: - return newErrorWithHTTPStatus(err, http.StatusServiceUnavailable) - case mimirpb.SERVICE_UNAVAILABLE: - return newErrorWithStatus(err, codes.Unavailable) - case mimirpb.METHOD_NOT_ALLOWED: - return newErrorWithStatus(err, codes.Unimplemented) - case mimirpb.CIRCUIT_BREAKER_OPEN: - return newErrorWithStatus(err, codes.Unavailable) - } - } - return err -} diff --git a/pkg/ingester/errors_test.go b/pkg/ingester/errors_test.go index 22ecad0bf1b..ea42948e549 100644 --- a/pkg/ingester/errors_test.go +++ b/pkg/ingester/errors_test.go @@ -844,51 +844,6 @@ func TestMapReadErrorToErrorWithStatus(t *testing.T) { } } -func TestMapReadErrorToErrorWithHTTPOrGRPCStatus(t *testing.T) { - const originalMsg = "this is an error" - originalErr := errors.New(originalMsg) - - testCases := map[string]struct { - err error - expectedTranslation error - }{ - "a generic error is not translated": { - err: originalErr, - expectedTranslation: originalErr, - }, - "an unavailableError gets translated into an ErrorWithStatus Unavailable error with details": { - err: newUnavailableError(services.Stopping), - expectedTranslation: newErrorWithStatus(newUnavailableError(services.Stopping), codes.Unavailable), - }, - "a wrapped unavailableError gets translated into an ErrorWithStatus Unavailable error": { - err: fmt.Errorf("wrapped: %w", newUnavailableError(services.Stopping)), - expectedTranslation: newErrorWithStatus(fmt.Errorf("wrapped: %w", newUnavailableError(services.Stopping)), codes.Unavailable), - }, - "errTooBusy gets translated into an errorWithHTTPStatus with status code 503": { - err: errTooBusy, - expectedTranslation: newErrorWithHTTPStatus(errTooBusy, http.StatusServiceUnavailable), - }, - "a wrapped errTooBusy gets translated into an errorWithHTTPStatus with status code 503": { - err: fmt.Errorf("wrapped: %w", errTooBusy), - expectedTranslation: newErrorWithHTTPStatus(fmt.Errorf("wrapped: %w", errTooBusy), http.StatusServiceUnavailable), - }, - "a circuitBreakerOpenError gets translated into an ErrorWithStatus Unavailable error": { - err: newCircuitBreakerOpenError("foo", 1*time.Second), - expectedTranslation: newErrorWithStatus(newCircuitBreakerOpenError("foo", 1*time.Second), codes.Unavailable), - }, - "a wrapped circuitBreakerOpenError gets translated into an ErrorWithStatus Unavailable": { - err: fmt.Errorf("wrapped: %w", newCircuitBreakerOpenError("foo", 1*time.Second)), - expectedTranslation: newErrorWithStatus(fmt.Errorf("wrapped: %w", newCircuitBreakerOpenError("foo", 1*time.Second)), codes.Unavailable), - }, - } - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - handledErr := mapReadErrorToErrorWithHTTPOrGRPCStatus(tc.err) - require.Equal(t, tc.expectedTranslation, handledErr) - }) - } -} - type mockIngesterErr string func (e mockIngesterErr) Error() string { diff --git a/pkg/ingester/ingester.go b/pkg/ingester/ingester.go index 9495f4439aa..2b2d36af8c2 100644 --- a/pkg/ingester/ingester.go +++ b/pkg/ingester/ingester.go @@ -122,8 +122,6 @@ const ( // Value used to track the limit between sequential and concurrent TSDB opernings. // Below this value, TSDBs of different tenants are opened sequentially, otherwise concurrently. maxTSDBOpenWithoutConcurrency = 10 - - deprecatedReturnOnlyGRPCErrorsFlag = "ingester.return-only-grpc-errors" // Deprecated. TODO: Remove in Mimir 2.14. ) var ( @@ -205,8 +203,6 @@ type Config struct { ErrorSampleRate int64 `yaml:"error_sample_rate" json:"error_sample_rate" category:"advanced"` - DeprecatedReturnOnlyGRPCErrors bool `yaml:"return_only_grpc_errors" json:"return_only_grpc_errors" category:"deprecated"` - UseIngesterOwnedSeriesForLimits bool `yaml:"use_ingester_owned_series_for_limits" category:"experimental"` UpdateIngesterOwnedSeries bool `yaml:"track_ingester_owned_series" category:"experimental"` OwnedSeriesUpdateInterval time.Duration `yaml:"owned_series_update_interval" category:"experimental"` @@ -247,25 +243,15 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet, logger log.Logger) { f.DurationVar(&cfg.OwnedSeriesUpdateInterval, "ingester.owned-series-update-interval", 15*time.Second, "How often to check for ring changes and possibly recompute owned series as a result of detected change.") f.BoolVar(&cfg.PushGrpcMethodEnabled, "ingester.push-grpc-method-enabled", true, "Enables Push gRPC method on ingester. Can be only disabled when using ingest-storage to make sure ingesters only receive data from Kafka.") - // The ingester.return-only-grpc-errors flag has been deprecated. - // According to the migration plan (https://github.com/grafana/mimir/issues/6008#issuecomment-1854320098) - // the default behaviour of Mimir should be as this flag were set to true. - // TODO: Remove in Mimir 2.14.0 - f.BoolVar(&cfg.DeprecatedReturnOnlyGRPCErrors, deprecatedReturnOnlyGRPCErrorsFlag, true, "When enabled only gRPC errors will be returned by the ingester.") - // Hardcoded config (can only be overridden in tests). cfg.limitMetricsUpdatePeriod = time.Second * 15 } -func (cfg *Config) Validate(logger log.Logger) error { +func (cfg *Config) Validate(log.Logger) error { if cfg.ErrorSampleRate < 0 { return fmt.Errorf("error sample rate cannot be a negative number") } - if !cfg.DeprecatedReturnOnlyGRPCErrors { - util.WarnDeprecatedConfig(deprecatedReturnOnlyGRPCErrorsFlag, logger) - } - return cfg.IngesterRing.Validate() } @@ -3850,7 +3836,7 @@ func (i *Ingester) checkAvailableForPush() error { func (i *Ingester) PushToStorage(ctx context.Context, req *mimirpb.WriteRequest) error { err := i.PushWithCleanup(ctx, req, func() { mimirpb.ReuseSlice(req.Timeseries) }) if err != nil { - return i.mapPushErrorToErrorWithStatus(err) + return mapPushErrorToErrorWithStatus(err) } return nil } @@ -3868,13 +3854,6 @@ func (i *Ingester) Push(ctx context.Context, req *mimirpb.WriteRequest) (*mimirp return &mimirpb.WriteResponse{}, err } -func (i *Ingester) mapPushErrorToErrorWithStatus(err error) error { - if i.cfg.DeprecatedReturnOnlyGRPCErrors { - return mapPushErrorToErrorWithStatus(err) - } - return mapPushErrorToErrorWithHTTPOrGRPCStatus(err) -} - func (i *Ingester) mapReadErrorToErrorWithStatus(err error) error { if err == nil { return nil @@ -3884,10 +3863,7 @@ func (i *Ingester) mapReadErrorToErrorWithStatus(err error) error { return err } - if i.cfg.DeprecatedReturnOnlyGRPCErrors { - return mapReadErrorToErrorWithStatus(err) - } - return mapReadErrorToErrorWithHTTPOrGRPCStatus(err) + return mapReadErrorToErrorWithStatus(err) } // pushMetadata returns number of ingested metadata. diff --git a/pkg/ingester/ingester_test.go b/pkg/ingester/ingester_test.go index 6e00fe50904..5e630a052af 100644 --- a/pkg/ingester/ingester_test.go +++ b/pkg/ingester/ingester_test.go @@ -2824,7 +2824,7 @@ func TestIngester_Push(t *testing.T) { if testData.expectedErr == nil { assert.NoError(t, err) } else { - handledErr := i.mapPushErrorToErrorWithStatus(err) + handledErr := mapPushErrorToErrorWithStatus(err) errWithStatus, ok := handledErr.(globalerror.ErrorWithStatus) assert.True(t, ok) assert.True(t, errWithStatus.Equals(testData.expectedErr)) diff --git a/pkg/mimir/mimir.go b/pkg/mimir/mimir.go index 1858cde95c1..9142b18d5e5 100644 --- a/pkg/mimir/mimir.go +++ b/pkg/mimir/mimir.go @@ -246,9 +246,6 @@ func (c *Config) Validate(log log.Logger) error { return errors.Wrap(err, "invalid ingest storage config") } if c.isAnyModuleEnabled(Ingester, Write, All) { - if c.IngestStorage.Enabled && !c.Ingester.DeprecatedReturnOnlyGRPCErrors { - return errors.New("to use ingest storage (-ingest-storage.enabled) also enable -ingester.return-only-grpc-errors") - } if !c.IngestStorage.Enabled && !c.Ingester.PushGrpcMethodEnabled { return errors.New("cannot disable Push gRPC method in ingester, while ingest storage (-ingest-storage.enabled) is not enabled") } diff --git a/pkg/mimir/mimir_test.go b/pkg/mimir/mimir_test.go index 074597bee49..3204de55e44 100644 --- a/pkg/mimir/mimir_test.go +++ b/pkg/mimir/mimir_test.go @@ -424,34 +424,6 @@ func TestConfigValidation(t *testing.T) { }, expectAnyError: true, }, - { - name: "should pass if grpc errors are disabled, and the distributor is running with ingest storage", - getTestConfig: func() *Config { - cfg := newDefaultConfig() - _ = cfg.Target.Set("distributor") - cfg.IngestStorage.Enabled = true - cfg.IngestStorage.KafkaConfig.Address = "localhost:123" - cfg.IngestStorage.KafkaConfig.Topic = "topic" - cfg.Ingester.DeprecatedReturnOnlyGRPCErrors = false - - return cfg - }, - expectAnyError: false, - }, - { - name: "should fails if grpc errors are disabled, and the ingester is running with ingest storage", - getTestConfig: func() *Config { - cfg := newDefaultConfig() - _ = cfg.Target.Set("ingester") - cfg.IngestStorage.Enabled = true - cfg.IngestStorage.KafkaConfig.Address = "localhost:123" - cfg.IngestStorage.KafkaConfig.Topic = "topic" - cfg.Ingester.DeprecatedReturnOnlyGRPCErrors = false - - return cfg - }, - expectAnyError: true, - }, { name: "should fails if push api disabled in ingester, and the ingester isn't running with ingest storage", getTestConfig: func() *Config { diff --git a/pkg/mimirtool/commands/rules.go b/pkg/mimirtool/commands/rules.go index 886fb48523b..aaff6313d36 100644 --- a/pkg/mimirtool/commands/rules.go +++ b/pkg/mimirtool/commands/rules.go @@ -78,7 +78,6 @@ type RuleCommand struct { // Load Rules Config RuleFilesList []string - RuleFiles string RuleFilesPath string // Sync/Diff Rules Config @@ -228,7 +227,6 @@ func (r *RuleCommand) Register(app *kingpin.Application, envVars EnvVarNames, re diffRulesCmd.Flag("ignored-namespaces", "comma-separated list of namespaces to ignore during a diff. Cannot be used together with other namespaces options.").StringVar(&r.IgnoredNamespaces) diffRulesCmd.Flag("namespaces-regex", "regex matching namespaces to check during a diff. Cannot be used together with other namespaces options.").RegexpVar(&r.NamespacesRegex) diffRulesCmd.Flag("ignored-namespaces-regex", "regex matching namespaces to ignore during a diff. Cannot be used together with other namespaces options.").RegexpVar(&r.IgnoredNamespacesRegex) - diffRulesCmd.Flag("rule-files", "The rule files to check. Flag can be reused to load multiple files.").Hidden().StringVar(&r.RuleFiles) // TODO: Remove flag in Mimir 2.14. diffRulesCmd.Flag( "rule-dirs", "Comma separated list of paths to directories containing rules yaml files. Each file in a directory with a .yml or .yaml suffix will be parsed.", @@ -242,7 +240,6 @@ func (r *RuleCommand) Register(app *kingpin.Application, envVars EnvVarNames, re syncRulesCmd.Flag("ignored-namespaces", "comma-separated list of namespaces to ignore during a sync. Cannot be used together with other namespaces options.").StringVar(&r.IgnoredNamespaces) syncRulesCmd.Flag("namespaces-regex", "regex matching namespaces to check during a sync. Cannot be used together with other namespaces options.").RegexpVar(&r.NamespacesRegex) syncRulesCmd.Flag("ignored-namespaces-regex", "regex matching namespaces to ignore during a sync. Cannot be used together with other namespaces options.").RegexpVar(&r.IgnoredNamespacesRegex) - syncRulesCmd.Flag("rule-files", "The rule files to check. Flag can be reused to load multiple files.").Hidden().StringVar(&r.RuleFiles) // TODO: Remove flag in Mimir 2.14. syncRulesCmd.Flag( "rule-dirs", "Comma separated list of paths to directories containing rules yaml files. Each file in a directory with a .yml or .yaml suffix will be parsed.", @@ -254,7 +251,6 @@ func (r *RuleCommand) Register(app *kingpin.Application, envVars EnvVarNames, re // Prepare Command prepareCmd.Arg("rule-files", "The rule files to check.").ExistingFilesVar(&r.RuleFilesList) - prepareCmd.Flag("rule-files", "The rule files to check. Flag can be reused to load multiple files.").Hidden().StringVar(&r.RuleFiles) // TODO: Remove flag in Mimir 2.14. prepareCmd.Flag( "rule-dirs", "Comma separated list of paths to directories containing rules yaml files. Each file in a directory with a .yml or .yaml suffix will be parsed.", @@ -268,7 +264,6 @@ func (r *RuleCommand) Register(app *kingpin.Application, envVars EnvVarNames, re // Lint Command lintCmd.Arg("rule-files", "The rule files to check.").ExistingFilesVar(&r.RuleFilesList) - lintCmd.Flag("rule-files", "The rule files to check. Flag can be reused to load multiple files.").Hidden().StringVar(&r.RuleFiles) // TODO: Remove flag in Mimir 2.14. lintCmd.Flag( "rule-dirs", "Comma separated list of paths to directories containing rules yaml files. Each file in a directory with a .yml or .yaml suffix will be parsed.", @@ -277,7 +272,6 @@ func (r *RuleCommand) Register(app *kingpin.Application, envVars EnvVarNames, re // Check Command checkCmd.Arg("rule-files", "The rule files to check.").ExistingFilesVar(&r.RuleFilesList) - checkCmd.Flag("rule-files", "The rule files to check. Flag can be reused to load multiple files.").Hidden().StringVar(&r.RuleFiles) // TODO: Remove flag in Mimir 2.14. checkCmd.Flag( "rule-dirs", "Comma separated list of paths to directories containing rules yaml files. Each file in a directory with a .yml or .yaml suffix will be parsed.", @@ -349,19 +343,6 @@ func (r *RuleCommand) setupArgs() error { } } - // TODO: Remove statement in Mimir 2.14. - if r.RuleFiles != "" { - log.Warn("flag --rule-files is deprecated, use the argument instead") - for _, file := range strings.Split(r.RuleFiles, ",") { - if file != "" { - log.WithFields(log.Fields{ - "file": file, - }).Debugf("adding file") - r.RuleFilesList = append(r.RuleFilesList, file) - } - } - } - for _, dir := range strings.Split(r.RuleFilesPath, ",") { if dir != "" { err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { diff --git a/pkg/querier/blocks_store_queryable.go b/pkg/querier/blocks_store_queryable.go index 44dc2fa323e..4a1459565e6 100644 --- a/pkg/querier/blocks_store_queryable.go +++ b/pkg/querier/blocks_store_queryable.go @@ -263,9 +263,6 @@ func NewBlocksStoreQueryableFromConfig(querierCfg Config, gatewayCfg storegatewa ) streamingBufferSize := querierCfg.StreamingChunksPerStoreGatewaySeriesBufferSize - if !querierCfg.PreferStreamingChunksFromStoreGateways { - streamingBufferSize = 0 - } return NewBlocksStoreQueryable(stores, finder, consistency, limits, querierCfg.QueryStoreAfter, streamingBufferSize, logger, reg) } diff --git a/pkg/querier/querier.go b/pkg/querier/querier.go index ed59fb58ba0..576678a581c 100644 --- a/pkg/querier/querier.go +++ b/pkg/querier/querier.go @@ -50,7 +50,6 @@ type Config struct { ShuffleShardingIngestersEnabled bool `yaml:"shuffle_sharding_ingesters_enabled" category:"advanced"` - PreferStreamingChunksFromStoreGateways bool `yaml:"prefer_streaming_chunks_from_store_gateways" category:"experimental"` // Enabled by default as of Mimir 2.13, remove altogether in 2.14. PreferAvailabilityZone string `yaml:"prefer_availability_zone" category:"experimental" doc:"hidden"` StreamingChunksPerIngesterSeriesBufferSize uint64 `yaml:"streaming_chunks_per_ingester_series_buffer_size" category:"advanced"` StreamingChunksPerStoreGatewaySeriesBufferSize uint64 `yaml:"streaming_chunks_per_store_gateway_series_buffer_size" category:"advanced"` @@ -77,7 +76,6 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet) { f.DurationVar(&cfg.MaxQueryIntoFuture, "querier.max-query-into-future", 10*time.Minute, "Maximum duration into the future you can query. 0 to disable.") f.DurationVar(&cfg.QueryStoreAfter, queryStoreAfterFlag, 12*time.Hour, "The time after which a metric should be queried from storage and not just ingesters. 0 means all queries are sent to store. If this option is enabled, the time range of the query sent to the store-gateway will be manipulated to ensure the query end is not more recent than 'now - query-store-after'.") f.BoolVar(&cfg.ShuffleShardingIngestersEnabled, "querier.shuffle-sharding-ingesters-enabled", true, fmt.Sprintf("Fetch in-memory series from the minimum set of required ingesters, selecting only ingesters which may have received series since -%s. If this setting is false or -%s is '0', queriers always query all ingesters (ingesters shuffle sharding on read path is disabled).", validation.QueryIngestersWithinFlag, validation.QueryIngestersWithinFlag)) - f.BoolVar(&cfg.PreferStreamingChunksFromStoreGateways, "querier.prefer-streaming-chunks-from-store-gateways", true, "Request store-gateways stream chunks. Store-gateways will only respond with a stream of chunks if the target store-gateway supports this, and this preference will be ignored by store-gateways that do not support this.") f.StringVar(&cfg.PreferAvailabilityZone, "querier.prefer-availability-zone", "", "Preferred availability zone to query ingesters from when using the ingest storage.") const minimiseIngesterRequestsFlagName = "querier.minimize-ingester-requests" diff --git a/pkg/storage/tsdb/config.go b/pkg/storage/tsdb/config.go index d248103c6cf..700594a53ff 100644 --- a/pkg/storage/tsdb/config.go +++ b/pkg/storage/tsdb/config.go @@ -21,7 +21,6 @@ import ( "github.com/grafana/mimir/pkg/ingester/activeseries" "github.com/grafana/mimir/pkg/storage/bucket" "github.com/grafana/mimir/pkg/storegateway/indexheader" - "github.com/grafana/mimir/pkg/util" ) const ( @@ -416,25 +415,8 @@ type BucketStoreConfig struct { // Controls advanced options for index-header file reading. IndexHeader indexheader.Config `yaml:"index_header" category:"advanced"` - StreamingBatchSize int `yaml:"streaming_series_batch_size" category:"advanced"` - SeriesSelectionStrategyName string `yaml:"series_selection_strategy" category:"experimental"` - SelectionStrategies struct { - WorstCaseSeriesPreference float64 `yaml:"worst_case_series_preference" category:"experimental"` - } `yaml:"series_selection_strategies"` -} - -const ( - SpeculativePostingsStrategy = "speculative" - WorstCasePostingsStrategy = "worst-case" - WorstCaseSmallPostingListsPostingsStrategy = "worst-case-small-posting-lists" - AllPostingsStrategy = "all" -) - -var validSeriesSelectionStrategies = []string{ - SpeculativePostingsStrategy, - WorstCasePostingsStrategy, - WorstCaseSmallPostingListsPostingsStrategy, - AllPostingsStrategy, + StreamingBatchSize int `yaml:"streaming_series_batch_size" category:"advanced"` + SeriesFetchPreference float64 `yaml:"series_fetch_preference" category:"advanced"` } // RegisterFlags registers the BucketStore flags @@ -459,8 +441,7 @@ func (cfg *BucketStoreConfig) RegisterFlags(f *flag.FlagSet) { f.IntVar(&cfg.PostingOffsetsInMemSampling, "blocks-storage.bucket-store.posting-offsets-in-mem-sampling", DefaultPostingOffsetInMemorySampling, "Controls what is the ratio of postings offsets that the store will hold in memory.") f.Uint64Var(&cfg.PartitionerMaxGapBytes, "blocks-storage.bucket-store.partitioner-max-gap-bytes", DefaultPartitionerMaxGapSize, "Max size - in bytes - of a gap for which the partitioner aggregates together two bucket GET object requests.") f.IntVar(&cfg.StreamingBatchSize, "blocks-storage.bucket-store.batch-series-size", 5000, "This option controls how many series to fetch per batch. The batch size must be greater than 0.") - f.StringVar(&cfg.SeriesSelectionStrategyName, seriesSelectionStrategyFlag, WorstCasePostingsStrategy, "This option controls the strategy to selection of series and deferring application of matchers. A more aggressive strategy will fetch less posting lists at the cost of more series. This is useful when querying large blocks in which many series share the same label name and value. Supported values (most aggressive to least aggressive): "+strings.Join(validSeriesSelectionStrategies, ", ")+".") - f.Float64Var(&cfg.SelectionStrategies.WorstCaseSeriesPreference, "blocks-storage.bucket-store.series-selection-strategies.worst-case-series-preference", 0.75, "This option is only used when "+seriesSelectionStrategyFlag+"="+WorstCasePostingsStrategy+". Increasing the series preference results in fetching more series than postings. Must be a positive floating point number.") + f.Float64Var(&cfg.SeriesFetchPreference, "blocks-storage.bucket-store.series-fetch-preference", 0.75, "This parameter controls the trade-off in fetching series versus fetching postings to fulfill a series request. Increasing the series preference results in fetching more series and reducing the volume of postings fetched. Reducing the series preference results in the opposite. Increase this parameter to reduce the rate of fetched series bytes (see \"Mimir / Queries\" dashboard) or API calls to the object store. Must be a positive floating point number.") } // Validate the config. @@ -480,10 +461,7 @@ func (cfg *BucketStoreConfig) Validate() error { if err := cfg.BucketIndex.Validate(); err != nil { return errors.Wrap(err, "bucket-index configuration") } - if !util.StringsContain(validSeriesSelectionStrategies, cfg.SeriesSelectionStrategyName) { - return errors.New("invalid series-selection-strategy, set one of " + strings.Join(validSeriesSelectionStrategies, ", ")) - } - if cfg.SeriesSelectionStrategyName == WorstCasePostingsStrategy && cfg.SelectionStrategies.WorstCaseSeriesPreference <= 0 { + if cfg.SeriesFetchPreference <= 0 { return errors.New("invalid worst-case series preference; must be positive") } if err := cfg.IndexHeader.Validate(); err != nil { diff --git a/pkg/storegateway/bucket.go b/pkg/storegateway/bucket.go index 14197159759..c892f1fd45d 100644 --- a/pkg/storegateway/bucket.go +++ b/pkg/storegateway/bucket.go @@ -1567,7 +1567,7 @@ func (s *BucketStore) LabelValues(ctx context.Context, req *storepb.LabelValuesR // This index reader shouldn't be used for ExpandedPostings, since it doesn't have the correct strategy. // It's here only to make sure the block is held open inside the goroutine below. - indexr := b.indexReader(selectAllStrategy{}) + indexr := b.indexReader(nil) g.Go(func() error { defer runutil.CloseWithLogOnErr(b.logger, indexr, "close block index reader") diff --git a/pkg/storegateway/bucket_e2e_test.go b/pkg/storegateway/bucket_e2e_test.go index bd1ddf694a4..f46d06ff848 100644 --- a/pkg/storegateway/bucket_e2e_test.go +++ b/pkg/storegateway/bucket_e2e_test.go @@ -793,6 +793,7 @@ func TestBucketStore_PersistsLazyLoadedBlocks(t *testing.T) { cfg.logger = test.NewTestingLogger(t) cfg.bucketStoreConfig.IndexHeader.EagerLoadingPersistInterval = persistInterval cfg.bucketStoreConfig.IndexHeader.EagerLoadingStartupEnabled = true + cfg.bucketStoreConfig.IndexHeader.LazyLoadingIdleTimeout = persistInterval * 3 ctx := context.Background() // Start the store so we generate some blocks and can use them in the mock snapshot. @@ -816,6 +817,15 @@ func TestBucketStore_PersistsLazyLoadedBlocks(t *testing.T) { blocks, err = indexheader.RestoreLoadedBlocks(cfg.tempDir) assert.NoError(t, err) assert.Len(t, blocks, cfg.numBlocks) + + // Wait for the blocks to be unloaded. + // Technically we need to wait for 3x persistInterval, and we've already waited 2x since last using the blocks. + // But we give some more time to avoid races. + time.Sleep(persistInterval * 2) + // The snapshot should be empty. + blocks, err = indexheader.RestoreLoadedBlocks(cfg.tempDir) + assert.NoError(t, err) + assert.Empty(t, blocks) } type staticLoadedBlocks map[ulid.ULID]int64 diff --git a/pkg/storegateway/bucket_index_postings.go b/pkg/storegateway/bucket_index_postings.go index b94a50d2906..70d25628420 100644 --- a/pkg/storegateway/bucket_index_postings.go +++ b/pkg/storegateway/bucket_index_postings.go @@ -336,16 +336,6 @@ type postingsSelectionStrategy interface { selectPostings([]postingGroup) (selected, omitted []postingGroup) } -type selectAllStrategy struct{} - -func (selectAllStrategy) name() string { - return tsdb.AllPostingsStrategy -} - -func (selectAllStrategy) selectPostings(groups []postingGroup) (selected, omitted []postingGroup) { - return groups, nil -} - // worstCaseFetchedDataStrategy select a few of the posting groups such that their total size // does not exceed the size of series in the worst case. The worst case is fetching all series // in the smallest non-subtractive posting group - this is effectively the @@ -376,7 +366,7 @@ type worstCaseFetchedDataStrategy struct { } func (s worstCaseFetchedDataStrategy) name() string { - return fmt.Sprintf(tsdb.WorstCasePostingsStrategy+"%0.1f", s.postingListActualSizeFactor) + return fmt.Sprintf("worst-case%0.1f", s.postingListActualSizeFactor) } func (s worstCaseFetchedDataStrategy) selectPostings(groups []postingGroup) (selected, omitted []postingGroup) { @@ -443,53 +433,6 @@ func numSeriesInSmallestIntersectingPostingGroup(groups []postingGroup) int64 { return minGroupSize / tsdb.BytesPerPostingInAPostingList } -// speculativeFetchedDataStrategy selects postings lists in a very similar way to worstCaseFetchedDataStrategy, -// except it speculates on the size of the actual series after intersecting the selected posting lists. -// Right now it assumes that each intersecting posting list will halve the number of series selected by the query. -// -// For example, given the query `cpu_seconds_total{namespace="ns1"}`, if `namespace="ns1"` selects 1M series and -// `__name__="cpu_seconds_total"` selects 500K series, then the speculative strategy assumes the whole query will -// select 250K series. It uses this to calculate that in the worst case we will fetch 250K * tsdb.EstimatedSeriesP99Size -// bytes for the series = 128 MB. So it will not fetch more than 128 MB of posting lists. -type speculativeFetchedDataStrategy struct{} - -func (s speculativeFetchedDataStrategy) name() string { - return tsdb.SpeculativePostingsStrategy -} - -func (s speculativeFetchedDataStrategy) selectPostings(groups []postingGroup) (selected, omitted []postingGroup) { - sort.Slice(groups, func(i, j int) bool { - return groups[i].totalSize < groups[j].totalSize - }) - - maxSelectedSeriesCount := numSeriesInSmallestIntersectingPostingGroup(groups) - if maxSelectedSeriesCount == 0 { - // This should also cover the case of all postings group. all postings is requested only when there is no - // additive group. - return groups, nil - } - - var ( - selectedSize int64 - atLeastOneIntersectingSelected bool - maxSelectedSize = maxSelectedSeriesCount * tsdb.EstimatedSeriesP99Size - ) - for i, g := range groups { - if atLeastOneIntersectingSelected && selectedSize+g.totalSize > maxSelectedSize { - return groups[:i], groups[i:] - } - selectedSize += g.totalSize - atLeastOneIntersectingSelected = atLeastOneIntersectingSelected || !g.isSubtract - - // We assume that every intersecting posting list after the first one will - // filter out half of the postings. - if i > 0 && !g.isSubtract { - maxSelectedSize /= 2 - } - } - return groups, nil -} - // labelValuesPostingsStrategy works in a similar way to worstCaseFetchedDataStrategy. // The differences are: // - it doesn't a factor for the posting list size diff --git a/pkg/storegateway/bucket_index_postings_test.go b/pkg/storegateway/bucket_index_postings_test.go index 08dcc4f99c7..3f0eccdb667 100644 --- a/pkg/storegateway/bucket_index_postings_test.go +++ b/pkg/storegateway/bucket_index_postings_test.go @@ -141,115 +141,6 @@ func TestWorstCaseFetchedDataStrategy(t *testing.T) { } } -func TestSpeculativeFetchedDataStrategy(t *testing.T) { - testCases := map[string]struct { - input []postingGroup - expectedSelected []postingGroup - expectedOmitted []postingGroup - }{ - "single posting group is selected": { - input: []postingGroup{ - {totalSize: 128}, - }, - expectedSelected: []postingGroup{ - {totalSize: 128}, - }, - }, - "only all-postings & subtracting groups": { - input: []postingGroup{ - {totalSize: 0 /* all-postings doesn't have a size at the moment */, keys: []labels.Label{allPostingsKey}}, - {isSubtract: true, totalSize: 128}, - {isSubtract: true, totalSize: 64 * 1024 * 1024}, - }, - expectedSelected: []postingGroup{ - {totalSize: 0, keys: []labels.Label{allPostingsKey}}, - {isSubtract: true, totalSize: 128}, - {isSubtract: true, totalSize: 64 * 1024 * 1024}, - }, - }, - "only small posting lists": { - input: []postingGroup{ - {totalSize: 1024}, - {totalSize: 256}, - {totalSize: 128}, - }, - expectedSelected: []postingGroup{ - {totalSize: 1024}, - {totalSize: 256}, - {totalSize: 128}, - }, - }, - "two small and one large list": { - input: []postingGroup{ - {totalSize: 64 * 1024 * 1024}, - {totalSize: 256}, - {totalSize: 128}, - }, - expectedSelected: []postingGroup{ - {totalSize: 256}, - {totalSize: 128}, - }, - expectedOmitted: []postingGroup{ - {totalSize: 64 * 1024 * 1024}, - }, - }, - "one small and two mid size lists - last is omitted (more aggressive than worstCase)": { - input: []postingGroup{ - {totalSize: 128}, - {totalSize: 4 * 1024}, - {totalSize: 4 * 1024}, - }, - expectedSelected: []postingGroup{ - {totalSize: 128}, - {totalSize: 4 * 1024}, - }, - expectedOmitted: []postingGroup{ - {totalSize: 4 * 1024}, - }, - }, - "subtractive lists are not taken into consideration for halving number of postings": { - input: []postingGroup{ - {totalSize: 128}, - {isSubtract: true, totalSize: 256}, - {isSubtract: true, totalSize: 512}, - {totalSize: 4 * 1024}, - {totalSize: 4 * 1024}, - }, - expectedSelected: []postingGroup{ - {totalSize: 128}, - {isSubtract: true, totalSize: 256}, - {isSubtract: true, totalSize: 512}, - {totalSize: 4 * 1024}, - }, - expectedOmitted: []postingGroup{ - {totalSize: 4 * 1024}, - }, - }, - "x": { - input: []postingGroup{ - {totalSize: 4 * 1024 * 1024}, - {totalSize: 32*1024 + 4}, - {totalSize: 32*1024 + 4}, - }, - expectedSelected: []postingGroup{ - {totalSize: 32*1024 + 4}, - {totalSize: 32*1024 + 4}, - }, - expectedOmitted: []postingGroup{ - {totalSize: 4 * 1024 * 1024}, - }, - }, - } - - for testName, testCase := range testCases { - t.Run(testName, func(t *testing.T) { - actualSelected, actualOmitted := speculativeFetchedDataStrategy{}.selectPostings(testCase.input) - assert.ElementsMatch(t, testCase.expectedSelected, actualSelected) - assert.ElementsMatch(t, testCase.expectedOmitted, actualOmitted) - }) - } -} - func TestLabelValuesPostingsStrategy(t *testing.T) { testCases := map[string]struct { postingLists []streamindex.PostingListOffset diff --git a/pkg/storegateway/bucket_stores.go b/pkg/storegateway/bucket_stores.go index 4bcaf8b418c..f8366c60e5e 100644 --- a/pkg/storegateway/bucket_stores.go +++ b/pkg/storegateway/bucket_stores.go @@ -532,7 +532,7 @@ func (u *BucketStores) getOrCreateStore(ctx context.Context, userID string) (*Bu fetcher, u.syncDirForUser(userID), u.cfg.BucketStore, - selectPostingsStrategy(u.logger, u.cfg.BucketStore.SeriesSelectionStrategyName, u.cfg.BucketStore.SelectionStrategies.WorstCaseSeriesPreference), + worstCaseFetchedDataStrategy{postingListActualSizeFactor: u.cfg.BucketStore.SeriesFetchPreference}, NewChunksLimiterFactory(func() uint64 { return uint64(u.limits.MaxChunksPerQuery(userID)) }), @@ -557,24 +557,6 @@ func (u *BucketStores) getOrCreateStore(ctx context.Context, userID string) (*Bu return bs, nil } -func selectPostingsStrategy(l log.Logger, name string, worstCaseSeriesPreference float64) postingsSelectionStrategy { - switch name { - case tsdb.AllPostingsStrategy: - return selectAllStrategy{} - case tsdb.SpeculativePostingsStrategy: - return speculativeFetchedDataStrategy{} - case tsdb.WorstCasePostingsStrategy: - return worstCaseFetchedDataStrategy{postingListActualSizeFactor: worstCaseSeriesPreference} - case tsdb.WorstCaseSmallPostingListsPostingsStrategy: - return worstCaseFetchedDataStrategy{postingListActualSizeFactor: 0.3} - default: - // This should only be reached if the tsdb package has mismatching names for these strategies. - // Prefer keeping the store-gateway running as opposed to failing, since strategies are still an experimental feature anyway. - level.Warn(l).Log("msg", "unknown posting strategy; using "+tsdb.AllPostingsStrategy+" instead", "strategy", name) - return selectAllStrategy{} - } -} - // closeBucketStoreAndDeleteLocalFilesForExcludedTenants closes bucket store and removes local "sync" directories // for tenants that are not included in the current shard. func (u *BucketStores) closeBucketStoreAndDeleteLocalFilesForExcludedTenants(includedUserIDs []string) { diff --git a/pkg/storegateway/bucket_test.go b/pkg/storegateway/bucket_test.go index c906e5bbf0b..98d658d38ef 100644 --- a/pkg/storegateway/bucket_test.go +++ b/pkg/storegateway/bucket_test.go @@ -561,6 +561,16 @@ func (o omitMatchersStrategy) selectPostings(groups []postingGroup) (selected, o return } +type selectAllStrategy struct{} + +func (selectAllStrategy) name() string { + return "all" +} + +func (selectAllStrategy) selectPostings(groups []postingGroup) (selected, omitted []postingGroup) { + return groups, nil +} + func TestBucketIndexReader_ExpandedPostings(t *testing.T) { tb := test.NewTB(t) const series = 50000 diff --git a/vendor/github.com/cespare/xxhash/LICENSE.txt b/vendor/github.com/cespare/xxhash/LICENSE.txt deleted file mode 100644 index 24b53065f40..00000000000 --- a/vendor/github.com/cespare/xxhash/LICENSE.txt +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2016 Caleb Spare - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/cespare/xxhash/README.md b/vendor/github.com/cespare/xxhash/README.md deleted file mode 100644 index 0982fd25e5c..00000000000 --- a/vendor/github.com/cespare/xxhash/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# xxhash - -[![GoDoc](https://godoc.org/github.com/cespare/xxhash?status.svg)](https://godoc.org/github.com/cespare/xxhash) - -xxhash is a Go implementation of the 64-bit -[xxHash](http://cyan4973.github.io/xxHash/) algorithm, XXH64. This is a -high-quality hashing algorithm that is much faster than anything in the Go -standard library. - -The API is very small, taking its cue from the other hashing packages in the -standard library: - - $ go doc github.com/cespare/xxhash ! - package xxhash // import "github.com/cespare/xxhash" - - Package xxhash implements the 64-bit variant of xxHash (XXH64) as described - at http://cyan4973.github.io/xxHash/. - - func New() hash.Hash64 - func Sum64(b []byte) uint64 - func Sum64String(s string) uint64 - -This implementation provides a fast pure-Go implementation and an even faster -assembly implementation for amd64. - -## Benchmarks - -Here are some quick benchmarks comparing the pure-Go and assembly -implementations of Sum64 against another popular Go XXH64 implementation, -[github.com/OneOfOne/xxhash](https://github.com/OneOfOne/xxhash): - -| input size | OneOfOne | cespare (purego) | cespare | -| --- | --- | --- | --- | -| 5 B | 416 MB/s | 720 MB/s | 872 MB/s | -| 100 B | 3980 MB/s | 5013 MB/s | 5252 MB/s | -| 4 KB | 12727 MB/s | 12999 MB/s | 13026 MB/s | -| 10 MB | 9879 MB/s | 10775 MB/s | 10913 MB/s | - -These numbers were generated with: - -``` -$ go test -benchtime 10s -bench '/OneOfOne,' -$ go test -tags purego -benchtime 10s -bench '/xxhash,' -$ go test -benchtime 10s -bench '/xxhash,' -``` - -## Projects using this package - -- [InfluxDB](https://github.com/influxdata/influxdb) -- [Prometheus](https://github.com/prometheus/prometheus) diff --git a/vendor/github.com/cespare/xxhash/rotate.go b/vendor/github.com/cespare/xxhash/rotate.go deleted file mode 100644 index f3eac5ebc02..00000000000 --- a/vendor/github.com/cespare/xxhash/rotate.go +++ /dev/null @@ -1,14 +0,0 @@ -// +build !go1.9 - -package xxhash - -// TODO(caleb): After Go 1.10 comes out, remove this fallback code. - -func rol1(x uint64) uint64 { return (x << 1) | (x >> (64 - 1)) } -func rol7(x uint64) uint64 { return (x << 7) | (x >> (64 - 7)) } -func rol11(x uint64) uint64 { return (x << 11) | (x >> (64 - 11)) } -func rol12(x uint64) uint64 { return (x << 12) | (x >> (64 - 12)) } -func rol18(x uint64) uint64 { return (x << 18) | (x >> (64 - 18)) } -func rol23(x uint64) uint64 { return (x << 23) | (x >> (64 - 23)) } -func rol27(x uint64) uint64 { return (x << 27) | (x >> (64 - 27)) } -func rol31(x uint64) uint64 { return (x << 31) | (x >> (64 - 31)) } diff --git a/vendor/github.com/cespare/xxhash/rotate19.go b/vendor/github.com/cespare/xxhash/rotate19.go deleted file mode 100644 index b99612bab88..00000000000 --- a/vendor/github.com/cespare/xxhash/rotate19.go +++ /dev/null @@ -1,14 +0,0 @@ -// +build go1.9 - -package xxhash - -import "math/bits" - -func rol1(x uint64) uint64 { return bits.RotateLeft64(x, 1) } -func rol7(x uint64) uint64 { return bits.RotateLeft64(x, 7) } -func rol11(x uint64) uint64 { return bits.RotateLeft64(x, 11) } -func rol12(x uint64) uint64 { return bits.RotateLeft64(x, 12) } -func rol18(x uint64) uint64 { return bits.RotateLeft64(x, 18) } -func rol23(x uint64) uint64 { return bits.RotateLeft64(x, 23) } -func rol27(x uint64) uint64 { return bits.RotateLeft64(x, 27) } -func rol31(x uint64) uint64 { return bits.RotateLeft64(x, 31) } diff --git a/vendor/github.com/cespare/xxhash/xxhash.go b/vendor/github.com/cespare/xxhash/xxhash.go deleted file mode 100644 index f896bd28f05..00000000000 --- a/vendor/github.com/cespare/xxhash/xxhash.go +++ /dev/null @@ -1,168 +0,0 @@ -// Package xxhash implements the 64-bit variant of xxHash (XXH64) as described -// at http://cyan4973.github.io/xxHash/. -package xxhash - -import ( - "encoding/binary" - "hash" -) - -const ( - prime1 uint64 = 11400714785074694791 - prime2 uint64 = 14029467366897019727 - prime3 uint64 = 1609587929392839161 - prime4 uint64 = 9650029242287828579 - prime5 uint64 = 2870177450012600261 -) - -// NOTE(caleb): I'm using both consts and vars of the primes. Using consts where -// possible in the Go code is worth a small (but measurable) performance boost -// by avoiding some MOVQs. Vars are needed for the asm and also are useful for -// convenience in the Go code in a few places where we need to intentionally -// avoid constant arithmetic (e.g., v1 := prime1 + prime2 fails because the -// result overflows a uint64). -var ( - prime1v = prime1 - prime2v = prime2 - prime3v = prime3 - prime4v = prime4 - prime5v = prime5 -) - -type xxh struct { - v1 uint64 - v2 uint64 - v3 uint64 - v4 uint64 - total int - mem [32]byte - n int // how much of mem is used -} - -// New creates a new hash.Hash64 that implements the 64-bit xxHash algorithm. -func New() hash.Hash64 { - var x xxh - x.Reset() - return &x -} - -func (x *xxh) Reset() { - x.n = 0 - x.total = 0 - x.v1 = prime1v + prime2 - x.v2 = prime2 - x.v3 = 0 - x.v4 = -prime1v -} - -func (x *xxh) Size() int { return 8 } -func (x *xxh) BlockSize() int { return 32 } - -// Write adds more data to x. It always returns len(b), nil. -func (x *xxh) Write(b []byte) (n int, err error) { - n = len(b) - x.total += len(b) - - if x.n+len(b) < 32 { - // This new data doesn't even fill the current block. - copy(x.mem[x.n:], b) - x.n += len(b) - return - } - - if x.n > 0 { - // Finish off the partial block. - copy(x.mem[x.n:], b) - x.v1 = round(x.v1, u64(x.mem[0:8])) - x.v2 = round(x.v2, u64(x.mem[8:16])) - x.v3 = round(x.v3, u64(x.mem[16:24])) - x.v4 = round(x.v4, u64(x.mem[24:32])) - b = b[32-x.n:] - x.n = 0 - } - - if len(b) >= 32 { - // One or more full blocks left. - b = writeBlocks(x, b) - } - - // Store any remaining partial block. - copy(x.mem[:], b) - x.n = len(b) - - return -} - -func (x *xxh) Sum(b []byte) []byte { - s := x.Sum64() - return append( - b, - byte(s>>56), - byte(s>>48), - byte(s>>40), - byte(s>>32), - byte(s>>24), - byte(s>>16), - byte(s>>8), - byte(s), - ) -} - -func (x *xxh) Sum64() uint64 { - var h uint64 - - if x.total >= 32 { - v1, v2, v3, v4 := x.v1, x.v2, x.v3, x.v4 - h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4) - h = mergeRound(h, v1) - h = mergeRound(h, v2) - h = mergeRound(h, v3) - h = mergeRound(h, v4) - } else { - h = x.v3 + prime5 - } - - h += uint64(x.total) - - i, end := 0, x.n - for ; i+8 <= end; i += 8 { - k1 := round(0, u64(x.mem[i:i+8])) - h ^= k1 - h = rol27(h)*prime1 + prime4 - } - if i+4 <= end { - h ^= uint64(u32(x.mem[i:i+4])) * prime1 - h = rol23(h)*prime2 + prime3 - i += 4 - } - for i < end { - h ^= uint64(x.mem[i]) * prime5 - h = rol11(h) * prime1 - i++ - } - - h ^= h >> 33 - h *= prime2 - h ^= h >> 29 - h *= prime3 - h ^= h >> 32 - - return h -} - -func u64(b []byte) uint64 { return binary.LittleEndian.Uint64(b) } -func u32(b []byte) uint32 { return binary.LittleEndian.Uint32(b) } - -func round(acc, input uint64) uint64 { - acc += input * prime2 - acc = rol31(acc) - acc *= prime1 - return acc -} - -func mergeRound(acc, val uint64) uint64 { - val = round(0, val) - acc ^= val - acc = acc*prime1 + prime4 - return acc -} diff --git a/vendor/github.com/cespare/xxhash/xxhash_amd64.go b/vendor/github.com/cespare/xxhash/xxhash_amd64.go deleted file mode 100644 index d6176526802..00000000000 --- a/vendor/github.com/cespare/xxhash/xxhash_amd64.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build !appengine -// +build gc -// +build !purego - -package xxhash - -// Sum64 computes the 64-bit xxHash digest of b. -// -//go:noescape -func Sum64(b []byte) uint64 - -func writeBlocks(x *xxh, b []byte) []byte diff --git a/vendor/github.com/cespare/xxhash/xxhash_amd64.s b/vendor/github.com/cespare/xxhash/xxhash_amd64.s deleted file mode 100644 index 757f2011f0f..00000000000 --- a/vendor/github.com/cespare/xxhash/xxhash_amd64.s +++ /dev/null @@ -1,233 +0,0 @@ -// +build !appengine -// +build gc -// +build !purego - -#include "textflag.h" - -// Register allocation: -// AX h -// CX pointer to advance through b -// DX n -// BX loop end -// R8 v1, k1 -// R9 v2 -// R10 v3 -// R11 v4 -// R12 tmp -// R13 prime1v -// R14 prime2v -// R15 prime4v - -// round reads from and advances the buffer pointer in CX. -// It assumes that R13 has prime1v and R14 has prime2v. -#define round(r) \ - MOVQ (CX), R12 \ - ADDQ $8, CX \ - IMULQ R14, R12 \ - ADDQ R12, r \ - ROLQ $31, r \ - IMULQ R13, r - -// mergeRound applies a merge round on the two registers acc and val. -// It assumes that R13 has prime1v, R14 has prime2v, and R15 has prime4v. -#define mergeRound(acc, val) \ - IMULQ R14, val \ - ROLQ $31, val \ - IMULQ R13, val \ - XORQ val, acc \ - IMULQ R13, acc \ - ADDQ R15, acc - -// func Sum64(b []byte) uint64 -TEXT ·Sum64(SB), NOSPLIT, $0-32 - // Load fixed primes. - MOVQ ·prime1v(SB), R13 - MOVQ ·prime2v(SB), R14 - MOVQ ·prime4v(SB), R15 - - // Load slice. - MOVQ b_base+0(FP), CX - MOVQ b_len+8(FP), DX - LEAQ (CX)(DX*1), BX - - // The first loop limit will be len(b)-32. - SUBQ $32, BX - - // Check whether we have at least one block. - CMPQ DX, $32 - JLT noBlocks - - // Set up initial state (v1, v2, v3, v4). - MOVQ R13, R8 - ADDQ R14, R8 - MOVQ R14, R9 - XORQ R10, R10 - XORQ R11, R11 - SUBQ R13, R11 - - // Loop until CX > BX. -blockLoop: - round(R8) - round(R9) - round(R10) - round(R11) - - CMPQ CX, BX - JLE blockLoop - - MOVQ R8, AX - ROLQ $1, AX - MOVQ R9, R12 - ROLQ $7, R12 - ADDQ R12, AX - MOVQ R10, R12 - ROLQ $12, R12 - ADDQ R12, AX - MOVQ R11, R12 - ROLQ $18, R12 - ADDQ R12, AX - - mergeRound(AX, R8) - mergeRound(AX, R9) - mergeRound(AX, R10) - mergeRound(AX, R11) - - JMP afterBlocks - -noBlocks: - MOVQ ·prime5v(SB), AX - -afterBlocks: - ADDQ DX, AX - - // Right now BX has len(b)-32, and we want to loop until CX > len(b)-8. - ADDQ $24, BX - - CMPQ CX, BX - JG fourByte - -wordLoop: - // Calculate k1. - MOVQ (CX), R8 - ADDQ $8, CX - IMULQ R14, R8 - ROLQ $31, R8 - IMULQ R13, R8 - - XORQ R8, AX - ROLQ $27, AX - IMULQ R13, AX - ADDQ R15, AX - - CMPQ CX, BX - JLE wordLoop - -fourByte: - ADDQ $4, BX - CMPQ CX, BX - JG singles - - MOVL (CX), R8 - ADDQ $4, CX - IMULQ R13, R8 - XORQ R8, AX - - ROLQ $23, AX - IMULQ R14, AX - ADDQ ·prime3v(SB), AX - -singles: - ADDQ $4, BX - CMPQ CX, BX - JGE finalize - -singlesLoop: - MOVBQZX (CX), R12 - ADDQ $1, CX - IMULQ ·prime5v(SB), R12 - XORQ R12, AX - - ROLQ $11, AX - IMULQ R13, AX - - CMPQ CX, BX - JL singlesLoop - -finalize: - MOVQ AX, R12 - SHRQ $33, R12 - XORQ R12, AX - IMULQ R14, AX - MOVQ AX, R12 - SHRQ $29, R12 - XORQ R12, AX - IMULQ ·prime3v(SB), AX - MOVQ AX, R12 - SHRQ $32, R12 - XORQ R12, AX - - MOVQ AX, ret+24(FP) - RET - -// writeBlocks uses the same registers as above except that it uses AX to store -// the x pointer. - -// func writeBlocks(x *xxh, b []byte) []byte -TEXT ·writeBlocks(SB), NOSPLIT, $0-56 - // Load fixed primes needed for round. - MOVQ ·prime1v(SB), R13 - MOVQ ·prime2v(SB), R14 - - // Load slice. - MOVQ b_base+8(FP), CX - MOVQ CX, ret_base+32(FP) // initialize return base pointer; see NOTE below - MOVQ b_len+16(FP), DX - LEAQ (CX)(DX*1), BX - SUBQ $32, BX - - // Load vN from x. - MOVQ x+0(FP), AX - MOVQ 0(AX), R8 // v1 - MOVQ 8(AX), R9 // v2 - MOVQ 16(AX), R10 // v3 - MOVQ 24(AX), R11 // v4 - - // We don't need to check the loop condition here; this function is - // always called with at least one block of data to process. -blockLoop: - round(R8) - round(R9) - round(R10) - round(R11) - - CMPQ CX, BX - JLE blockLoop - - // Copy vN back to x. - MOVQ R8, 0(AX) - MOVQ R9, 8(AX) - MOVQ R10, 16(AX) - MOVQ R11, 24(AX) - - // Construct return slice. - // NOTE: It's important that we don't construct a slice that has a base - // pointer off the end of the original slice, as in Go 1.7+ this will - // cause runtime crashes. (See discussion in, for example, - // https://github.com/golang/go/issues/16772.) - // Therefore, we calculate the length/cap first, and if they're zero, we - // keep the old base. This is what the compiler does as well if you - // write code like - // b = b[len(b):] - - // New length is 32 - (CX - BX) -> BX+32 - CX. - ADDQ $32, BX - SUBQ CX, BX - JZ afterSetBase - - MOVQ CX, ret_base+32(FP) - -afterSetBase: - MOVQ BX, ret_len+40(FP) - MOVQ BX, ret_cap+48(FP) // set cap == len - - RET diff --git a/vendor/github.com/cespare/xxhash/xxhash_other.go b/vendor/github.com/cespare/xxhash/xxhash_other.go deleted file mode 100644 index c68d13f89e9..00000000000 --- a/vendor/github.com/cespare/xxhash/xxhash_other.go +++ /dev/null @@ -1,75 +0,0 @@ -// +build !amd64 appengine !gc purego - -package xxhash - -// Sum64 computes the 64-bit xxHash digest of b. -func Sum64(b []byte) uint64 { - // A simpler version would be - // x := New() - // x.Write(b) - // return x.Sum64() - // but this is faster, particularly for small inputs. - - n := len(b) - var h uint64 - - if n >= 32 { - v1 := prime1v + prime2 - v2 := prime2 - v3 := uint64(0) - v4 := -prime1v - for len(b) >= 32 { - v1 = round(v1, u64(b[0:8:len(b)])) - v2 = round(v2, u64(b[8:16:len(b)])) - v3 = round(v3, u64(b[16:24:len(b)])) - v4 = round(v4, u64(b[24:32:len(b)])) - b = b[32:len(b):len(b)] - } - h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4) - h = mergeRound(h, v1) - h = mergeRound(h, v2) - h = mergeRound(h, v3) - h = mergeRound(h, v4) - } else { - h = prime5 - } - - h += uint64(n) - - i, end := 0, len(b) - for ; i+8 <= end; i += 8 { - k1 := round(0, u64(b[i:i+8:len(b)])) - h ^= k1 - h = rol27(h)*prime1 + prime4 - } - if i+4 <= end { - h ^= uint64(u32(b[i:i+4:len(b)])) * prime1 - h = rol23(h)*prime2 + prime3 - i += 4 - } - for ; i < end; i++ { - h ^= uint64(b[i]) * prime5 - h = rol11(h) * prime1 - } - - h ^= h >> 33 - h *= prime2 - h ^= h >> 29 - h *= prime3 - h ^= h >> 32 - - return h -} - -func writeBlocks(x *xxh, b []byte) []byte { - v1, v2, v3, v4 := x.v1, x.v2, x.v3, x.v4 - for len(b) >= 32 { - v1 = round(v1, u64(b[0:8:len(b)])) - v2 = round(v2, u64(b[8:16:len(b)])) - v3 = round(v3, u64(b[16:24:len(b)])) - v4 = round(v4, u64(b[24:32:len(b)])) - b = b[32:len(b):len(b)] - } - x.v1, x.v2, x.v3, x.v4 = v1, v2, v3, v4 - return b -} diff --git a/vendor/github.com/cespare/xxhash/xxhash_safe.go b/vendor/github.com/cespare/xxhash/xxhash_safe.go deleted file mode 100644 index dfa15ab7e27..00000000000 --- a/vendor/github.com/cespare/xxhash/xxhash_safe.go +++ /dev/null @@ -1,10 +0,0 @@ -// +build appengine - -// This file contains the safe implementations of otherwise unsafe-using code. - -package xxhash - -// Sum64String computes the 64-bit xxHash digest of s. -func Sum64String(s string) uint64 { - return Sum64([]byte(s)) -} diff --git a/vendor/github.com/cespare/xxhash/xxhash_unsafe.go b/vendor/github.com/cespare/xxhash/xxhash_unsafe.go deleted file mode 100644 index d2b64e8bb00..00000000000 --- a/vendor/github.com/cespare/xxhash/xxhash_unsafe.go +++ /dev/null @@ -1,30 +0,0 @@ -// +build !appengine - -// This file encapsulates usage of unsafe. -// xxhash_safe.go contains the safe implementations. - -package xxhash - -import ( - "reflect" - "unsafe" -) - -// Sum64String computes the 64-bit xxHash digest of s. -// It may be faster than Sum64([]byte(s)) by avoiding a copy. -// -// TODO(caleb): Consider removing this if an optimization is ever added to make -// it unnecessary: https://golang.org/issue/2205. -// -// TODO(caleb): We still have a function call; we could instead write Go/asm -// copies of Sum64 for strings to squeeze out a bit more speed. -func Sum64String(s string) uint64 { - // See https://groups.google.com/d/msg/golang-nuts/dcjzJy-bSpw/tcZYBzQqAQAJ - // for some discussion about this unsafe conversion. - var b []byte - bh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) - bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data - bh.Len = len(s) - bh.Cap = len(s) - return Sum64(b) -} diff --git a/vendor/gopkg.in/ini.v1/.editorconfig b/vendor/github.com/go-ini/ini/.editorconfig similarity index 100% rename from vendor/gopkg.in/ini.v1/.editorconfig rename to vendor/github.com/go-ini/ini/.editorconfig diff --git a/vendor/gopkg.in/ini.v1/.gitignore b/vendor/github.com/go-ini/ini/.gitignore similarity index 100% rename from vendor/gopkg.in/ini.v1/.gitignore rename to vendor/github.com/go-ini/ini/.gitignore diff --git a/vendor/gopkg.in/ini.v1/.golangci.yml b/vendor/github.com/go-ini/ini/.golangci.yml similarity index 100% rename from vendor/gopkg.in/ini.v1/.golangci.yml rename to vendor/github.com/go-ini/ini/.golangci.yml diff --git a/vendor/gopkg.in/ini.v1/LICENSE b/vendor/github.com/go-ini/ini/LICENSE similarity index 100% rename from vendor/gopkg.in/ini.v1/LICENSE rename to vendor/github.com/go-ini/ini/LICENSE diff --git a/vendor/gopkg.in/ini.v1/Makefile b/vendor/github.com/go-ini/ini/Makefile similarity index 100% rename from vendor/gopkg.in/ini.v1/Makefile rename to vendor/github.com/go-ini/ini/Makefile diff --git a/vendor/gopkg.in/ini.v1/README.md b/vendor/github.com/go-ini/ini/README.md similarity index 100% rename from vendor/gopkg.in/ini.v1/README.md rename to vendor/github.com/go-ini/ini/README.md diff --git a/vendor/gopkg.in/ini.v1/codecov.yml b/vendor/github.com/go-ini/ini/codecov.yml similarity index 100% rename from vendor/gopkg.in/ini.v1/codecov.yml rename to vendor/github.com/go-ini/ini/codecov.yml diff --git a/vendor/gopkg.in/ini.v1/data_source.go b/vendor/github.com/go-ini/ini/data_source.go similarity index 100% rename from vendor/gopkg.in/ini.v1/data_source.go rename to vendor/github.com/go-ini/ini/data_source.go diff --git a/vendor/gopkg.in/ini.v1/deprecated.go b/vendor/github.com/go-ini/ini/deprecated.go similarity index 100% rename from vendor/gopkg.in/ini.v1/deprecated.go rename to vendor/github.com/go-ini/ini/deprecated.go diff --git a/vendor/gopkg.in/ini.v1/error.go b/vendor/github.com/go-ini/ini/error.go similarity index 100% rename from vendor/gopkg.in/ini.v1/error.go rename to vendor/github.com/go-ini/ini/error.go diff --git a/vendor/gopkg.in/ini.v1/file.go b/vendor/github.com/go-ini/ini/file.go similarity index 100% rename from vendor/gopkg.in/ini.v1/file.go rename to vendor/github.com/go-ini/ini/file.go diff --git a/vendor/gopkg.in/ini.v1/helper.go b/vendor/github.com/go-ini/ini/helper.go similarity index 100% rename from vendor/gopkg.in/ini.v1/helper.go rename to vendor/github.com/go-ini/ini/helper.go diff --git a/vendor/gopkg.in/ini.v1/ini.go b/vendor/github.com/go-ini/ini/ini.go similarity index 100% rename from vendor/gopkg.in/ini.v1/ini.go rename to vendor/github.com/go-ini/ini/ini.go diff --git a/vendor/gopkg.in/ini.v1/key.go b/vendor/github.com/go-ini/ini/key.go similarity index 100% rename from vendor/gopkg.in/ini.v1/key.go rename to vendor/github.com/go-ini/ini/key.go diff --git a/vendor/gopkg.in/ini.v1/parser.go b/vendor/github.com/go-ini/ini/parser.go similarity index 100% rename from vendor/gopkg.in/ini.v1/parser.go rename to vendor/github.com/go-ini/ini/parser.go diff --git a/vendor/gopkg.in/ini.v1/section.go b/vendor/github.com/go-ini/ini/section.go similarity index 100% rename from vendor/gopkg.in/ini.v1/section.go rename to vendor/github.com/go-ini/ini/section.go diff --git a/vendor/gopkg.in/ini.v1/struct.go b/vendor/github.com/go-ini/ini/struct.go similarity index 100% rename from vendor/gopkg.in/ini.v1/struct.go rename to vendor/github.com/go-ini/ini/struct.go diff --git a/vendor/github.com/grafana/dskit/cache/memcached_server_selector.go b/vendor/github.com/grafana/dskit/cache/memcached_server_selector.go index 60c9afe94fb..2ef53169919 100644 --- a/vendor/github.com/grafana/dskit/cache/memcached_server_selector.go +++ b/vendor/github.com/grafana/dskit/cache/memcached_server_selector.go @@ -7,7 +7,7 @@ import ( "net" "sync" - "github.com/cespare/xxhash" + "github.com/cespare/xxhash/v2" "github.com/facette/natsort" "github.com/grafana/gomemcache/memcache" ) diff --git a/vendor/github.com/grafana/dskit/cache/redis_client.go b/vendor/github.com/grafana/dskit/cache/redis_client.go index 1f0bb25cd31..cd9efb4c124 100644 --- a/vendor/github.com/grafana/dskit/cache/redis_client.go +++ b/vendor/github.com/grafana/dskit/cache/redis_client.go @@ -311,12 +311,7 @@ func (c *RedisClient) Name() string { return c.name } -// stringToBytes converts string to byte slice (copied from vendor/github.com/go-redis/redis/v8/internal/util/unsafe.go). +// stringToBytes converts string to byte slice. func stringToBytes(s string) []byte { - return *(*[]byte)(unsafe.Pointer( - &struct { - string - Cap int - }{s, len(s)}, - )) + return unsafe.Slice(unsafe.StringData(s), len(s)) } diff --git a/vendor/github.com/grafana/dskit/ring/shard/shard.go b/vendor/github.com/grafana/dskit/ring/shard/shard.go index 1d70eb6283b..26d695514c2 100644 --- a/vendor/github.com/grafana/dskit/ring/shard/shard.go +++ b/vendor/github.com/grafana/dskit/ring/shard/shard.go @@ -41,5 +41,5 @@ func ShuffleShardExpectedInstances(shardSize, numZones int) int { // yoloBuf will return an unsafe pointer to a string, as the name yolo.yoloBuf implies use at your own risk. func yoloBuf(s string) []byte { - return *((*[]byte)(unsafe.Pointer(&s))) + return unsafe.Slice(unsafe.StringData(s), len(s)) } diff --git a/vendor/github.com/minio/minio-go/v7/api-get-object.go b/vendor/github.com/minio/minio-go/v7/api-get-object.go index 9e6b1543c4d..d7fd27835ba 100644 --- a/vendor/github.com/minio/minio-go/v7/api-get-object.go +++ b/vendor/github.com/minio/minio-go/v7/api-get-object.go @@ -32,10 +32,18 @@ import ( func (c *Client) GetObject(ctx context.Context, bucketName, objectName string, opts GetObjectOptions) (*Object, error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { - return nil, err + return nil, ErrorResponse{ + StatusCode: http.StatusBadRequest, + Code: "InvalidBucketName", + Message: err.Error(), + } } if err := s3utils.CheckValidObjectName(objectName); err != nil { - return nil, err + return nil, ErrorResponse{ + StatusCode: http.StatusBadRequest, + Code: "XMinioInvalidObjectName", + Message: err.Error(), + } } gctx, cancel := context.WithCancel(ctx) @@ -649,10 +657,18 @@ func newObject(ctx context.Context, cancel context.CancelFunc, reqCh chan<- getR func (c *Client) getObject(ctx context.Context, bucketName, objectName string, opts GetObjectOptions) (io.ReadCloser, ObjectInfo, http.Header, error) { // Validate input arguments. if err := s3utils.CheckValidBucketName(bucketName); err != nil { - return nil, ObjectInfo{}, nil, err + return nil, ObjectInfo{}, nil, ErrorResponse{ + StatusCode: http.StatusBadRequest, + Code: "InvalidBucketName", + Message: err.Error(), + } } if err := s3utils.CheckValidObjectName(objectName); err != nil { - return nil, ObjectInfo{}, nil, err + return nil, ObjectInfo{}, nil, ErrorResponse{ + StatusCode: http.StatusBadRequest, + Code: "XMinioInvalidObjectName", + Message: err.Error(), + } } // Execute GET on objectName. diff --git a/vendor/github.com/minio/minio-go/v7/api-put-object-streaming.go b/vendor/github.com/minio/minio-go/v7/api-put-object-streaming.go index 9182d4eac32..51226630d2b 100644 --- a/vendor/github.com/minio/minio-go/v7/api-put-object-streaming.go +++ b/vendor/github.com/minio/minio-go/v7/api-put-object-streaming.go @@ -637,7 +637,9 @@ func (c *Client) putObjectMultipartStreamParallel(ctx context.Context, bucketNam // Sort all completed parts. sort.Sort(completedParts(complMultipartUpload.Parts)) - opts = PutObjectOptions{} + opts = PutObjectOptions{ + ServerSideEncryption: opts.ServerSideEncryption, + } if len(crcBytes) > 0 { // Add hash of hashes. crc.Reset() diff --git a/vendor/github.com/minio/minio-go/v7/api-put-object.go b/vendor/github.com/minio/minio-go/v7/api-put-object.go index a96de9b9f6a..6ccb5815670 100644 --- a/vendor/github.com/minio/minio-go/v7/api-put-object.go +++ b/vendor/github.com/minio/minio-go/v7/api-put-object.go @@ -464,7 +464,9 @@ func (c *Client) putObjectMultipartStreamNoLength(ctx context.Context, bucketNam // Sort all completed parts. sort.Sort(completedParts(complMultipartUpload.Parts)) - opts = PutObjectOptions{} + opts = PutObjectOptions{ + ServerSideEncryption: opts.ServerSideEncryption, + } if len(crcBytes) > 0 { // Add hash of hashes. crc.Reset() diff --git a/vendor/github.com/minio/minio-go/v7/api-stat.go b/vendor/github.com/minio/minio-go/v7/api-stat.go index b043dc40c95..11455beb3fa 100644 --- a/vendor/github.com/minio/minio-go/v7/api-stat.go +++ b/vendor/github.com/minio/minio-go/v7/api-stat.go @@ -61,10 +61,18 @@ func (c *Client) BucketExists(ctx context.Context, bucketName string) (bool, err func (c *Client) StatObject(ctx context.Context, bucketName, objectName string, opts StatObjectOptions) (ObjectInfo, error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { - return ObjectInfo{}, err + return ObjectInfo{}, ErrorResponse{ + StatusCode: http.StatusBadRequest, + Code: "InvalidBucketName", + Message: err.Error(), + } } if err := s3utils.CheckValidObjectName(objectName); err != nil { - return ObjectInfo{}, err + return ObjectInfo{}, ErrorResponse{ + StatusCode: http.StatusBadRequest, + Code: "XMinioInvalidObjectName", + Message: err.Error(), + } } headers := opts.Header() if opts.Internal.ReplicationDeleteMarker { diff --git a/vendor/github.com/minio/minio-go/v7/api.go b/vendor/github.com/minio/minio-go/v7/api.go index eaaaa68c22a..937551403e9 100644 --- a/vendor/github.com/minio/minio-go/v7/api.go +++ b/vendor/github.com/minio/minio-go/v7/api.go @@ -129,7 +129,7 @@ type Options struct { // Global constants. const ( libraryName = "minio-go" - libraryVersion = "v7.0.72" + libraryVersion = "v7.0.74" ) // User Agent should always following the below style. diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_aws_credentials.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_aws_credentials.go index 8c5c4eb2de6..541e1a72f0f 100644 --- a/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_aws_credentials.go +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_aws_credentials.go @@ -26,7 +26,7 @@ import ( "strings" "time" - ini "gopkg.in/ini.v1" + "github.com/go-ini/ini" ) // A externalProcessCredentials stores the output of a credential_process diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_minio_client.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_minio_client.go index f1c165b79b3..750e26ffa8b 100644 --- a/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_minio_client.go +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_minio_client.go @@ -39,7 +39,7 @@ type FileMinioClient struct { Filename string // MinIO Alias to extract credentials from the shared credentials file. If empty - // will default to environment variable "MINIO_ALIAS" or "default" if + // will default to environment variable "MINIO_ALIAS" or "s3" if // environment variable is also not set. Alias string diff --git a/vendor/github.com/minio/minio-go/v7/pkg/replication/replication.go b/vendor/github.com/minio/minio-go/v7/pkg/replication/replication.go index 0abbf6efca6..65a2f75e94a 100644 --- a/vendor/github.com/minio/minio-go/v7/pkg/replication/replication.go +++ b/vendor/github.com/minio/minio-go/v7/pkg/replication/replication.go @@ -406,6 +406,9 @@ func (c *Config) EditRule(opts Options) error { return fmt.Errorf("priority must be unique. Replication configuration already has a rule with this priority") } if rule.Destination.Bucket != newRule.Destination.Bucket && rule.ID == newRule.ID { + if c.Role == newRule.Destination.Bucket { + continue + } return fmt.Errorf("invalid destination bucket for this rule") } } diff --git a/vendor/github.com/minio/minio-go/v7/pkg/s3utils/utils.go b/vendor/github.com/minio/minio-go/v7/pkg/s3utils/utils.go index 056e78a67a8..0e63ce2f7dc 100644 --- a/vendor/github.com/minio/minio-go/v7/pkg/s3utils/utils.go +++ b/vendor/github.com/minio/minio-go/v7/pkg/s3utils/utils.go @@ -226,7 +226,7 @@ func IsGoogleEndpoint(endpointURL url.URL) bool { if endpointURL == sentinelURL { return false } - return endpointURL.Host == "storage.googleapis.com" + return endpointURL.Hostname() == "storage.googleapis.com" } // Expects ascii encoded strings - from output of urlEncodePath diff --git a/vendor/github.com/minio/minio-go/v7/post-policy.go b/vendor/github.com/minio/minio-go/v7/post-policy.go index f6dbbf7f6ea..3f023704a46 100644 --- a/vendor/github.com/minio/minio-go/v7/post-policy.go +++ b/vendor/github.com/minio/minio-go/v7/post-policy.go @@ -209,6 +209,23 @@ func (p *PostPolicy) SetContentTypeStartsWith(contentTypeStartsWith string) erro return nil } +// SetContentDisposition - Sets content-disposition of the object for this policy +func (p *PostPolicy) SetContentDisposition(contentDisposition string) error { + if strings.TrimSpace(contentDisposition) == "" || contentDisposition == "" { + return errInvalidArgument("No content disposition specified.") + } + policyCond := policyCondition{ + matchType: "eq", + condition: "$Content-Disposition", + value: contentDisposition, + } + if err := p.addNewPolicy(policyCond); err != nil { + return err + } + p.formData["Content-Disposition"] = contentDisposition + return nil +} + // SetContentLengthRange - Set new min and max content length // condition for all incoming uploads. func (p *PostPolicy) SetContentLengthRange(min, max int64) error { diff --git a/vendor/github.com/minio/minio-go/v7/s3-endpoints.go b/vendor/github.com/minio/minio-go/v7/s3-endpoints.go index 068a6bfa147..01cee8a19df 100644 --- a/vendor/github.com/minio/minio-go/v7/s3-endpoints.go +++ b/vendor/github.com/minio/minio-go/v7/s3-endpoints.go @@ -44,6 +44,10 @@ var awsS3EndpointMap = map[string]awsS3Endpoint{ "s3.ca-central-1.amazonaws.com", "s3.dualstack.ca-central-1.amazonaws.com", }, + "ca-west-1": { + "s3.ca-west-1.amazonaws.com", + "s3.dualstack.ca-west-1.amazonaws.com", + }, "eu-west-1": { "s3.eu-west-1.amazonaws.com", "s3.dualstack.eu-west-1.amazonaws.com", diff --git a/vendor/modules.txt b/vendor/modules.txt index 5e174dde7de..31e266fad1e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -290,9 +290,6 @@ github.com/cenkalti/backoff/v3 # github.com/cenkalti/backoff/v4 v4.3.0 ## explicit; go 1.18 github.com/cenkalti/backoff/v4 -# github.com/cespare/xxhash v1.1.0 -## explicit -github.com/cespare/xxhash # github.com/cespare/xxhash/v2 v2.3.0 ## explicit; go 1.11 github.com/cespare/xxhash/v2 @@ -368,6 +365,9 @@ github.com/fsnotify/fsnotify # github.com/go-errors/errors v1.4.2 ## explicit; go 1.14 github.com/go-errors/errors +# github.com/go-ini/ini v1.67.0 +## explicit +github.com/go-ini/ini # github.com/go-jose/go-jose/v3 v3.0.3 ## explicit; go 1.12 github.com/go-jose/go-jose/v3 @@ -610,7 +610,7 @@ github.com/grafana/alerting/receivers/webex github.com/grafana/alerting/receivers/webhook github.com/grafana/alerting/receivers/wecom github.com/grafana/alerting/templates -# github.com/grafana/dskit v0.0.0-20240718080635-f5bd38371e1c +# github.com/grafana/dskit v0.0.0-20240719153732-6e8a03e781de ## explicit; go 1.21 github.com/grafana/dskit/backoff github.com/grafana/dskit/ballast @@ -822,7 +822,7 @@ github.com/miekg/dns # github.com/minio/md5-simd v1.1.2 ## explicit; go 1.14 github.com/minio/md5-simd -# github.com/minio/minio-go/v7 v7.0.72 +# github.com/minio/minio-go/v7 v7.0.74 ## explicit; go 1.21 github.com/minio/minio-go/v7 github.com/minio/minio-go/v7/pkg/credentials @@ -1563,9 +1563,6 @@ google.golang.org/protobuf/types/known/timestamppb # gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc ## explicit gopkg.in/alexcesaro/quotedprintable.v3 -# gopkg.in/ini.v1 v1.67.0 -## explicit -gopkg.in/ini.v1 # gopkg.in/mail.v2 v2.3.1 ## explicit gopkg.in/mail.v2