Repository navigation
Conversation
Contributor
|
Thank you for your contribution to Apache Doris. Please clearly describe your PR:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What problem does this PR solve?
Related PR: #66378, #66389, #66447, #66451
Problem Summary:
Every round,
CloudTabletRebalancerrebuilds a current and a future generation of three routing indexes:be -> tabletIdstableId -> be -> tabletIdspartitionId -> indexId -> be -> tabletIdsAll inner containers were
ConcurrentHashMap/ConcurrentHashMap.newKeySet()holding boxedLongs. The partition and table levels create one concurrent set per (partition index, backend) and per (table, backend), so the per-container and per-element overhead dominates. With millions of routes, these indexes become one of the largest objects on the FE heap.Test cluster and metadata
Table specs (empty tables created by a script):
With this metadata, a heap dump taken while the indexes were alive showed
CloudTabletRebalancerretaining 839.82 MB, which is 4.6 timesCloudInternalCatalog(182.16 MB) and 16 timesCloudTabletInvertedIndex(52.56 MB).Changes
This PR replaces the inner containers with primitive fastutil collections. Scheduling logic and decisions are unchanged.
Partition level:
ConcurrentHashMap<partitionId, Long2ObjectOpenHashMap<indexId, Long2ObjectOpenHashMap<be, LongArrayList>>>. A partition index usually has only a few tablets per backend, so a list is smaller than a set and its linear removal is cheap. Containers are created with small initial capacities.Table level:
ConcurrentHashMap<tableId, Long2ObjectOpenHashMap<be, LongOpenHashSet>>. A large table can have many tablets on one backend, so a hash set keeps removal O(1).The partition and table indexes are only read and written by the rebalancer daemon thread (
statRouteInfo,balanceImpl, warmup rollback inprocessFailedWarmupTasks), so their inner containers are intentionally not thread-safe and are accessed without locking. The outer maps are stillConcurrentHashMap.A tablet is added to the partition / table containers only when it is newly added to the global set of the same generation. Lists are not idempotent like the sets they replace, so this keeps them free of duplicates (e.g. two replicas of one tablet routed to the same backend).
Global level: the inner sets become
LongOpenHashSet. Unlike the other two levels, these sets are copied by other threads throughgetSnapshotTabletsIn*ByBeId(tablet report inCloudReportHandler, warm up inCacheHotspotManager, multi-cluster sync load inStmtExecutor.syncLoadForTablets). An open-addressing removal shifts unrelated elements, so an unguarded copy could miss a tablet that is not moving, and the tablet report would then drop a tablet that is still in use. Each set is therefore guarded by its own monitor:fillBeToTablets,updateBeToTablets); the lock is uncontended whilestatRouteInfofills the sets, because they are published afterwards by the volatile field write;addAlltakes fastutil's primitive copy path, so the lock is held for a few milliseconds even for a backend with ~950k tablets;getTabletNumByBackendId(size()only) do not lock.The lock is never nested and never held together with a table or catalog lock. A snapshot is now an exact point-in-time copy; previously the weakly consistent iteration could include or miss the tablet being moved.
Snapshot results change from
HashSet<Long>toLongOpenHashSetand are still returned asSet<Long>. Callers only usecontains/removeAll.The global set presize hint is no longer capped at
1 << 16and uses the previous round's size directly. WithLongOpenHashSetthe table is the whole storage: under the cap, a backend with ~950k tablets regrew 4 times every round, discarding about as much memory as the final set. An over-sized hint after a catalog shrink lasts one round and is never larger than the previous round's set, which is still alive while the new one is built.Balancing helpers take
Map<Long, ? extends Collection<Long>>.reservoirPick/containsTabletiterateLongCollections without boxing, andpickedTabletIdsis aLongOpenHashSet.Result
Measured on the same metadata (MAT retained heap, both generations, taken while the indexes were alive;
currentRoundTabletScanCount5,682,450 vs 5,682,462):partitionToTablets+futurePartitionToTabletsbeToTabletsInTable+futureBeToTabletsInTablebeToTabletsGlobal+futureBeToTabletsGlobalCloudTabletRebalancerretainedThe global sets were the last holders of boxed tablet ids, so the boxed
Longs retained by the rebalancer (about 68 MB, 24 bytes each) are gone as well. The remaining 300 MB is almost entirely thelong[]tables of the three levels.Release note
Reduce FE memory used by the cloud tablet rebalancer by storing its routing indexes in primitive collections.
Check List (For Author)
CloudTabletRebalancerTest(37 tests), including:testSnapshotDoesNotMissUnmovedTabletsWhileTabletsAreMoving: one thread keeps moving tablets between two backends while another keeps taking snapshots; every unmoved tablet must be present. It fails with the locks removed.testStatRouteInfoPresizesLargeGlobalTabletSetsWithoutBoundtestFillBeToTabletsAddsDuplicateRouteOncetestPickTabletPreferCold_primitiveCandidatesCacheHotspotManagerTest(15 tests)statRouteInfoand tookjmap -dump:livewith the old and new builds on the same metadata; the retained sizes are in "Result" above.cloud_tablet_rebalancer_last_round_duration_msbefore and after.Check List (For Reviewer who merge this PR)