You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by al...@apache.org on 2021/12/12 09:01:38 UTC

[dubbo] branch 3.0 updated: [3.0] Add router fail fast option (#9388)

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

albumenj pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.0 by this push:
     new 312dd2b  [3.0] Add router fail fast option (#9388)
312dd2b is described below

commit 312dd2b7acc7c365ac330955f3634a2e0bb4c149
Author: Albumen Kevin <jh...@gmail.com>
AuthorDate: Sun Dec 12 17:01:06 2021 +0800

    [3.0] Add router fail fast option (#9388)
---
 .../org/apache/dubbo/rpc/cluster/Constants.java    |  2 ++
 .../org/apache/dubbo/rpc/cluster/RouterChain.java  | 23 ++++++++++++++++------
 .../registry/integration/DynamicDirectory.java     | 18 ++++++++++++++---
 3 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Constants.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Constants.java
index ad9bd0d..c493610 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Constants.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Constants.java
@@ -135,4 +135,6 @@ public interface Constants {
      * The key of shortestResponseSlidePeriod
      */
     String SHORTEST_RESPONSE_SLIDE_PERIOD = "shortestResponseSlidePeriod";
+
+    String SHOULD_FAIL_FAST_KEY = "dubbo.router.should-fail-fast";
 }
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java
index 12e32c7..b4ca2c5 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java
@@ -18,6 +18,7 @@ package org.apache.dubbo.rpc.cluster;
 
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.Version;
+import org.apache.dubbo.common.config.ConfigurationUtils;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.CollectionUtils;
@@ -30,6 +31,7 @@ import org.apache.dubbo.rpc.cluster.router.state.BitList;
 import org.apache.dubbo.rpc.cluster.router.state.StateRouter;
 import org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory;
 import org.apache.dubbo.rpc.cluster.router.state.StateRouterResult;
+import org.apache.dubbo.rpc.model.ModuleModel;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -63,12 +65,19 @@ public class RouterChain<T> {
     private volatile List<StateRouter<T>> builtinStateRouters = Collections.emptyList();
     private volatile List<StateRouter<T>> stateRouters = Collections.emptyList();
 
+    /**
+     * Should continue route if current router's result is empty
+     */
+    private final boolean shouldFailFast;
+
     public static <T> RouterChain<T> buildChain(Class<T> interfaceClass, URL url) {
         return new RouterChain<>(interfaceClass, url);
     }
 
     private RouterChain(Class<T> interfaceClass, URL url) {
-        List<RouterFactory> extensionFactories = url.getOrDefaultApplicationModel().getExtensionLoader(RouterFactory.class)
+        ModuleModel moduleModel = url.getOrDefaultModuleModel();
+
+        List<RouterFactory> extensionFactories = moduleModel.getExtensionLoader(RouterFactory.class)
             .getActivateExtension(url, ROUTER_KEY);
 
         List<Router> routers = extensionFactories.stream()
@@ -78,7 +87,7 @@ public class RouterChain<T> {
 
         initWithRouters(routers);
 
-        List<StateRouterFactory> extensionStateRouterFactories = url.getOrDefaultApplicationModel()
+        List<StateRouterFactory> extensionStateRouterFactories = moduleModel
             .getExtensionLoader(StateRouterFactory.class)
             .getActivateExtension(url, ROUTER_KEY);
 
@@ -89,6 +98,8 @@ public class RouterChain<T> {
 
         // init state routers
         initWithStateRouters(stateRouters);
+
+        this.shouldFailFast = Boolean.parseBoolean(ConfigurationUtils.getProperty(moduleModel, Constants.SHOULD_FAIL_FAST_KEY, "true"));
     }
 
     /**
@@ -158,7 +169,7 @@ public class RouterChain<T> {
         for (StateRouter<T> stateRouter : stateRouters) {
             StateRouterResult<Invoker<T>> routeResult = stateRouter.route(resultInvokers, url, invocation, false);
             resultInvokers = routeResult.getResult();
-            if (resultInvokers.isEmpty()) {
+            if (resultInvokers.isEmpty() && shouldFailFast) {
                 printRouterSnapshot(url, availableInvokers, invocation);
                 return BitList.emptyList();
             }
@@ -179,7 +190,7 @@ public class RouterChain<T> {
             // Copy resultInvokers to a arrayList. BitList not support
             RouterResult<Invoker<T>> routeResult = router.route(commonRouterResult, url, invocation, false);
             commonRouterResult = routeResult.getResult();
-            if (CollectionUtils.isEmpty(commonRouterResult)) {
+            if (CollectionUtils.isEmpty(commonRouterResult) && shouldFailFast) {
                 printRouterSnapshot(url, availableInvokers, invocation);
                 return BitList.emptyList();
             }
@@ -222,7 +233,7 @@ public class RouterChain<T> {
             currentNode.setRouterMessage(routerMessage);
 
             // result is empty, log out
-            if (resultInvokers.isEmpty()) {
+            if (resultInvokers.isEmpty() && shouldFailFast) {
                 return snapshotNode;
             }
 
@@ -248,7 +259,7 @@ public class RouterChain<T> {
             currentNode.setRouterMessage(routerMessage);
 
             // result is empty, log out
-            if (CollectionUtils.isEmpty(routeResult)) {
+            if (CollectionUtils.isEmpty(routeResult) && shouldFailFast) {
                 return snapshotNode;
             } else {
                 commonRouterResult = routeResult;
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java
index 9a907d6..65b71a7 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java
@@ -18,6 +18,7 @@ package org.apache.dubbo.registry.integration;
 
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.Version;
+import org.apache.dubbo.common.config.ConfigurationUtils;
 import org.apache.dubbo.common.extension.ExtensionLoader;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
@@ -34,10 +35,12 @@ import org.apache.dubbo.rpc.Protocol;
 import org.apache.dubbo.rpc.RpcException;
 import org.apache.dubbo.rpc.cluster.Cluster;
 import org.apache.dubbo.rpc.cluster.Configurator;
+import org.apache.dubbo.rpc.cluster.Constants;
 import org.apache.dubbo.rpc.cluster.RouterChain;
 import org.apache.dubbo.rpc.cluster.RouterFactory;
 import org.apache.dubbo.rpc.cluster.directory.AbstractDirectory;
 import org.apache.dubbo.rpc.cluster.router.state.BitList;
+import org.apache.dubbo.rpc.model.ModuleModel;
 
 import java.util.List;
 
@@ -107,11 +110,18 @@ public abstract class DynamicDirectory<T> extends AbstractDirectory<T> implement
 
     protected ServiceInstancesChangedListener serviceListener;
 
+    /**
+     * Should continue route if directory is empty
+     */
+    private final boolean shouldFailFast;
+
     public DynamicDirectory(Class<T> serviceType, URL url) {
         super(url, true);
 
-        this.cluster = url.getOrDefaultApplicationModel().getExtensionLoader(Cluster.class).getAdaptiveExtension();
-        this.routerFactory = url.getOrDefaultApplicationModel().getExtensionLoader(RouterFactory.class).getAdaptiveExtension();
+        ModuleModel moduleModel = url.getOrDefaultModuleModel();
+
+        this.cluster = moduleModel.getExtensionLoader(Cluster.class).getAdaptiveExtension();
+        this.routerFactory = moduleModel.getExtensionLoader(RouterFactory.class).getAdaptiveExtension();
 
         if (serviceType == null) {
             throw new IllegalArgumentException("service type is null.");
@@ -130,6 +140,8 @@ public abstract class DynamicDirectory<T> extends AbstractDirectory<T> implement
         this.directoryUrl = consumerUrl;
         String group = directoryUrl.getGroup("");
         this.multiGroup = group != null && (ANY_VALUE.equals(group) || group.contains(","));
+
+        this.shouldFailFast = Boolean.parseBoolean(ConfigurationUtils.getProperty(moduleModel, Constants.SHOULD_FAIL_FAST_KEY, "true"));
     }
 
     @Override
@@ -165,7 +177,7 @@ public abstract class DynamicDirectory<T> extends AbstractDirectory<T> implement
 
     @Override
     public List<Invoker<T>> doList(BitList<Invoker<T>> invokers, Invocation invocation) {
-        if (forbidden) {
+        if (forbidden && shouldFailFast) {
             // 1. No service provider 2. Service providers are disabled
             throw new RpcException(RpcException.FORBIDDEN_EXCEPTION, "No provider available from registry " +
                 getUrl().getAddress() + " for service " + getConsumerUrl().getServiceKey() + " on consumer " +