Skip to content
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

feat: Blooms retention #12258

Merged
merged 17 commits into from
Mar 28, 2024
Merged

feat: Blooms retention #12258

merged 17 commits into from
Mar 28, 2024

Conversation

salvacorts
Copy link
Contributor

@salvacorts salvacorts commented Mar 19, 2024

What this PR does / why we need it:

This PR adds retention to bloom blocks and metas. The retention is applied by only one compactor (the one that owns the smallest token).

Compaction works as follows:

  1. Check if the compactor owns the smaller token in the ring. If so, this compactor should run retention.
  2. Start with day = today - 1 day
  3. Get bloom client for day
  4. List tenants in the day table
  5. If there is no tenants, we are done (means we have applied retention for all tenants here in the last iteration)
  6. For each tenant:
    6.1. Get max retention across all streams
    6.2. If day < (now - maxretention) --> delete all content for tenant in the day table.
  7. day--; goto 3.

We try to run retention up to once a day but:

  • On a ring topology change, two compactors might run retention simultaneusly (if both see they own the smallest token).
  • We store the last day retention was applied in memory, if the compactor restarts, this is lost and retention might be run again.

We add the following configs:

bloom_compactor:
  retention:
    enabled: false
    max_lookback_days: 365

Special notes for your reviewer:
They PR looks big but it's mostly tests.

Checklist

  • Reviewed the CONTRIBUTING.md guide (required)
  • Documentation added
  • Tests updated
  • CHANGELOG.md updated
    • If the change is worth mentioning in the release notes, add add-to-release-notes label
  • Changes that require user attention or interaction to upgrade are documented in docs/sources/setup/upgrade/_index.md
  • For Helm chart changes bump the Helm chart version in production/helm/loki/Chart.yaml and update production/helm/loki/CHANGELOG.md and production/helm/loki/README.md. Example PR
  • 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

@salvacorts salvacorts changed the title Salvacorts/bloom retention feat: Blooms retention Mar 19, 2024
@github-actions github-actions bot added the type/docs Issues related to technical documentation; the Docs Squad uses this label across many repositories label Mar 19, 2024
@salvacorts salvacorts marked this pull request as ready for review March 21, 2024 15:58
@salvacorts salvacorts requested a review from a team as a code owner March 21, 2024 15:58
Copy link
Member

@owen-d owen-d left a comment

Choose a reason for hiding this comment

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

An unintended consequence here is that if a tenant has any retention configs larger than the range the compactor checks for, it'll never delete blooms for that tenant. I think it makes more sense to delete all tenants once they hit max_lookback_days regardless of their configs.

Comment on lines 198 to 199
// 1second -> 5 years, 10 buckets
Buckets: prometheus.DefBuckets,
Copy link
Member

Choose a reason for hiding this comment

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

The default buckets are 0.005->10s

Copy link
Contributor Author

@salvacorts salvacorts Mar 22, 2024

Choose a reason for hiding this comment

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

That comment is misleading. I forgot to remove that comment after copy-pasting. This metric tracks the time needed to apply retention. The def buckets should work.

Comment on lines 33 to 34
Tenant(tenant, table string) Location
ParseTenantKey(loc Location) (string, error)
Copy link
Member

Choose a reason for hiding this comment

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

Maybe rename this to TenantPrefix and ParseTenantFromKey?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@@ -127,6 +128,51 @@ func (b *bloomStoreEntry) FetchBlocks(ctx context.Context, refs []BlockRef, _ ..
return b.fetcher.FetchBlocks(ctx, refs)
}

func (b *bloomStoreEntry) TenantFilesForInterval(ctx context.Context, interval Interval) (map[string][]string, error) {
Copy link
Member

Choose a reason for hiding this comment

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

nit: not needed now, but making this not need to buffer the entire file list would be good.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added a TODO inside the function to add pooling if this becomes a problem.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I refactored the implementation to reuse the slices from the listed objects.


startDay := storageconfig.NewDayTime(today.Add(-smallestRetention))
endDay := storageconfig.NewDayTime(0)
if r.cfg.MaxLookbackDays > 0 {
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this should be allowed to be zero to prevent trying to iterate every day since 1970.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agree. Done.

break
}

for tenant, objectKeys := range tenants {
Copy link
Member

Choose a reason for hiding this comment

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

nit: it's probably better to pass limits to TenantFilesForInterval so it doesn't need to allocate space for files that won't be removed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I ended up doing something slightly different. The TenantFilesForInterval now takes a filter function. We use that filter function to filter out tenants whose retention hasn't expired yet.

}

if _, ok := tenants[tenant]; !ok {
tenants[tenant] = make([]string, 0, 100)
tenants[tenant] = nil // Initialize tenant with empty slice
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We do this since the function returns all tenants regardless of the filter. The filter filters out the files.
This way we can know which tenants are there for a given day, but filter the files whose retention are not expired yet.

@salvacorts
Copy link
Contributor Author

An unintended consequence here is that if a tenant has any retention configs larger than the range the compactor checks for, it'll never delete blooms for that tenant.

The goal of max_lookback_days is to prevent us from iterating till 1970. Still, retention stops earlier than the lookback days if for a given day table there are no tenants: meaning that a previous retention iteration removed all the tenants and therefore we can assume there won't be files for any tenants beyond that day.

I think it makes more sense to delete all tenants once they hit max_lookback_days regardless of their configs.

I see two problems with that:

  • We'd be storing blooms for tenants whose retention has expired before max_lookback_days.
  • If a tenant retention is set beyond max_lookback_days, we'd be deleting blooms earlier than desired.

I'd stick with using max_lookback_days as a global limit to make sure we don't iterate too long. To be clear, we shouldn't actually reach max_lookback_days at all under normal circumstances.

@salvacorts salvacorts requested a review from owen-d March 25, 2024 08:19
Copy link
Member

@owen-d owen-d left a comment

Choose a reason for hiding this comment

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

Let's add a metric which fires when a tenant's retention is longer than the lookback the compactor checks so we can alert on it.

Left a nit, but giving you an approval so you can merge when fixed

}

// findSmallestRetention returns the smallest retention period across all tenants.
// It also returns a boolean indicating if there is any retention period set at all
Copy link
Member

Choose a reason for hiding this comment

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

This is somewhat confusing. It returns the smallest retention, but skips zero (disabled). It also does not return a bool like it suggests. Maybe smallestEnabledRetention?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed, thanks.

@salvacorts salvacorts merged commit 86c768c into main Mar 28, 2024
11 checks passed
@salvacorts salvacorts deleted the salvacorts/bloom-retention branch March 28, 2024 10:44
rhnasc pushed a commit to inloco/loki that referenced this pull request Apr 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size/XXL type/docs Issues related to technical documentation; the Docs Squad uses this label across many repositories
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants