Skip to content

Commit 4e4db62

Browse files
ethqunzhongdlg99
authored andcommitted
remove in address2Region while bookie left to get correct rack info (apache#4504)
(cherry picked from commit 07de650) (cherry picked from commit 857959e)
1 parent 677e7cb commit 4e4db62

File tree

2 files changed

+136
-2
lines changed

2 files changed

+136
-2
lines changed

bookkeeper-server/src/main/java/org/apache/bookkeeper/client/RegionAwareEnsemblePlacementPolicy.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,23 @@ protected String parseBookieRegion(BookieId addr) {
117117

118118
@Override
119119
public void handleBookiesThatLeft(Set<BookieId> leftBookies) {
120+
// case 1: (In some situation, eg, Broker and bookie restart concurrently.)
121+
//1. Bookie X join cluster for the first time, encounters a region exception, and `address2Region` record X's
122+
// region as default-region.
123+
//2. Bookie X left cluster and is removed from knownBookies, but address2Region retains the information of
124+
// bookie X.
125+
//3. update Bookie X's rack info, and calling `onBookieRackChange` will only update address2Region for
126+
// addresses present in knownBookies; therefore, bookie X's region info is not updated.
127+
//4. Bookie X join cluster again, since address2Region contains the previous default-region information,
128+
// getRegion will directly use cached data, resulting of an incorrect region.
129+
130+
// The bookie region is initialized to "default-region" in address2Region.
131+
// We should ensure that when a bookie leaves the cluster,
132+
// we also clean up the corresponding region information for that bookie in address2Region,
133+
// so that it can update the correct region for the bookie during onBookieRackChange and
134+
// handleBookiesThatJoined.
135+
// to avoid traffic skew in ensemble selection.
136+
leftBookies.forEach(address2Region::remove);
120137
super.handleBookiesThatLeft(leftBookies);
121138

122139
for (TopologyAwareEnsemblePlacementPolicy policy: perRegionPlacement.values()) {

bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestRegionAwareEnsemblePlacementPolicy.java

Lines changed: 119 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,7 +1066,7 @@ public void testEnsembleWithThreeRegionsReplaceDisableDurability() throws Except
10661066
testEnsembleWithThreeRegionsReplaceInternal(1, true, false);
10671067
}
10681068

1069-
public void testEnsembleWithThreeRegionsReplaceInternal(int minDurability, boolean disableDurability,
1069+
private void testEnsembleWithThreeRegionsReplaceInternal(int minDurability, boolean disableDurability,
10701070
boolean disableOneRegion) throws Exception {
10711071
repp.uninitalize();
10721072
repp = new RegionAwareEnsemblePlacementPolicy();
@@ -1208,7 +1208,7 @@ public void testEnsembleDisableDurability() throws Exception {
12081208
testEnsembleDurabilityDisabledInternal(2, true);
12091209
}
12101210

1211-
public void testEnsembleDurabilityDisabledInternal(int minDurability, boolean disableDurability) throws Exception {
1211+
private void testEnsembleDurabilityDisabledInternal(int minDurability, boolean disableDurability) throws Exception {
12121212
repp.uninitalize();
12131213
repp = new RegionAwareEnsemblePlacementPolicy();
12141214
conf.setProperty(REPP_REGIONS_TO_WRITE, "region1;region2;region3");
@@ -2027,4 +2027,121 @@ public void testNotifyRackChangeWithNewRegion() throws Exception {
20272027
assertEquals("region2", repp.address2Region.get(addr3.toBookieId()));
20282028
assertEquals("region3", repp.address2Region.get(addr4.toBookieId()));
20292029
}
2030+
2031+
@Test
2032+
public void testBookieLeftThenJoinWithDNSResolveFailed() throws Exception {
2033+
2034+
BookieSocketAddress addr1 = new BookieSocketAddress("127.0.1.1", 3181);
2035+
BookieSocketAddress addr2 = new BookieSocketAddress("127.0.1.2", 3181);
2036+
BookieSocketAddress addr3 = new BookieSocketAddress("127.0.1.3", 3181);
2037+
BookieSocketAddress addr4 = new BookieSocketAddress("127.0.1.4", 3181);
2038+
2039+
// init dns mapping
2040+
// 2. mock dns resolver failed, use default region and rack.
2041+
// addr1 rack info. /region-1/default-rack -> /default-region/default-rack.
2042+
2043+
// 1. mock addr1 dns resolver failed and use default region and rack.
2044+
StaticDNSResolver.addNodeToRack(addr1.getHostName(), "/default-region/default-rack");
2045+
StaticDNSResolver.addNodeToRack(addr2.getHostName(), "/region-1/default-rack");
2046+
StaticDNSResolver.addNodeToRack(addr3.getHostName(), "/region-2/default-rack");
2047+
StaticDNSResolver.addNodeToRack(addr4.getHostName(), "/region-3/default-rack");
2048+
2049+
// init cluster
2050+
Set<BookieId> addrs = Sets.newHashSet(addr1.toBookieId(),
2051+
addr2.toBookieId(), addr3.toBookieId(), addr4.toBookieId());
2052+
repp.onClusterChanged(addrs, new HashSet<>());
2053+
2054+
assertEquals(4, repp.knownBookies.size());
2055+
assertEquals("/default-region/default-rack", repp.knownBookies.get(addr1.toBookieId()).getNetworkLocation());
2056+
assertEquals("/region-1/default-rack", repp.knownBookies.get(addr2.toBookieId()).getNetworkLocation());
2057+
assertEquals("/region-2/default-rack", repp.knownBookies.get(addr3.toBookieId()).getNetworkLocation());
2058+
assertEquals("/region-3/default-rack", repp.knownBookies.get(addr4.toBookieId()).getNetworkLocation());
2059+
2060+
assertEquals(4, repp.perRegionPlacement.size());
2061+
TopologyAwareEnsemblePlacementPolicy unknownRegionPlacement = repp.perRegionPlacement.get("UnknownRegion");
2062+
assertEquals(1, unknownRegionPlacement.knownBookies.keySet().size());
2063+
assertEquals("/default-region/default-rack",
2064+
unknownRegionPlacement.knownBookies.get(addr1.toBookieId()).getNetworkLocation());
2065+
2066+
TopologyAwareEnsemblePlacementPolicy region1Placement = repp.perRegionPlacement.get("region-1");
2067+
assertEquals(1, region1Placement.knownBookies.keySet().size());
2068+
assertEquals("/region-1/default-rack",
2069+
region1Placement.knownBookies.get(addr2.toBookieId()).getNetworkLocation());
2070+
2071+
TopologyAwareEnsemblePlacementPolicy region2Placement = repp.perRegionPlacement.get("region-2");
2072+
assertEquals(1, region2Placement.knownBookies.keySet().size());
2073+
assertEquals("/region-2/default-rack",
2074+
region2Placement.knownBookies.get(addr3.toBookieId()).getNetworkLocation());
2075+
2076+
TopologyAwareEnsemblePlacementPolicy region3Placement = repp.perRegionPlacement.get("region-3");
2077+
assertEquals(1, region3Placement.knownBookies.keySet().size());
2078+
assertEquals("/region-3/default-rack",
2079+
region3Placement.knownBookies.get(addr4.toBookieId()).getNetworkLocation());
2080+
2081+
assertEquals("UnknownRegion", repp.address2Region.get(addr1.toBookieId()));
2082+
assertEquals("region-1", repp.address2Region.get(addr2.toBookieId()));
2083+
assertEquals("region-2", repp.address2Region.get(addr3.toBookieId()));
2084+
assertEquals("region-3", repp.address2Region.get(addr4.toBookieId()));
2085+
2086+
// 2. addr1 bookie shutdown and decommission
2087+
addrs.remove(addr1.toBookieId());
2088+
repp.onClusterChanged(addrs, new HashSet<>());
2089+
2090+
assertEquals(3, repp.knownBookies.size());
2091+
assertNull(repp.knownBookies.get(addr1.toBookieId()));
2092+
assertEquals("/region-1/default-rack", repp.knownBookies.get(addr2.toBookieId()).getNetworkLocation());
2093+
assertEquals("/region-2/default-rack", repp.knownBookies.get(addr3.toBookieId()).getNetworkLocation());
2094+
assertEquals("/region-3/default-rack", repp.knownBookies.get(addr4.toBookieId()).getNetworkLocation());
2095+
2096+
// UnknownRegion,region-1,region-2,region-3
2097+
assertEquals(4, repp.perRegionPlacement.size());
2098+
// after addr1 bookie left, it should remove from locally address2Region
2099+
assertNull(repp.address2Region.get(addr1.toBookieId()));
2100+
assertEquals("region-1", repp.address2Region.get(addr2.toBookieId()));
2101+
assertEquals("region-2", repp.address2Region.get(addr3.toBookieId()));
2102+
assertEquals("region-3", repp.address2Region.get(addr4.toBookieId()));
2103+
2104+
2105+
// 3. addr1 bookie start and join
2106+
addrs.add(addr1.toBookieId());
2107+
repp.onClusterChanged(addrs, new HashSet<>());
2108+
2109+
assertEquals(4, repp.knownBookies.size());
2110+
assertEquals("/default-region/default-rack", repp.knownBookies.get(addr1.toBookieId()).getNetworkLocation());
2111+
assertEquals("/region-1/default-rack", repp.knownBookies.get(addr2.toBookieId()).getNetworkLocation());
2112+
assertEquals("/region-2/default-rack", repp.knownBookies.get(addr3.toBookieId()).getNetworkLocation());
2113+
assertEquals("/region-3/default-rack", repp.knownBookies.get(addr4.toBookieId()).getNetworkLocation());
2114+
2115+
// UnknownRegion,region-1,region-2,region-3
2116+
assertEquals(4, repp.perRegionPlacement.size());
2117+
assertEquals("UnknownRegion", repp.address2Region.get(addr1.toBookieId()));
2118+
// addr1 bookie belongs to unknown region
2119+
unknownRegionPlacement = repp.perRegionPlacement.get("UnknownRegion");
2120+
assertEquals(1, unknownRegionPlacement.knownBookies.keySet().size());
2121+
assertEquals("/default-region/default-rack",
2122+
unknownRegionPlacement.knownBookies.get(addr1.toBookieId()).getNetworkLocation());
2123+
2124+
// 4. Update the correct rack.
2125+
// change addr1 rack info. /default-region/default-rack -> /region-1/default-rack.
2126+
List<BookieSocketAddress> bookieAddressList = new ArrayList<>();
2127+
List<String> rackList = new ArrayList<>();
2128+
bookieAddressList.add(addr1);
2129+
rackList.add("/region-1/default-rack");
2130+
// onBookieRackChange
2131+
StaticDNSResolver.changeRack(bookieAddressList, rackList);
2132+
2133+
assertEquals(4, repp.perRegionPlacement.size());
2134+
// addr1 bookie, oldRegion=default-region, newRegion=region-1
2135+
assertEquals("region-1", repp.address2Region.get(addr1.toBookieId()));
2136+
2137+
unknownRegionPlacement = repp.perRegionPlacement.get("UnknownRegion");
2138+
assertEquals(0, unknownRegionPlacement.knownBookies.keySet().size());
2139+
assertNotNull(unknownRegionPlacement.historyBookies.get(addr1.toBookieId()));
2140+
2141+
2142+
region1Placement = repp.perRegionPlacement.get("region-1");
2143+
assertEquals(2, region1Placement.knownBookies.keySet().size());
2144+
assertEquals("/region-1/default-rack",
2145+
region1Placement.knownBookies.get(addr1.toBookieId()).getNetworkLocation());
2146+
}
20302147
}

0 commit comments

Comments
 (0)