wenhao created HBASE-30405:
------------------------------

             Summary: [Balancer] `HDFSBlocksDistribution.getTopHosts()` breaks 
weight ties by hostname, causing the current RS to be misranked and occasional 
zero-gain region moves
                 Key: HBASE-30405
                 URL: https://issues.apache.org/jira/browse/HBASE-30405
             Project: HBase
          Issue Type: Bug
          Components: Balancer
    Affects Versions: 2.5.11, 2.0.0
            Reporter: wenhao
            Assignee: wenhao


h2. Summary

When multiple hosts hold an equal total weight of a region's HFiles (i.e. equal 
block locality), {{HDFSBlocksDistribution.getTopHosts()}} resolves the tie by 
hostname. The resulting "most local host" ordering is therefore arbitrary with 
respect to locality, and the host currently serving the region is frequently 
not ranked first even though its locality is identical to the top host. This 
contradicts the documented contract of {{BalancerClusterState.regionLocations}} 
("regionIndex -> list of serverIndex sorted by locality") and, through the 
most-local-entity selection used by {{{}LocalityBasedCandidateGenerator{}}}, 
can make the stochastic balancer emit zero-locality-gain move/swap proposals.
h2. Problem

{{HDFSBlocksDistribution.getTopHostsWithWeights()}} builds a {{TreeSet}} 
ordered by {{HostAndWeight.WeightComparator}} and returns its 
{{{}descendingSet(){}}}:
 * {{{}WeightComparator.compare(l, r){}}}: primary key is weight (ascending); 
*when weights are equal, the tie is broken by 
{{l.getHost().compareTo(r.getHost())}}* (hostname, ascending).

 * {{descendingSet()}} reverses that order, so the returned list is: weight 
descending, and {*}among equal weights, hostname descending{*}.

Consequently the first element of {{getTopHosts()}} is the host with the 
maximum block weight; if several hosts share the same maximum weight, the first 
one is simply the lexicographically largest hostname — not the host with any 
locality advantage.
h2. Root cause
 # {{HDFSBlocksDistribution.java}}

 ** {{WeightComparator}} tie-break: {{return 
l.getHost().compareTo(r.getHost());}}

 ** {{getTopHostsWithWeights()}} returns {{{}orderedHosts.descendingSet(){}}}, 
so equal-weight hosts are ordered by hostname {_}descending{_}.

 # {{RegionLocationFinder.getTopBlockLocations(RegionInfo region)}} returns the 
host list in exactly that order.

 # {{BalancerClusterState.registerRegion()}} fills 
{{regionLocations[regionIndex]}} from that list. The field contract says the 
list is "sorted by locality", but under weight ties it is actually sorted by 
hostname.

 



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to