Skip to content

fix(ingest-limits): Use stripe locking for metadata #17150

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Apr 25, 2025

Conversation

periklis
Copy link
Collaborator

@periklis periklis commented Apr 11, 2025

What this PR does / why we need it:
This pull request implements a stripe-lock approach to read/write the internal ingest-limits stream metadata structure. The stripes are distributed over the total amount of partitions (e.g. default is 64). This allows updating and reading the structure with less lock contention.

                                                                                    │    old.txt    │                new.txt                │
                                                                                   │    sec/op     │    sec/op     vs base                 │
StreamMetadata_Store/4_partitions_small_streams_single_tenant_create-14               180.8n ± ∞ ¹   133.7n ± ∞ ¹        ~ (p=1.000 n=1) ²
StreamMetadata_Store/4_partitions_small_streams_single_tenant_update-14               190.6n ± ∞ ¹   135.5n ± ∞ ¹        ~ (p=1.000 n=1) ²
StreamMetadata_Store/4_partitions_small_streams_single_tenant_create_parallel-14      320.4n ± ∞ ¹   232.3n ± ∞ ¹        ~ (p=1.000 n=1) ²
StreamMetadata_Store/4_partitions_small_streams_single_tenant_update_parallel-14      347.7n ± ∞ ¹   256.7n ± ∞ ¹        ~ (p=1.000 n=1) ²
StreamMetadata_Store/8_partitions_medium_streams_multi_tenant_create-14               189.1n ± ∞ ¹   124.0n ± ∞ ¹        ~ (p=1.000 n=1) ²
StreamMetadata_Store/8_partitions_medium_streams_multi_tenant_update-14               195.1n ± ∞ ¹   125.9n ± ∞ ¹        ~ (p=1.000 n=1) ²
StreamMetadata_Store/8_partitions_medium_streams_multi_tenant_create_parallel-14      341.6n ± ∞ ¹   125.1n ± ∞ ¹        ~ (p=1.000 n=1) ²
StreamMetadata_Store/8_partitions_medium_streams_multi_tenant_update_parallel-14      356.0n ± ∞ ¹   150.3n ± ∞ ¹        ~ (p=1.000 n=1) ²
StreamMetadata_Store/16_partitions_large_streams_multi_tenant_create-14               206.9n ± ∞ ¹   134.7n ± ∞ ¹        ~ (p=1.000 n=1) ²
StreamMetadata_Store/16_partitions_large_streams_multi_tenant_update-14               208.6n ± ∞ ¹   136.6n ± ∞ ¹        ~ (p=1.000 n=1) ²
StreamMetadata_Store/16_partitions_large_streams_multi_tenant_create_parallel-14     336.20n ± ∞ ¹   82.15n ± ∞ ¹        ~ (p=1.000 n=1) ²
StreamMetadata_Store/16_partitions_large_streams_multi_tenant_update_parallel-14     343.20n ± ∞ ¹   91.31n ± ∞ ¹        ~ (p=1.000 n=1) ²
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant_create-14              211.4n ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant_update-14              212.2n ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant_create_parallel-14     327.2n ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant_update_parallel-14     332.0n ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant__create-14                            134.9n ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant__update-14                            139.1n ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant__create_parallel-14                   60.90n ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant__update_parallel-14                   65.67n ± ∞ ¹
geomean                                                                               259.3n         124.4n        -46.83%               ³
¹ need >= 6 samples for confidence interval at level 0.95
² need >= 4 samples to detect a difference at alpha level 0.05
³ benchmark set differs from baseline; geomeans may not be comparable

                                                                                   │   old.txt   │               new.txt                │
                                                                                   │    B/op     │     B/op      vs base                │
StreamMetadata_Store/4_partitions_small_streams_single_tenant_create-14              56.00 ± ∞ ¹    56.00 ± ∞ ¹       ~ (p=1.000 n=1) ²
StreamMetadata_Store/4_partitions_small_streams_single_tenant_update-14              72.00 ± ∞ ¹    71.00 ± ∞ ¹       ~ (p=1.000 n=1) ³
StreamMetadata_Store/4_partitions_small_streams_single_tenant_create_parallel-14     90.00 ± ∞ ¹    90.00 ± ∞ ¹       ~ (p=1.000 n=1) ²
StreamMetadata_Store/4_partitions_small_streams_single_tenant_update_parallel-14     157.0 ± ∞ ¹    141.0 ± ∞ ¹       ~ (p=1.000 n=1) ³
StreamMetadata_Store/8_partitions_medium_streams_multi_tenant_create-14              56.00 ± ∞ ¹    56.00 ± ∞ ¹       ~ (p=1.000 n=1) ²
StreamMetadata_Store/8_partitions_medium_streams_multi_tenant_update-14              72.00 ± ∞ ¹    72.00 ± ∞ ¹       ~ (p=1.000 n=1) ²
StreamMetadata_Store/8_partitions_medium_streams_multi_tenant_create_parallel-14     89.00 ± ∞ ¹    90.00 ± ∞ ¹       ~ (p=1.000 n=1) ³
StreamMetadata_Store/8_partitions_medium_streams_multi_tenant_update_parallel-14     137.0 ± ∞ ¹    138.0 ± ∞ ¹       ~ (p=1.000 n=1) ³
StreamMetadata_Store/16_partitions_large_streams_multi_tenant_create-14              56.00 ± ∞ ¹    56.00 ± ∞ ¹       ~ (p=1.000 n=1) ²
StreamMetadata_Store/16_partitions_large_streams_multi_tenant_update-14              72.00 ± ∞ ¹    72.00 ± ∞ ¹       ~ (p=1.000 n=1) ²
StreamMetadata_Store/16_partitions_large_streams_multi_tenant_create_parallel-14     73.00 ± ∞ ¹   116.00 ± ∞ ¹       ~ (p=1.000 n=1) ³
StreamMetadata_Store/16_partitions_large_streams_multi_tenant_update_parallel-14     113.0 ± ∞ ¹    159.0 ± ∞ ¹       ~ (p=1.000 n=1) ³
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant_create-14             56.00 ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant_update-14             72.00 ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant_create_parallel-14    62.00 ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant_update_parallel-14    92.00 ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant__create-14                           56.00 ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant__update-14                           71.00 ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant__create_parallel-14                  95.00 ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant__update_parallel-14                  138.0 ± ∞ ¹
geomean                                                                              78.65          86.48        +6.02%               ⁴
¹ need >= 6 samples for confidence interval at level 0.95
² all samples are equal
³ need >= 4 samples to detect a difference at alpha level 0.05
⁴ benchmark set differs from baseline; geomeans may not be comparable

                                                                                   │   old.txt   │               new.txt               │
                                                                                   │  allocs/op  │  allocs/op   vs base                │
StreamMetadata_Store/4_partitions_small_streams_single_tenant_create-14              2.000 ± ∞ ¹   2.000 ± ∞ ¹       ~ (p=1.000 n=1) ²
StreamMetadata_Store/4_partitions_small_streams_single_tenant_update-14              2.000 ± ∞ ¹   2.000 ± ∞ ¹       ~ (p=1.000 n=1) ²
StreamMetadata_Store/4_partitions_small_streams_single_tenant_create_parallel-14     2.000 ± ∞ ¹   2.000 ± ∞ ¹       ~ (p=1.000 n=1) ²
StreamMetadata_Store/4_partitions_small_streams_single_tenant_update_parallel-14     2.000 ± ∞ ¹   2.000 ± ∞ ¹       ~ (p=1.000 n=1) ²
StreamMetadata_Store/8_partitions_medium_streams_multi_tenant_create-14              2.000 ± ∞ ¹   2.000 ± ∞ ¹       ~ (p=1.000 n=1) ²
StreamMetadata_Store/8_partitions_medium_streams_multi_tenant_update-14              2.000 ± ∞ ¹   2.000 ± ∞ ¹       ~ (p=1.000 n=1) ²
StreamMetadata_Store/8_partitions_medium_streams_multi_tenant_create_parallel-14     2.000 ± ∞ ¹   2.000 ± ∞ ¹       ~ (p=1.000 n=1) ²
StreamMetadata_Store/8_partitions_medium_streams_multi_tenant_update_parallel-14     2.000 ± ∞ ¹   2.000 ± ∞ ¹       ~ (p=1.000 n=1) ²
StreamMetadata_Store/16_partitions_large_streams_multi_tenant_create-14              2.000 ± ∞ ¹   2.000 ± ∞ ¹       ~ (p=1.000 n=1) ²
StreamMetadata_Store/16_partitions_large_streams_multi_tenant_update-14              2.000 ± ∞ ¹   2.000 ± ∞ ¹       ~ (p=1.000 n=1) ²
StreamMetadata_Store/16_partitions_large_streams_multi_tenant_create_parallel-14     2.000 ± ∞ ¹   2.000 ± ∞ ¹       ~ (p=1.000 n=1) ²
StreamMetadata_Store/16_partitions_large_streams_multi_tenant_update_parallel-14     2.000 ± ∞ ¹   2.000 ± ∞ ¹       ~ (p=1.000 n=1) ²
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant_create-14             2.000 ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant_update-14             2.000 ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant_create_parallel-14    2.000 ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant_update_parallel-14    2.000 ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant__create-14                          2.000 ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant__update-14                          2.000 ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant__create_parallel-14                 2.000 ± ∞ ¹
StreamMetadata_Store/32_partitions_xlarge_streams_multi_tenant__update_parallel-14                 2.000 ± ∞ ¹
geomean                                                                              2.000         2.000        +0.00%               ³
¹ need >= 6 samples for confidence interval at level 0.95
² all samples are equal
³ benchmark set differs from baseline; geomeans may not be comparable

Which issue(s) this PR fixes:
Fixes #

Special notes for your reviewer:

Checklist

  • Reviewed the CONTRIBUTING.md guide (required)
  • Documentation added
  • Tests updated
  • Title matches the required conventional commits format, see here
    • Note that Promtail is considered to be feature complete, and future development for logs collection will be in Grafana Alloy. As such, feat PRs are unlikely to be accepted unless a case can be made for the feature actually being a bug fix to existing behavior.
  • Changes that require user attention or interaction to upgrade are documented in docs/sources/setup/upgrade/_index.md
  • If the change is deprecating or removing a configuration option, update the deprecated-config.yaml and deleted-config.yaml files respectively in the tools/deprecated-config-checker directory. Example PR
@periklis periklis self-assigned this Apr 11, 2025
@periklis periklis force-pushed the ingest-limits-stripe-locks branch from 7222994 to c6b8c9c Compare April 15, 2025 13:47
@periklis periklis marked this pull request as ready for review April 15, 2025 18:16
@periklis periklis requested a review from a team as a code owner April 15, 2025 18:16
@periklis periklis force-pushed the ingest-limits-stripe-locks branch from c6b8c9c to 805f573 Compare April 15, 2025 18:17
Copy link
Contributor

@grobinson-grafana grobinson-grafana left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general looks good! I would love to see a better abstraction around the stripes and the lock acquisition though. I think if you do this you'll find the code easier to reason about and also easier to write tests. You could consider using https://pkg.go.dev/iter for some of the operations.

@periklis periklis force-pushed the ingest-limits-stripe-locks branch from 6cb1f32 to 8a03e24 Compare April 22, 2025 09:02
@periklis periklis force-pushed the ingest-limits-stripe-locks branch from 266b8c1 to 4bf6f5d Compare April 23, 2025 06:43

// AllFunc is a function that is called for each stream in the metadata.
// It is used to count per tenant active streams.
// Note: The collect function should not modify the stream metadata.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is modification possible as we pass a copy of Stream? I suppose you could change the values in RateBuckets?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, this is more of a note on how to use the interface not an enforced rule as of now.

require.ElementsMatch(t, expected, actual)
}

func TestStreamMetadata_Usage_Concurrent(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to run these with -race?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just FYI, we don't run our tests with -race:

Run gotestsum -- -covermode=atomic -coverprofile=coverage.txt -p=4 ./pkg/limits/...
@grobinson-grafana grobinson-grafana enabled auto-merge (squash) April 25, 2025 08:37
@periklis periklis enabled auto-merge (squash) April 25, 2025 09:29
@periklis periklis merged commit c32e479 into main Apr 25, 2025
61 checks passed
@periklis periklis deleted the ingest-limits-stripe-locks branch April 25, 2025 09:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2 participants