perf: Improve efficiency of embedded kill tasks - #19772
Conversation
cryptoe
left a comment
There was a problem hiding this comment.
+1
I think the changes make sense to me.
Thank you for working on this.
| // Identify intervals with unused segments which are eligible for kill | ||
| final Map<DatasourceInterval, Integer> killCandidates = | ||
| storageCoordinator.retrieveSomeUnusedSegmentIntervals( | ||
| DateTimes.nowUtc().minus(killConfig.getBufferPeriod()), |
There was a problem hiding this comment.
So we have basically pushed in the bufferPeriod inside the sql query so that we donot populate segments which would be ineligible.
I think this change alone would get us lot of improvements.
I am a bit worried about fetching all the data sources at once but I guess there is where the inner query limit comes into place.
There was a problem hiding this comment.
Yes, the inner limit (currently 200k) takes care of that.
Fetching all the datasources in one go is actually better since in the current flow, we would fire separate queries for each datasource. When the number of datasources is large, this can be pretty redundant, especially since a lot of the datasources might not even have killable unused segments.
| @Test | ||
| public void test_maxSegmentsKilledInAnInterval_is_1k() | ||
| @Test(timeout = 30_000L) | ||
| public void test_maxSegmentsKilledInRun_is_200k() |
There was a problem hiding this comment.
On my machine this test legitimately takes nearly 30s to run, which has two problems:
- The
timeout = 30_000Lis low enough that it would make the test flaky - 30s is just generally a long time.
Is it possible to change the test to run faster while still being effective?
There was a problem hiding this comment.
Added a config to control the maxSegmentsToKill.
Most clusters should work fine with the default value of 200k itself.
FrankChen021
left a comment
There was a problem hiding this comment.
| Severity | Findings |
|---|---|
| P0 | 0 |
| P1 | 2 |
| P2 | 1 |
| P3 | 0 |
| Total | 3 |
The capped global scan can starve cleanup behind locked intervals, embedded tasks can exceed their discovered deletion limits, and malformed interval rows can abort queue rebuilding.
Reviewed 8 of 8 changed files.
This is an automated review by Codex GPT-5.6-Sol
| //CHECKSTYLE.ON: Regexp | ||
| dbTables.getSegmentsTable(), | ||
| connector.getQuoteString(), | ||
| connector.limitClause(maxSegmentsToScan), |
There was a problem hiding this comment.
[P1] Prevent locked rows from monopolizing the global scan
The new global LIMIT has no ordering, cursor, or rotation state. If the selected 200,000 rows belong to intervals whose exclusive locks cannot be acquired, all generated tasks are skipped, the rows remain, and the next rebuild can select the identical slice again. Eligible segments outside that slice—including unrelated datasources—can then be starved indefinitely, whereas the previous per-datasource discovery still allowed other datasources to progress. Candidate discovery needs a deterministic progress/fairness mechanism that can advance past repeatedly skipped intervals.
There was a problem hiding this comment.
While this is possible, it is not very likely to happen.
- Firstly, intervals will not remain locked forever, unless there is a lot of late arriving data in streaming supervisors.
- Secondly, the search query need not pick up the same intervals in the next iteration.
Also, the eventual goal is to use concurrent locks in embedded kill tasks, thereby removing the need to skip locked intervals altogether. I will create a follow up PR for that change.
|
Items for follow up PR:
|
Description
The
UnusedSegmentsKillercurrenly has some limitations:UnusedSegmentsKillerwould take very long to clear a backlog of killable unused segments.Changes
UnusedSegmentsKillerand small enough to keep the query time within ~5s (tried on MySQL 8 with 17M unused segments).KillCandidate.This PR has: