sanjeet006py commented on code in PR #8733:
URL: https://github.com/apache/hbase/pull/8733#discussion_r4229310168
##########
hbase-server/src/main/java/org/apache/hadoop/hbase/rsgroup/RSGroupInfoManagerImpl.java:
##########
@@ -742,30 +831,267 @@ private void updateCacheOfRSGroups(final Set<String>
currentGroups) {
this.prevRSGroups.addAll(currentGroups);
}
- // Called by ServerEventsListenerThread. Presume it has lock on this manager
when it runs.
- private SortedSet<Address> getDefaultServers() {
- return getDefaultServers(listRSGroups()/* get from rsGroupMap */);
+ /**
+ * Parses {@code hbase.rsgroup.regex.<groupname>=<regex>} entries out of
{@code conf}. Entries
+ * with an invalid group name, targeting the reserved {@link
RSGroupInfo#DEFAULT_GROUP}, or with
+ * an unparsable regex are logged and skipped.
+ */
+ static Map<String, Pattern> getRegexGroupMap(Configuration conf) {
+ Map<String, String> rsGroupNameToRegexMap =
conf.getPropsWithPrefix(RS_GROUP_REGEX_PREFIX);
+ Map<String, Pattern> rsGroupNameToPatternMap = new HashMap<>();
+ for (Map.Entry<String, String> e : rsGroupNameToRegexMap.entrySet()) {
+ if (e.getValue() == null) {
+ // getPropsWithPrefix reads names and values separately, so an entry
removed by a concurrent
+ // configuration reload can show up here with a null value. Treat it
as unset.
+ continue;
+ }
+ if (!GROUP_NAME_PATTERN.matcher(e.getKey()).matches()) {
+ LOG.warn("Ignoring {}{} -- '{}' is not a valid RSGroup name (only
alphanumeric characters "
+ + "and underscore allowed)", RS_GROUP_REGEX_PREFIX, e.getKey(),
e.getKey());
+ continue;
+ }
+ if (RSGroupInfo.DEFAULT_GROUP.equals(e.getKey())) {
+ LOG.warn("Ignoring {}{} -- regex-based membership cannot target the
reserved '{}' group",
+ RS_GROUP_REGEX_PREFIX, e.getKey(), RSGroupInfo.DEFAULT_GROUP);
+ continue;
+ }
+ try {
+ rsGroupNameToPatternMap.put(e.getKey(), Pattern.compile(e.getValue()));
+ } catch (PatternSyntaxException ex) {
+ LOG.warn("Invalid regex '{}' for RSGroup '{}' ({}{}); ignoring this
entry", e.getValue(),
+ e.getKey(), RS_GROUP_REGEX_PREFIX, e.getKey());
+ }
+ }
+ LOG.info("Resolved regex-based RSGroup membership config: {}",
rsGroupNameToPatternMap);
+ return rsGroupNameToPatternMap;
}
- // Called by ServerEventsListenerThread. Presume it has lock on this manager
when it runs.
- private SortedSet<Address> getDefaultServers(List<RSGroupInfo>
rsGroupInfoList) {
- // Build a list of servers in other groups than default group, from
rsGroupMap
- Set<Address> serversInOtherGroup = new HashSet<>();
- for (RSGroupInfo group : rsGroupInfoList) {
- if (!RSGroupInfo.DEFAULT_GROUP.equals(group.getName())) { // not default
group
- serversInOtherGroup.addAll(group.getServers());
+ private static List<String> getMatchingRSGroupNames(String hostname,
+ Map<String, Pattern> rsGroupNameToPatternMap) {
+ List<String> rsGroupNames = new ArrayList<>();
+ for (Map.Entry<String, Pattern> e : rsGroupNameToPatternMap.entrySet()) {
+ if (e.getValue().matcher(hostname).matches()) {
+ rsGroupNames.add(e.getKey());
}
}
+ LOG.info("Hostname '{}' matches RSGroup name(s) {}", hostname,
rsGroupNames);
+ return rsGroupNames;
+ }
- // Get all online servers from Zookeeper and find out servers in default
group
- SortedSet<Address> defaultServers = Sets.newTreeSet();
- for (ServerName serverName :
masterServices.getServerManager().getOnlineServers().keySet()) {
- Address server = Address.fromParts(serverName.getHostname(),
serverName.getPort());
- if (!serversInOtherGroup.contains(server)) { // not in other groups
- defaultServers.add(server);
+ /**
+ * Resolves every server in {@code onlineServers} whose hostname
unambiguously matches exactly one
+ * entry of {@code rsGroupNameToPatternMap} naming a group in {@code
existingGroupNames}. A server
+ * matching multiple regexes, or matching a regex for a group that does not
(yet) exist, is
+ * omitted (warn-only) rather than resolved.
+ */
+ static Map<Address, String> resolveServerAddrToRSGroupName(Set<Address>
onlineServers,
+ Map<String, Pattern> rsGroupNameToPatternMap, Set<String>
existingGroupNames) {
+ Map<Address, String> serverAddrToRSGroupName = new HashMap<>();
+ if (rsGroupNameToPatternMap.isEmpty()) {
+ return serverAddrToRSGroupName;
+ }
+ Set<String> nonExistingRSGroupNames = new HashSet<>();
+ for (Address server : onlineServers) {
+ List<String> matchingRSGroupNames =
+ getMatchingRSGroupNames(server.getHostName(), rsGroupNameToPatternMap);
+ if (matchingRSGroupNames.isEmpty()) {
+ continue;
+ }
+ if (matchingRSGroupNames.size() > 1) {
+ LOG.warn("Server {} hostname matches regexes for multiple RSGroups {};
treating it as "
+ + "unmatched by regex (falls back to default) until the overlapping "
+ + "hbase.rsgroup.regex.* entries are fixed", server,
matchingRSGroupNames);
+ continue;
+ }
+ String rsGroupName = matchingRSGroupNames.get(0);
+ if (existingGroupNames.contains(rsGroupName)) {
+ serverAddrToRSGroupName.put(server, rsGroupName);
+ } else if (nonExistingRSGroupNames.add(rsGroupName)) {
+ LOG.warn(
+ "Config {}{} matches server {} but RSGroup '{}' does not exist --
create it with "
+ + "addRSGroup first; treating this server as unmatched by regex
until then",
+ RS_GROUP_REGEX_PREFIX, rsGroupName, server, rsGroupName);
}
}
- return defaultServers;
+ LOG.info("Resolved server address to RSGroup name map: {}",
serverAddrToRSGroupName);
+ return serverAddrToRSGroupName;
+ }
+
+ /** Returns {@code true} if every online server is either admin-managed or
regex-matched. */
+ static boolean wouldEmptyDefaultGroup(Set<Address> onlineServers,
+ Set<Address> adminManagedServers, Set<Address> regexMatchedServers) {
+ for (Address server : onlineServers) {
+ if (!adminManagedServers.contains(server) &&
!regexMatchedServers.contains(server)) {
+ return false;
+ }
+ }
+ return !onlineServers.isEmpty();
+ }
+
+ static final class RegexBasedRSGroupMembershipResolution {
+ final Set<Address> adminManagedServers;
+ final Map<Address, String> regexMatchedServers;
+
+ RegexBasedRSGroupMembershipResolution(Set<Address> adminManagedServers,
+ Map<Address, String> regexMatchedServers) {
+ this.adminManagedServers = adminManagedServers;
+ this.regexMatchedServers = regexMatchedServers;
+ }
+ }
+
+ static RegexBasedRSGroupMembershipResolution
resolveRegexBasedRSGroupMembership(
+ Map<String, Pattern> rsGroupNameToPatternMap, Set<Address> onlineServers,
+ Collection<RSGroupInfo> existingGroups) {
+ Set<String> existingGroupNames =
+
existingGroups.stream().map(RSGroupInfo::getName).collect(Collectors.toSet());
+ Set<Address> adminManagedServers = new HashSet<>();
+ for (RSGroupInfo existingGroup : existingGroups) {
+ if (
+ !RSGroupInfo.DEFAULT_GROUP.equals(existingGroup.getName())
+ && !rsGroupNameToPatternMap.containsKey(existingGroup.getName())
+ ) {
+ adminManagedServers.addAll(existingGroup.getServers());
+ }
+ }
+ Map<Address, String> regexMatchedServers =
+ resolveServerAddrToRSGroupName(onlineServers, rsGroupNameToPatternMap,
existingGroupNames);
+ // A server stored in an admin-managed group that a regex now claims
belongs to the regex group.
+ adminManagedServers.removeAll(regexMatchedServers.keySet());
+ if (wouldEmptyDefaultGroup(onlineServers, adminManagedServers,
regexMatchedServers.keySet())) {
+ // Regex placement is still applied: every server lands in its correct
group. Operators are
+ // expected to configure regexes carefully, so this is a warning, not an
error.
+ LOG.warn(
+ "Regex-based RSGroup membership leaves RSGroup '{}' with no online
servers -- every "
+ + "online server is either admin-managed or matches a {}* entry.
Tables in RSGroup '{}' "
+ + "(including system tables, unless they are in another RSGroup)
have no server of "
+ + "their own to be assigned to; set {} to let them fall back to
servers of other "
+ + "RSGroups",
+ RSGroupInfo.DEFAULT_GROUP, RS_GROUP_REGEX_PREFIX,
RSGroupInfo.DEFAULT_GROUP,
+ RSGroupBasedLoadBalancer.FALLBACK_GROUP_ENABLE_KEY);
+ }
+ LOG.info(
+ "Regex-based RSGroup membership resolution: onlineServers={}, "
+ + "adminManagedServers={}, regexMatchedServers={}",
+ onlineServers, adminManagedServers, regexMatchedServers);
+ return new RegexBasedRSGroupMembershipResolution(adminManagedServers,
regexMatchedServers);
+ }
+
+ private Map<String, SortedSet<Address>>
+ computeAutoManagedRSGroupServers(Collection<RSGroupInfo> existingGroups) {
+ LOG.info("Computing auto-managed RSGroup server membership.");
+ Set<Address> onlineServers = getOnlineServers();
+ Map<String, Pattern> rsGroupNameToPatternMap =
+ getRegexGroupMap(masterServices.getConfiguration());
+ RegexBasedRSGroupMembershipResolution resolution =
+ resolveRegexBasedRSGroupMembership(rsGroupNameToPatternMap,
onlineServers, existingGroups);
+
+ Set<String> existingGroupNames =
+
existingGroups.stream().map(RSGroupInfo::getName).collect(Collectors.toSet());
+ Map<String, SortedSet<Address>> result = new HashMap<>();
+ for (String rsGroupName : rsGroupNameToPatternMap.keySet()) {
+ if (existingGroupNames.contains(rsGroupName)) {
+ result.put(rsGroupName, new TreeSet<>());
+ }
+ }
+ result.put(RSGroupInfo.DEFAULT_GROUP, new TreeSet<>());
+
+ for (Address server : onlineServers) {
+ String regexGroupName = resolution.regexMatchedServers.get(server);
+ if (regexGroupName != null) {
+ result.get(regexGroupName).add(server);
+ continue;
+ }
+ if (resolution.adminManagedServers.contains(server)) {
+ continue;
+ }
+ result.get(RSGroupInfo.DEFAULT_GROUP).add(server);
+ }
+ for (Map.Entry<String, SortedSet<Address>> entry : result.entrySet()) {
+ if (entry.getValue().isEmpty() &&
!RSGroupInfo.DEFAULT_GROUP.equals(entry.getKey())) {
+ LOG.warn(
+ "Regex-governed RSGroup '{}' has no online servers; any table
assigned to it has "
+ + "nowhere to go (check {}{} and the online servers' hostnames)",
+ entry.getKey(), RS_GROUP_REGEX_PREFIX, entry.getKey());
+ }
+ }
+ LOG.info("Computed auto-managed RSGroup server membership: {}", result);
Review Comment:
Changed to `debug` log level.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]