You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by zh...@apache.org on 2026/10/11 04:52:06 UTC

(hbase) branch branch-3 updated: HBASE-30409 Move throttle enabled flag storage from zookeeper to master local region (#8705)

This is an automated email from the ASF dual-hosted git repository.

Apache9 pushed a commit to branch branch-3
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/branch-3 by this push:
     new 80c0e46e25b HBASE-30409 Move throttle enabled flag storage from zookeeper to master local region (#8705)
80c0e46e25b is described below

commit 80c0e46e25b28b9cb5b34bb01e46a0de22c92e6b
Author: Duo Zhang <zh...@apache.org>
AuthorDate: Sun Oct 11 12:22:14 2026 +0800

    HBASE-30409 Move throttle enabled flag storage from zookeeper to master local region (#8705)
    
    Signed-off-by: Charles Connell <cc...@apache.org>
    (cherry picked from commit 9b00e9ca8b01e497f33836475cfa5071e65c2f3b)
---
 .../server/master/RegionServerStatus.proto         | 15 ++++-
 .../hadoop/hbase/MockRegionServerServices.java     |  5 ++
 .../org/apache/hadoop/hbase/master/HMaster.java    | 12 ++++
 .../hadoop/hbase/master/MasterRpcServices.java     |  9 +++
 .../master/MasterRpcServicesVersionWrapper.java    |  8 +++
 .../apache/hadoop/hbase/master/MasterServices.java |  3 +
 .../procedure/SwitchRpcThrottleProcedure.java      | 27 +++------
 .../hadoop/hbase/quotas/MasterQuotaManager.java    | 15 ++---
 .../hbase/quotas/RegionServerRpcQuotaManager.java  | 16 ++---
 .../hadoop/hbase/quotas/RpcThrottleStateStore.java | 60 +++++++++++++++++++
 .../hadoop/hbase/quotas/RpcThrottleStorage.java    | 68 ----------------------
 .../hadoop/hbase/regionserver/HRegionServer.java   | 25 ++++++++
 .../hbase/regionserver/RegionServerServices.java   |  2 +
 .../hbase/master/MockNoopMasterServices.java       |  6 ++
 .../hadoop/hbase/master/MockRegionServer.java      |  5 ++
 15 files changed, 167 insertions(+), 109 deletions(-)

diff --git a/hbase-protocol-shaded/src/main/protobuf/server/master/RegionServerStatus.proto b/hbase-protocol-shaded/src/main/protobuf/server/master/RegionServerStatus.proto
index 3d2d8c6ff5f..e9892e0b58f 100644
--- a/hbase-protocol-shaded/src/main/protobuf/server/master/RegionServerStatus.proto
+++ b/hbase-protocol-shaded/src/main/protobuf/server/master/RegionServerStatus.proto
@@ -190,6 +190,13 @@ message GetLiveRegionServersResponse {
   required uint32 total = 2;
 }
 
+message GetThrottleStateRequest {
+}
+
+message GetThrottleStateResponse {
+  required bool rpc_throttle_enabled = 1;
+}
+
 service RegionServerStatusService {
   /** Called when a region server first starts. */
   rpc RegionServerStartup(RegionServerStartupRequest)
@@ -236,4 +243,10 @@ service RegionServerStatusService {
   /** Get some live region servers to be used as seed for bootstrap nodes */
   rpc GetLiveRegionServers(GetLiveRegionServersRequest)
     returns(GetLiveRegionServersResponse);
-}
+
+  /**
+   * Get throttle state. Mainly used for checking whether rpc throttle is enabled.
+   */
+  rpc GetThrottleState(GetThrottleStateRequest)
+    returns(GetThrottleStateResponse);
+}
\ No newline at end of file
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/MockRegionServerServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/MockRegionServerServices.java
index 32ad587ad96..389074b9417 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/MockRegionServerServices.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/MockRegionServerServices.java
@@ -386,4 +386,9 @@ public class MockRegionServerServices implements RegionServerServices {
   public RegionReplicationBufferManager getRegionReplicationBufferManager() {
     return null;
   }
+
+  @Override
+  public boolean isRpcThrottleEnabled() throws IOException {
+    return false;
+  }
 }
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
index 5ebda0a30a0..2399bf2f029 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
@@ -220,6 +220,7 @@ import org.apache.hadoop.hbase.quotas.MasterQuotasObserver;
 import org.apache.hadoop.hbase.quotas.QuotaObserverChore;
 import org.apache.hadoop.hbase.quotas.QuotaTableUtil;
 import org.apache.hadoop.hbase.quotas.QuotaUtil;
+import org.apache.hadoop.hbase.quotas.RpcThrottleStateStore;
 import org.apache.hadoop.hbase.quotas.SnapshotQuotaObserverChore;
 import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshot;
 import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshot.SpaceQuotaStatus;
@@ -467,6 +468,7 @@ public class HMaster extends HBaseServerBase<MasterRpcServices> implements Maste
   private RegionsRecoveryConfigManager regionsRecoveryConfigManager = null;
   // it is assigned after 'initialized' guard set to true, so should be volatile
   private volatile MasterQuotaManager quotaManager;
+  private RpcThrottleStateStore rpcThrottleStateStore;
   private SpaceQuotaSnapshotNotifier spaceQuotaSnapshotNotifier;
   private QuotaObserverChore quotaObserverChore;
   private SnapshotQuotaObserverChore snapshotQuotaChore;
@@ -889,6 +891,11 @@ public class HMaster extends HBaseServerBase<MasterRpcServices> implements Maste
     this.mpmHost.register(new MasterFlushTableProcedureManager());
     this.mpmHost.loadProcedures(conf);
     this.mpmHost.initialize(this, this.metricsMaster);
+
+    String rpcThrottleZNode = conf.get(RpcThrottleStateStore.RPC_THROTTLE_ZNODE,
+      RpcThrottleStateStore.RPC_THROTTLE_ZNODE_DEFAULT);
+    this.rpcThrottleStateStore = new RpcThrottleStateStore(masterRegion, zooKeeper,
+      ZNodePaths.joinZNode(zooKeeper.getZNodePaths().baseZNode, rpcThrottleZNode));
   }
 
   // Will be overriden in test to inject customized AssignmentManager
@@ -4793,4 +4800,9 @@ public class HMaster extends HBaseServerBase<MasterRpcServices> implements Maste
         }
       });
   }
+
+  @Override
+  public RpcThrottleStateStore getRpcThrottleStateStore() {
+    return rpcThrottleStateStore;
+  }
 }
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
index f62ff122060..a8fc92913fb 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java
@@ -407,6 +407,8 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProto
 import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.GetLastFlushedSequenceIdResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.GetLiveRegionServersRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.GetLiveRegionServersResponse;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.GetThrottleStateRequest;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.GetThrottleStateResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.RegionServerReportRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.RegionServerReportResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.RegionServerStartupRequest;
@@ -3666,6 +3668,13 @@ public class MasterRpcServices extends HBaseRpcServicesBase<HMaster>
     return builder.build();
   }
 
+  @Override
+  public GetThrottleStateResponse getThrottleState(RpcController controller,
+    GetThrottleStateRequest request) throws ServiceException {
+    boolean on = server.getRpcThrottleStateStore().get();
+    return GetThrottleStateResponse.newBuilder().setRpcThrottleEnabled(on).build();
+  }
+
   @Override
   public ReplicateWALEntryResponse replicateToReplica(RpcController controller,
     ReplicateWALEntryRequest request) throws ServiceException {
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServicesVersionWrapper.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServicesVersionWrapper.java
index fabae6741b8..34fbecd8bea 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServicesVersionWrapper.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServicesVersionWrapper.java
@@ -26,6 +26,8 @@ import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.GetLiveRegionServersRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.GetLiveRegionServersResponse;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.GetThrottleStateRequest;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.GetThrottleStateResponse;
 
 /**
  * A wrapper class for MasterRpcServices shortcut that ensures a client version is available to the
@@ -113,4 +115,10 @@ public class MasterRpcServicesVersionWrapper
     GetLiveRegionServersRequest request) throws ServiceException {
     return masterRpcServices.getLiveRegionServers(controller, request);
   }
+
+  @Override
+  public GetThrottleStateResponse getThrottleState(RpcController controller,
+    GetThrottleStateRequest request) throws ServiceException {
+    return masterRpcServices.getThrottleState(controller, request);
+  }
 }
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterServices.java
index 0573b1a7562..df8dfb9d335 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterServices.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterServices.java
@@ -49,6 +49,7 @@ import org.apache.hadoop.hbase.procedure2.Procedure;
 import org.apache.hadoop.hbase.procedure2.ProcedureEvent;
 import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
 import org.apache.hadoop.hbase.quotas.MasterQuotaManager;
+import org.apache.hadoop.hbase.quotas.RpcThrottleStateStore;
 import org.apache.hadoop.hbase.replication.ReplicationException;
 import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
 import org.apache.hadoop.hbase.replication.ReplicationPeerDescription;
@@ -521,4 +522,6 @@ public interface MasterServices extends Server {
    * @return procedure id
    */
   long rollAllWALWriters(long nonceGroup, long nonce) throws IOException;
+
+  RpcThrottleStateStore getRpcThrottleStateStore();
 }
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/SwitchRpcThrottleProcedure.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/SwitchRpcThrottleProcedure.java
index ece7d3dc45e..3706d571017 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/SwitchRpcThrottleProcedure.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/SwitchRpcThrottleProcedure.java
@@ -24,7 +24,6 @@ import org.apache.hadoop.hbase.procedure2.ProcedureSuspendedException;
 import org.apache.hadoop.hbase.procedure2.ProcedureUtil;
 import org.apache.hadoop.hbase.procedure2.ProcedureYieldException;
 import org.apache.hadoop.hbase.procedure2.StateMachineProcedure;
-import org.apache.hadoop.hbase.quotas.RpcThrottleStorage;
 import org.apache.hadoop.hbase.util.RetryCounter;
 import org.apache.yetus.audience.InterfaceAudience;
 import org.slf4j.Logger;
@@ -40,11 +39,10 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.ProcedureProtos;
 @InterfaceAudience.Private
 public class SwitchRpcThrottleProcedure
   extends StateMachineProcedure<MasterProcedureEnv, SwitchRpcThrottleState>
-  implements ServerProcedureInterface {
+  implements GlobalProcedureInterface {
 
   private static Logger LOG = LoggerFactory.getLogger(SwitchRpcThrottleProcedure.class);
 
-  private RpcThrottleStorage rpcThrottleStorage;
   private boolean rpcThrottleEnabled;
   private ProcedurePrepareLatch syncLatch;
   private ServerName serverName;
@@ -53,9 +51,8 @@ public class SwitchRpcThrottleProcedure
   public SwitchRpcThrottleProcedure() {
   }
 
-  public SwitchRpcThrottleProcedure(RpcThrottleStorage rpcThrottleStorage,
-    boolean rpcThrottleEnabled, ServerName serverName, final ProcedurePrepareLatch syncLatch) {
-    this.rpcThrottleStorage = rpcThrottleStorage;
+  public SwitchRpcThrottleProcedure(boolean rpcThrottleEnabled, ServerName serverName,
+    final ProcedurePrepareLatch syncLatch) {
     this.syncLatch = syncLatch;
     this.rpcThrottleEnabled = rpcThrottleEnabled;
     this.serverName = serverName;
@@ -138,23 +135,13 @@ public class SwitchRpcThrottleProcedure
   }
 
   @Override
-  public ServerName getServerName() {
-    return serverName;
+  public String getGlobalId() {
+    return getClass().getSimpleName();
   }
 
-  @Override
-  public boolean hasMetaTableRegion() {
-    return false;
-  }
-
-  @Override
-  public ServerOperationType getServerOperationType() {
-    return ServerOperationType.SWITCH_RPC_THROTTLE;
-  }
-
-  public void switchThrottleState(MasterProcedureEnv env, boolean rpcThrottleEnabled)
+  private void switchThrottleState(MasterProcedureEnv env, boolean rpcThrottleEnabled)
     throws IOException {
-    rpcThrottleStorage.switchRpcThrottle(rpcThrottleEnabled);
+    env.getMasterServices().getRpcThrottleStateStore().set(rpcThrottleEnabled);
   }
 
   @Override
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/MasterQuotaManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/MasterQuotaManager.java
index e310a4e4a45..3f4ba9f59ed 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/MasterQuotaManager.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/MasterQuotaManager.java
@@ -84,10 +84,8 @@ public class MasterQuotaManager implements RegionStateListener {
   private boolean initialized = false;
   private NamespaceAuditor namespaceQuotaManager;
   private ConcurrentHashMap<RegionInfo, SizeSnapshotWithTimestamp> regionSizes;
-  // Storage for quota rpc throttle
-  private RpcThrottleStorage rpcThrottleStorage;
 
-  public MasterQuotaManager(final MasterServices masterServices) {
+  public MasterQuotaManager(MasterServices masterServices) {
     this.masterServices = masterServices;
   }
 
@@ -114,9 +112,6 @@ public class MasterQuotaManager implements RegionStateListener {
     namespaceQuotaManager = new NamespaceAuditor(masterServices);
     namespaceQuotaManager.start();
     initialized = true;
-
-    rpcThrottleStorage =
-      new RpcThrottleStorage(masterServices.getZooKeeper(), masterServices.getConfiguration());
   }
 
   public void stop() {
@@ -394,13 +389,13 @@ public class MasterQuotaManager implements RegionStateListener {
     boolean rpcThrottle = request.getRpcThrottleEnabled();
     if (initialized) {
       masterServices.getMasterCoprocessorHost().preSwitchRpcThrottle(rpcThrottle);
-      boolean oldRpcThrottle = rpcThrottleStorage.isRpcThrottleEnabled();
+      boolean oldRpcThrottle = masterServices.getRpcThrottleStateStore().get();
       if (rpcThrottle != oldRpcThrottle) {
         LOG.info("{} switch rpc throttle from {} to {}", masterServices.getClientIdAuditPrefix(),
           oldRpcThrottle, rpcThrottle);
         ProcedurePrepareLatch latch = ProcedurePrepareLatch.createBlockingLatch();
-        SwitchRpcThrottleProcedure procedure = new SwitchRpcThrottleProcedure(rpcThrottleStorage,
-          rpcThrottle, masterServices.getServerName(), latch);
+        SwitchRpcThrottleProcedure procedure =
+          new SwitchRpcThrottleProcedure(rpcThrottle, masterServices.getServerName(), latch);
         masterServices.getMasterProcedureExecutor().submitProcedure(procedure);
         latch.await();
       } else {
@@ -433,7 +428,7 @@ public class MasterQuotaManager implements RegionStateListener {
   }
 
   public boolean isRpcThrottleEnabled() throws IOException {
-    return initialized ? rpcThrottleStorage.isRpcThrottleEnabled() : false;
+    return initialized && masterServices.getRpcThrottleStateStore().get();
   }
 
   public SwitchExceedThrottleQuotaResponse
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/RegionServerRpcQuotaManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/RegionServerRpcQuotaManager.java
index b2716c50e14..65683390560 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/RegionServerRpcQuotaManager.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/RegionServerRpcQuotaManager.java
@@ -56,14 +56,10 @@ public class RegionServerRpcQuotaManager implements RpcQuotaManager, Configurati
 
   private QuotaCache quotaCache = null;
   private volatile boolean rpcThrottleEnabled;
-  // Storage for quota rpc throttle
-  private RpcThrottleStorage rpcThrottleStorage;
   private final Supplier<Double> requestsPerSecondSupplier;
 
   public RegionServerRpcQuotaManager(final RegionServerServices rsServices) {
     this.rsServices = rsServices;
-    rpcThrottleStorage =
-      new RpcThrottleStorage(rsServices.getZooKeeper(), rsServices.getConfiguration());
     this.requestsPerSecondSupplier = Suppliers.memoizeWithExpiration(
       () -> rsServices.getMetrics().getRegionServerWrapper().getRequestsPerSecond(), 1,
       TimeUnit.MINUTES);
@@ -80,7 +76,7 @@ public class RegionServerRpcQuotaManager implements RpcQuotaManager, Configurati
     // Initialize quota cache
     quotaCache = new QuotaCache(rsServices);
     quotaCache.start();
-    rpcThrottleEnabled = rpcThrottleStorage.isRpcThrottleEnabled();
+    rpcThrottleEnabled = rsServices.isRpcThrottleEnabled();
     LOG.info("Start rpc quota manager and rpc throttle enabled is {}", rpcThrottleEnabled);
   }
 
@@ -111,14 +107,14 @@ public class RegionServerRpcQuotaManager implements RpcQuotaManager, Configurati
 
   public void switchRpcThrottle(boolean enable) throws IOException {
     if (isQuotaEnabled()) {
-      if (rpcThrottleEnabled != enable) {
-        boolean previousEnabled = rpcThrottleEnabled;
-        rpcThrottleEnabled = rpcThrottleStorage.isRpcThrottleEnabled();
-        LOG.info("Switch rpc throttle from {} to {}", previousEnabled, rpcThrottleEnabled);
+      boolean previousEnabled = rpcThrottleEnabled;
+      if (previousEnabled != enable) {
+        rpcThrottleEnabled = enable;
+        LOG.info("Switch rpc throttle from {} to {}", previousEnabled, enable);
       } else {
         LOG.warn(
           "Skip switch rpc throttle because previous value {} is the same as current value {}",
-          rpcThrottleEnabled, enable);
+          previousEnabled, enable);
       }
     } else {
       LOG.warn("Skip switch rpc throttle to {} because rpc quota is disabled", enable);
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/RpcThrottleStateStore.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/RpcThrottleStateStore.java
new file mode 100644
index 00000000000..dddda2f586d
--- /dev/null
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/RpcThrottleStateStore.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.quotas;
+
+import java.io.IOException;
+import org.apache.hadoop.hbase.exceptions.DeserializationException;
+import org.apache.hadoop.hbase.master.BooleanStateStore;
+import org.apache.hadoop.hbase.master.region.MasterRegion;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
+import org.apache.yetus.audience.InterfaceAudience;
+import org.apache.zookeeper.KeeperException;
+
+/**
+ * Store whether rpc throttle is enabled.
+ * <p>
+ * Notice that, this is stored in master local region so only master can read it. For region
+ * servers, we will publish the change through
+ * {@link org.apache.hadoop.hbase.master.procedure.SwitchRpcThrottleProcedure} and region servers
+ * can also query the flag through rpc request to master.
+ */
+@InterfaceAudience.Private
+public class RpcThrottleStateStore extends BooleanStateStore {
+
+  public static final String RPC_THROTTLE_ZNODE = "zookeeper.znode.quota.rpc.throttle";
+  public static final String RPC_THROTTLE_ZNODE_DEFAULT = "rpc-throttle";
+
+  public static final String STATE_NAME = "rpc-throttle";
+
+  public RpcThrottleStateStore(MasterRegion masterRegion, ZKWatcher watcher, String zkPath)
+    throws IOException, KeeperException, DeserializationException {
+    super(masterRegion, STATE_NAME, watcher, zkPath);
+  }
+
+  @Override
+  protected byte[] toByteArray(boolean on) {
+    return Bytes.toBytes(on);
+  }
+
+  @Override
+  protected boolean parseFrom(byte[] bytes) throws DeserializationException {
+    return Bytes.toBoolean(bytes);
+  }
+
+}
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/RpcThrottleStorage.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/RpcThrottleStorage.java
deleted file mode 100644
index ee114ebb4e8..00000000000
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/RpcThrottleStorage.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.hadoop.hbase.quotas;
-
-import java.io.IOException;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.hbase.util.Bytes;
-import org.apache.hadoop.hbase.zookeeper.ZKUtil;
-import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
-import org.apache.hadoop.hbase.zookeeper.ZNodePaths;
-import org.apache.yetus.audience.InterfaceAudience;
-import org.apache.zookeeper.KeeperException;
-
-/**
- * ZK based rpc throttle storage.
- */
-@InterfaceAudience.Private
-public class RpcThrottleStorage {
-  public static final String RPC_THROTTLE_ZNODE = "zookeeper.znode.quota.rpc.throttle";
-  public static final String RPC_THROTTLE_ZNODE_DEFAULT = "rpc-throttle";
-
-  private final ZKWatcher zookeeper;
-  private final String rpcThrottleZNode;
-
-  public RpcThrottleStorage(ZKWatcher zookeeper, Configuration conf) {
-    this.zookeeper = zookeeper;
-    this.rpcThrottleZNode = ZNodePaths.joinZNode(zookeeper.getZNodePaths().baseZNode,
-      conf.get(RPC_THROTTLE_ZNODE, RPC_THROTTLE_ZNODE_DEFAULT));
-  }
-
-  public boolean isRpcThrottleEnabled() throws IOException {
-    try {
-      byte[] upData = ZKUtil.getData(zookeeper, rpcThrottleZNode);
-      return upData == null || Bytes.toBoolean(upData);
-    } catch (KeeperException | InterruptedException e) {
-      throw new IOException("Failed to get rpc throttle", e);
-    }
-  }
-
-  /**
-   * Store the rpc throttle value.
-   * @param enable Set to <code>true</code> to enable, <code>false</code> to disable.
-   * @throws IOException if an unexpected io exception occurs
-   */
-  public void switchRpcThrottle(boolean enable) throws IOException {
-    try {
-      byte[] upData = Bytes.toBytes(enable);
-      ZKUtil.createSetData(zookeeper, rpcThrottleZNode, upData);
-    } catch (KeeperException e) {
-      throw new IOException("Failed to store rpc throttle", e);
-    }
-  }
-}
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java
index e11b334442f..42cecf4c810 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java
@@ -223,6 +223,8 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.LockServiceProtos.LockS
 import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.GetLastFlushedSequenceIdRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.GetLastFlushedSequenceIdResponse;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.GetThrottleStateRequest;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.GetThrottleStateResponse;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.RegionServerReportRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.RegionServerStartupRequest;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos.RegionServerStartupResponse;
@@ -3644,6 +3646,29 @@ public class HRegionServer extends HBaseServerBase<RSRpcServices>
     }
   }
 
+  @Override
+  public boolean isRpcThrottleEnabled() throws IOException {
+    RegionServerStatusService.BlockingInterface rss = rssStub;
+    if (rss == null) { // Try to connect one more time
+      createRegionServerStatusStub();
+      rss = rssStub;
+      if (rss == null) {
+        // Still no luck, we tried
+        throw new IOException("failed to connect to master");
+      }
+    }
+    GetThrottleStateResponse resp;
+    try {
+      resp = rss.getThrottleState(null, GetThrottleStateRequest.getDefaultInstance());
+    } catch (ServiceException e) {
+      if (rssStub == rss) {
+        rssStub = null;
+      }
+      throw ProtobufUtil.getRemoteException(e);
+    }
+    return resp.getRpcThrottleEnabled();
+  }
+
   /**
    * Will ignore the open/close region procedures which already submitted or executed. When master
    * had unfinished open/close region procedure and restarted, new active master may send duplicate
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionServerServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionServerServices.java
index a46e2dae695..ea1b1cde1d5 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionServerServices.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionServerServices.java
@@ -304,4 +304,6 @@ public interface RegionServerServices extends Server, MutableOnlineRegions, Favo
 
   @Override
   List<HRegion> getRegions();
+
+  boolean isRpcThrottleEnabled() throws IOException;
 }
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockNoopMasterServices.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockNoopMasterServices.java
index daaa2e5c2b9..0f01fde0af6 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockNoopMasterServices.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockNoopMasterServices.java
@@ -54,6 +54,7 @@ import org.apache.hadoop.hbase.procedure2.Procedure;
 import org.apache.hadoop.hbase.procedure2.ProcedureEvent;
 import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
 import org.apache.hadoop.hbase.quotas.MasterQuotaManager;
+import org.apache.hadoop.hbase.quotas.RpcThrottleStateStore;
 import org.apache.hadoop.hbase.replication.ReplicationException;
 import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
 import org.apache.hadoop.hbase.replication.ReplicationPeerDescription;
@@ -573,4 +574,9 @@ public class MockNoopMasterServices implements MasterServices {
   public long rollAllWALWriters(long nonceGroup, long nonce) throws IOException {
     return 0;
   }
+
+  @Override
+  public RpcThrottleStateStore getRpcThrottleStateStore() {
+    return null;
+  }
 }
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockRegionServer.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockRegionServer.java
index a25bae6ec7b..f5533652db5 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockRegionServer.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockRegionServer.java
@@ -757,4 +757,9 @@ class MockRegionServer implements AdminProtos.AdminService.BlockingInterface,
     ReplicateWALEntryRequest request) throws ServiceException {
     return null;
   }
+
+  @Override
+  public boolean isRpcThrottleEnabled() throws IOException {
+    return false;
+  }
 }