[SCB-2643]fix instance isolation filter not work problem (#3310)

diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/BeansHolder.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/BeansHolder.java
index d70bfb2..bb5c4db 100644
--- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/BeansHolder.java
+++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/BeansHolder.java
@@ -20,9 +20,6 @@
 
 import javax.inject.Inject;
 
-import org.springframework.stereotype.Component;
-
-@Component
 public class BeansHolder {
   @Inject
   private List<ExtensionsFactory> extentionsFactories;
diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadBalancer.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadBalancer.java
index aced1f5..4b7dfda 100644
--- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadBalancer.java
+++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadBalancer.java
@@ -34,13 +34,13 @@
 public class LoadBalancer {
   private static final Logger LOGGER = LoggerFactory.getLogger(LoadBalancer.class);
 
-  private static AtomicInteger id = new AtomicInteger(0);
+  private static final AtomicInteger id = new AtomicInteger(0);
 
-  private RuleExt rule;
+  private final RuleExt rule;
 
-  private LoadBalancerStats lbStats;
+  private final LoadBalancerStats lbStats;
 
-  private String microServiceName;
+  private final String microServiceName;
 
   private List<ServerListFilterExt> filters;
 
@@ -58,7 +58,7 @@
     List<ServiceCombServer> servers = invocation.getLocalContext(LoadbalanceHandler.CONTEXT_KEY_SERVER_LIST);
     int serversCount = servers.size();
     for (ServerListFilterExt filterExt : filters) {
-      if(!filterExt.enabled()) {
+      if (!filterExt.enabled()) {
         continue;
       }
       servers = filterExt.getFilteredListOfServers(servers, invocation);
@@ -76,6 +76,8 @@
       LOGGER.info("The Service {}'s instance {} has been isolated for a while, give a single test opportunity.",
           invocation.getMicroserviceName(),
           server.getInstance().getInstanceId());
+      LOGGER.info("stats: {}-{}-{}-{}", serverStats.getTotalRequests(), serverStats.getSuccessRequests(),
+          serverStats.getFailedRequests(), serverStats.getContinuousFailureCount());
     }
     return server;
   }
diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RandomRuleExt.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RandomRuleExt.java
index 6671d81..5f8d26c 100644
--- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RandomRuleExt.java
+++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RandomRuleExt.java
@@ -18,7 +18,7 @@
 package org.apache.servicecomb.loadbalance;
 
 import java.util.List;
-import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
 
 import org.apache.servicecomb.core.Invocation;
 
@@ -26,14 +26,12 @@
  * A random rule.
  */
 public class RandomRuleExt implements RuleExt {
-  private Random random = new Random();
-
   @Override
   public ServiceCombServer choose(List<ServiceCombServer> servers, Invocation invocation) {
     if (servers.isEmpty()) {
       return null;
     }
-    int index = Math.abs(random.nextInt()) % servers.size();
+    int index = Math.abs(ThreadLocalRandom.current().nextInt()) % servers.size();
     return servers.get(index);
   }
 }
diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RoundRobinRuleExt.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RoundRobinRuleExt.java
index ce51039..70d4678 100644
--- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RoundRobinRuleExt.java
+++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/RoundRobinRuleExt.java
@@ -26,7 +26,7 @@
  * A round robin rule
  */
 public class RoundRobinRuleExt implements RuleExt {
-  private AtomicInteger counter = new AtomicInteger(0);
+  private final AtomicInteger counter = new AtomicInteger(0);
 
   @Override
   public ServiceCombServer choose(List<ServiceCombServer> servers, Invocation invocation) {
diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServerListFilterExt.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServerListFilterExt.java
index 9dba004..002bb3a 100644
--- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServerListFilterExt.java
+++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServerListFilterExt.java
@@ -28,8 +28,20 @@
  *  support this.
  */
 public interface ServerListFilterExt {
+  int ORDER_NORMAL = 0;
+
+  int ORDER_ISOLATION = -100;
+
+  int ORDER_ZONE_AWARE = 200;
+
+  String EMPTY_INSTANCE_PROTECTION = "servicecomb.loadbalance.filter.isolation.emptyInstanceProtectionEnabled";
+
+  String ISOLATION_FILTER_ENABLED = "servicecomb.loadbalance.filter.isolation.enabled";
+
+  String ZONE_AWARE_FILTER_ENABLED = "servicecomb.loadbalance.filter.zoneaware.enabled";
+
   default int getOrder() {
-    return 0;
+    return ORDER_NORMAL;
   }
 
   default boolean enabled() {
diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombServer.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombServer.java
index b31e759..aeb63c8 100644
--- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombServer.java
+++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombServer.java
@@ -20,6 +20,7 @@
 import java.net.URI;
 import java.net.URISyntaxException;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.servicecomb.core.Endpoint;
 import org.apache.servicecomb.core.Transport;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
@@ -90,24 +91,28 @@
     return instance;
   }
 
+  @Override
   public String toString() {
     return endpoint.getEndpoint();
   }
 
   // used in LoadBalancerContext
+  @Override
   public String getHost() {
     return endpoint.getEndpoint();
   }
 
-  // take endpoints that belongs to same instance as same server
+  @Override
   public boolean equals(Object o) {
     if (o instanceof ServiceCombServer) {
-      return this.instance.getInstanceId().equals(((ServiceCombServer) o).instance.getInstanceId());
+      return this.instance.getInstanceId().equals(((ServiceCombServer) o).instance.getInstanceId())
+          && StringUtils.equals(endpoint.getEndpoint(), ((ServiceCombServer) o).getEndpoint().getEndpoint());
     } else {
       return false;
     }
   }
 
+  @Override
   public int hashCode() {
     return this.instance.getInstanceId().hashCode();
   }
diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombServerStats.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombServerStats.java
index d867da3..140ad21 100644
--- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombServerStats.java
+++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombServerStats.java
@@ -65,7 +65,7 @@
 
   private boolean isolated = false;
 
-  private String microserviceName;
+  private final String microserviceName;
 
   public ServiceCombServerStats(String microserviceName) {
     this(microserviceName, TimeUtils.getSystemDefaultZoneClock());
diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/SessionStickinessRule.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/SessionStickinessRule.java
index a854a83..7483d9c 100644
--- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/SessionStickinessRule.java
+++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/SessionStickinessRule.java
@@ -19,6 +19,7 @@
 
 import java.util.List;
 
+import com.google.common.annotations.VisibleForTesting;
 import org.apache.servicecomb.core.Invocation;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -39,7 +40,7 @@
   private LoadBalancer loadBalancer;
 
   // use random rule as the trigger rule, to prevent consumer instance select the same producer instance.
-  private RuleExt triggerRule;
+  private final RuleExt triggerRule;
 
   private volatile ServiceCombServer lastServer = null;
 
@@ -75,7 +76,8 @@
     return lastServer;
   }
 
-  private ServiceCombServer chooseServerWhenTimeout(List<ServiceCombServer> servers, Invocation invocation) {
+  @VisibleForTesting
+  ServiceCombServer chooseServerWhenTimeout(List<ServiceCombServer> servers, Invocation invocation) {
     synchronized (lock) {
       if (isTimeOut()) {
         chooseNextServer(servers, invocation);
@@ -106,9 +108,9 @@
 
     if (stats != null && stats.getServerStats() != null && stats.getServerStats().size() > 0) {
       ServerStats serverStats = stats.getSingleServerStat(lastServer);
-      int successiveFaildCount = serverStats.getSuccessiveConnectionFailureCount();
+      int successiveFailedCount = serverStats.getSuccessiveConnectionFailureCount();
       if (Configuration.INSTANCE.getSuccessiveFailedTimes(microserviceName) > 0
-          && successiveFaildCount >= Configuration.INSTANCE.getSuccessiveFailedTimes(microserviceName)) {
+          && successiveFailedCount >= Configuration.INSTANCE.getSuccessiveFailedTimes(microserviceName)) {
         serverStats.clearSuccessiveConnectionFailureCount();
         return true;
       }
diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/WeightedResponseTimeRuleExt.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/WeightedResponseTimeRuleExt.java
index 529c0a3..7a6fe6c 100644
--- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/WeightedResponseTimeRuleExt.java
+++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/WeightedResponseTimeRuleExt.java
@@ -19,7 +19,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
 
 import org.apache.servicecomb.core.Invocation;
 
@@ -34,11 +34,9 @@
 
   private static final int RANDOM_PERCENT = 10;
 
-  private Random random = new Random();
-
   private LoadBalancer loadBalancer;
 
-  private double totalWeightsCache = 0d;
+  private double totalWeightsCache = -1d;
 
   @Override
   public void setLoadBalancer(LoadBalancer loadBalancer) {
@@ -55,7 +53,7 @@
       for (int i = 0; i < stats.size() - 1; i++) {
         weights.add(finalTotal - stats.get(i));
       }
-      double ran = random.nextDouble() * finalTotal * (servers.size() - 1);
+      double ran = ThreadLocalRandom.current().nextDouble() * finalTotal * (servers.size() - 1);
       for (int i = 0; i < weights.size(); i++) {
         ran -= weights.get(i);
         if (ran < 0) {
@@ -68,11 +66,11 @@
   }
 
   private List<Double> calculateTotalWeights(List<ServiceCombServer> servers) {
-    if (totalWeightsCache > MIN_GAP * servers.size()) {
+    if (Double.compare(totalWeightsCache, 0) < 0 || Double.compare(totalWeightsCache, MIN_GAP * servers.size()) > 0) {
       return doCalculateTotalWeights(servers);
     }
     // 10% possibilities to use weighed response rule when the normal access is very fast.
-    if (random.nextInt(RANDOM_PERCENT) == 0) {
+    if (ThreadLocalRandom.current().nextInt(RANDOM_PERCENT) == 0) {
       return doCalculateTotalWeights(servers);
     } else {
       return new ArrayList<>();
@@ -85,7 +83,8 @@
     boolean needRandom = false;
     for (ServiceCombServer server : servers) {
       ServerStats serverStats = loadBalancer.getLoadBalancerStats().getSingleServerStat(server);
-      double avgTime = serverStats.getResponseTimeAvg();
+      //getResponseTimeAvgRecent()按照时间窗口统计,时间窗口大小为1分钟;getResponseTimeAvg()一直累积
+      double avgTime = serverStats.getResponseTimeAvgRecent();
       if (!needRandom && avgTime > MIN_GAP) {
         needRandom = true;
       }
diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/event/IsolationServerEvent.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/event/IsolationServerEvent.java
index 45c7ba0..abd7396 100644
--- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/event/IsolationServerEvent.java
+++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/event/IsolationServerEvent.java
@@ -20,35 +20,35 @@
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.foundation.common.event.AlarmEvent;
 import org.apache.servicecomb.loadbalance.ServiceCombServerStats;
-import org.apache.servicecomb.loadbalance.filter.IsolationDiscoveryFilter;
+import org.apache.servicecomb.loadbalance.filterext.IsolationDiscoveryFilter;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
 
 public class IsolationServerEvent extends AlarmEvent {
 
-  private String microserviceName;
+  private final String microserviceName;
 
-  private Endpoint endpoint;
+  private final Endpoint endpoint;
 
-  private MicroserviceInstance instance;
+  private final MicroserviceInstance instance;
 
   //当前实例总请求数
-  private long currentTotalRequest;
+  private final long currentTotalRequest;
 
   //当前实例连续出错次数
-  private long currentCountinuousFailureCount;
+  private final long currentCountinuousFailureCount;
 
   //当前实例出错百分比
-  private double currentErrorPercentage;
+  private final double currentErrorPercentage;
 
-  private int minIsolationTime;
+  private final int minIsolationTime;
 
-  private long enableRequestThreshold;
+  private final long enableRequestThreshold;
 
-  private int continuousFailureThreshold;
+  private final int continuousFailureThreshold;
 
-  private int errorThresholdPercentage;
+  private final int errorThresholdPercentage;
 
-  private long singleTestTime;
+  private final long singleTestTime;
 
   public IsolationServerEvent(Invocation invocation, MicroserviceInstance instance,
       ServiceCombServerStats serverStats,
diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/exception/LoadbalanceExceptionUtils.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/exception/LoadbalanceExceptionUtils.java
index 62c2db4..3a4bde5 100644
--- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/exception/LoadbalanceExceptionUtils.java
+++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/exception/LoadbalanceExceptionUtils.java
@@ -30,7 +30,6 @@
 
   public static CseException createLoadbalanceException(String code, Throwable cause, Object... args) {
     String msg = String.format(ERROR_DESC_MGR.ensureFindValue(code), args);
-    CseException exception = new CseException(code, msg, cause);
-    return exception;
+    return new CseException(code, msg, cause);
   }
 }
diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/InstancePropertyDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/InstancePropertyDiscoveryFilter.java
index 0c1d27a..e8ce416 100644
--- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/InstancePropertyDiscoveryFilter.java
+++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/InstancePropertyDiscoveryFilter.java
@@ -59,10 +59,9 @@
     Map<String, MicroserviceInstance> instances = parent.data();
     Map<String, String> filterOptions =
         Configuration.INSTANCE.getFlowsplitFilterOptions(invocation.getMicroserviceName());
-    instances.entrySet().forEach(stringMicroserviceInstanceEntry -> {
-      MicroserviceInstance target = stringMicroserviceInstanceEntry.getValue();
+    instances.forEach((key, target) -> {
       if (allowVisit(target, filterOptions)) {
-        matchedInstance.put(stringMicroserviceInstanceEntry.getKey(), target);
+        matchedInstance.put(key, target);
       }
     });
     parent.child(MATCHED, new DiscoveryTreeNode()
diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/PriorityInstancePropertyDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/PriorityInstancePropertyDiscoveryFilter.java
index d3758cd..2a5d8a9 100644
--- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/PriorityInstancePropertyDiscoveryFilter.java
+++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/PriorityInstancePropertyDiscoveryFilter.java
@@ -93,7 +93,7 @@
         currentProperty = currentProperty.child();
       }
     }
-    LOGGER.debug("Discovery instance filter by {}", currentProperty.toString());
+    LOGGER.debug("Discovery instance filter by {}", currentProperty);
     context.putContextParameter(propertyKey, currentProperty);
 
     // stop push filter stack if property is empty
@@ -116,7 +116,7 @@
     return new InstancePropertyDiscoveryFilter().getOrder() + 1;
   }
 
-  class PriorityInstanceProperty {
+  static class PriorityInstanceProperty {
     private static final int MAX_LENGTH = 10000;
 
     private static final String SEPARATOR = ".";
diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/ZoneAwareDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/ZoneAwareDiscoveryFilter.java
deleted file mode 100644
index c444467..0000000
--- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/ZoneAwareDiscoveryFilter.java
+++ /dev/null
@@ -1,134 +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.servicecomb.loadbalance.filter;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException;
-import org.apache.servicecomb.serviceregistry.RegistryUtils;
-import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
-import org.apache.servicecomb.serviceregistry.discovery.AbstractDiscoveryFilter;
-import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext;
-import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTreeNode;
-
-import com.netflix.config.DynamicPropertyFactory;
-
-
-public class ZoneAwareDiscoveryFilter extends AbstractDiscoveryFilter {
-  public static final String KEY_ZONE_AWARE_STEP = "_KEY_ZONE_AWARE_STEP";
-
-  private static final String GROUP_RegionAndAZMatch = "instancesRegionAndAZMatch";
-
-  private static final String GROUP_InstancesAZMatch = "instancesAZMatch";
-
-  private static final String GROUP_InstancesNoMatch = "instancesNoMatch";
-
-  public static final String GROUP_Instances_All = "instancesAll";
-
-  @Override
-  public int getOrder() {
-    return 300;
-  }
-
-  @Override
-  public boolean enabled() {
-    return DynamicPropertyFactory.getInstance()
-        .getBooleanProperty("servicecomb.loadbalance.filter.zoneaware.enabled", true).get();
-  }
-
-  @Override
-  public boolean isGroupingFilter() {
-    return true;
-  }
-
-  @Override
-  protected void init(DiscoveryContext context, DiscoveryTreeNode parent) {
-    MicroserviceInstance myself = RegistryUtils.getMicroserviceInstance();
-
-    Map<String, MicroserviceInstance> instancesRegionAndAZMatch = new HashMap<>();
-    Map<String, MicroserviceInstance> instancesAZMatch = new HashMap<>();
-    Map<String, MicroserviceInstance> instancesNoMatch = new HashMap<>();
-    Map<String, MicroserviceInstance> instances = parent.data();
-    instances.entrySet().forEach(stringMicroserviceInstanceEntry -> {
-      String id = stringMicroserviceInstanceEntry.getKey();
-      MicroserviceInstance target = stringMicroserviceInstanceEntry.getValue();
-      if (regionAndAZMatch(myself, target)) {
-        instancesRegionAndAZMatch.put(id, target);
-      } else if (regionMatch(myself, target)) {
-        instancesAZMatch.put(id, target);
-      } else {
-        instancesNoMatch.put(id, target);
-      }
-    });
-    Map<String, DiscoveryTreeNode> children = new HashMap<>();
-    children.put(GROUP_RegionAndAZMatch, new DiscoveryTreeNode()
-        .subName(parent, GROUP_RegionAndAZMatch)
-        .data(instancesRegionAndAZMatch));
-    children.put(GROUP_InstancesAZMatch, new DiscoveryTreeNode()
-        .subName(parent, GROUP_InstancesAZMatch)
-        .data(instancesAZMatch));
-    children.put(GROUP_InstancesNoMatch, new DiscoveryTreeNode()
-        .subName(parent, GROUP_InstancesNoMatch)
-        .data(instancesNoMatch));
-    children.put(GROUP_Instances_All, new DiscoveryTreeNode()
-        .subName(parent, GROUP_Instances_All)
-        .data(instances));
-    parent.children(children);
-  }
-
-  @Override
-  protected String findChildName(DiscoveryContext context, DiscoveryTreeNode parent) {
-    String key = context.getContextParameter(KEY_ZONE_AWARE_STEP);
-    if (key == null) {
-      key = GROUP_RegionAndAZMatch;
-      context.pushRerunFilter();
-    } else if (GROUP_RegionAndAZMatch.equals(key)) {
-      key = GROUP_InstancesAZMatch;
-      context.pushRerunFilter();
-    } else if (GROUP_InstancesAZMatch.equals(key)) {
-      key = GROUP_InstancesNoMatch;
-      context.pushRerunFilter();
-    } else if (GROUP_InstancesNoMatch.equals(key)) {
-      key = GROUP_Instances_All;
-    } else {
-      throw new ServiceCombException("not possible happen, maybe a bug.");
-    }
-    context.putContextParameter(KEY_ZONE_AWARE_STEP, key);
-    return key;
-  }
-
-  private boolean regionAndAZMatch(MicroserviceInstance myself, MicroserviceInstance target) {
-    if (myself.getDataCenterInfo() == null) {
-      // when instance have no datacenter info, it will match all other datacenters
-      return true;
-    }
-    if (target.getDataCenterInfo() != null) {
-      return myself.getDataCenterInfo().getRegion().equals(target.getDataCenterInfo().getRegion()) &&
-          myself.getDataCenterInfo().getAvailableZone().equals(target.getDataCenterInfo().getAvailableZone());
-    }
-    return false;
-  }
-
-  private boolean regionMatch(MicroserviceInstance myself, MicroserviceInstance target) {
-    if (target.getDataCenterInfo() != null) {
-      return myself.getDataCenterInfo().getRegion().equals(target.getDataCenterInfo().getRegion());
-    }
-    return false;
-  }
-}
diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/IsolationDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/IsolationDiscoveryFilter.java
similarity index 66%
rename from handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/IsolationDiscoveryFilter.java
rename to handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/IsolationDiscoveryFilter.java
index 7919c1d..8a3f152 100644
--- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filter/IsolationDiscoveryFilter.java
+++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/IsolationDiscoveryFilter.java
@@ -15,23 +15,20 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.loadbalance.filter;
+package org.apache.servicecomb.loadbalance.filterext;
 
-import java.util.HashMap;
-import java.util.Map;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.foundation.common.event.AlarmEvent.Type;
 import org.apache.servicecomb.foundation.common.event.EventManager;
 import org.apache.servicecomb.loadbalance.Configuration;
+import org.apache.servicecomb.loadbalance.ServerListFilterExt;
 import org.apache.servicecomb.loadbalance.ServiceCombLoadBalancerStats;
 import org.apache.servicecomb.loadbalance.ServiceCombServer;
 import org.apache.servicecomb.loadbalance.ServiceCombServerStats;
 import org.apache.servicecomb.loadbalance.event.IsolationServerEvent;
-import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
-import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext;
-import org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter;
-import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTreeNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -42,18 +39,16 @@
 /**
  * Isolate instances by error metrics
  */
-public class IsolationDiscoveryFilter implements DiscoveryFilter {
-
-  public static final String TRYING_INSTANCES_EXISTING = "scb-hasTryingInstances";
+public class IsolationDiscoveryFilter implements ServerListFilterExt {
 
   private static final Logger LOGGER = LoggerFactory.getLogger(IsolationDiscoveryFilter.class);
 
-  private static final String EMPTY_INSTANCE_PROTECTION = "servicecomb.loadbalance.filter.isolation.emptyInstanceProtectionEnabled";
-
   private final DynamicBooleanProperty emptyProtection = DynamicPropertyFactory.getInstance()
       .getBooleanProperty(EMPTY_INSTANCE_PROTECTION, false);
 
-  public class Settings {
+  private final EventBus eventBus = EventManager.getEventBus();
+
+  public static class Settings {
     public int errorThresholdPercentage;
 
     public long singleTestTime;
@@ -65,11 +60,9 @@
     public int minIsolationTime; // to avoid isolation recover too fast due to no concurrent control in concurrent scenario
   }
 
-  public EventBus eventBus = EventManager.getEventBus();
-
   @Override
   public int getOrder() {
-    return 500;
+    return ORDER_ISOLATION;
   }
 
   public IsolationDiscoveryFilter() {
@@ -82,40 +75,25 @@
   @Override
   public boolean enabled() {
     return DynamicPropertyFactory.getInstance()
-        .getBooleanProperty("servicecomb.loadbalance.filter.isolation.enabled", true).get();
+        .getBooleanProperty(ISOLATION_FILTER_ENABLED, true)
+        .get();
   }
 
   @Override
-  public boolean isGroupingFilter() {
-    return false;
-  }
-
-  @Override
-  public DiscoveryTreeNode discovery(DiscoveryContext context, DiscoveryTreeNode parent) {
-    Map<String, MicroserviceInstance> instances = parent.data();
-    Invocation invocation = context.getInputParameters();
-    if (!Configuration.INSTANCE.isIsolationFilterOpen(invocation.getMicroserviceName())) {
-      return parent;
-    }
-
-    Map<String, MicroserviceInstance> filteredServers = new HashMap<>();
-    instances.entrySet().forEach(stringMicroserviceInstanceEntry -> {
-      MicroserviceInstance instance = stringMicroserviceInstanceEntry.getValue();
-      if (allowVisit(invocation, instance)) {
-        filteredServers.put(stringMicroserviceInstanceEntry.getKey(), instance);
+  public List<ServiceCombServer> getFilteredListOfServers(List<ServiceCombServer> servers,
+      Invocation invocation) {
+    List<ServiceCombServer> filteredServers = new ArrayList<>();
+    Settings settings = createSettings(invocation);
+    servers.forEach((server) -> {
+      if (allowVisit(invocation, server, settings)) {
+        filteredServers.add(server);
       }
     });
-
-    DiscoveryTreeNode child = parent.children().computeIfAbsent("filterred", etn -> new DiscoveryTreeNode());
-    if (ZoneAwareDiscoveryFilter.GROUP_Instances_All
-        .equals(context.getContextParameter(ZoneAwareDiscoveryFilter.KEY_ZONE_AWARE_STEP)) && filteredServers.isEmpty()
-        && emptyProtection.get()) {
+    if (filteredServers.isEmpty() && emptyProtection.get()) {
       LOGGER.warn("All servers have been isolated, allow one of them based on load balance rule.");
-      child.data(instances);
-    } else {
-      child.data(filteredServers);
+      return servers;
     }
-    return child;
+    return filteredServers;
   }
 
   private Settings createSettings(Invocation invocation) {
@@ -132,14 +110,8 @@
     return settings;
   }
 
-  private boolean allowVisit(Invocation invocation, MicroserviceInstance instance) {
-    ServiceCombServer server = ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServer(instance);
-    if (server == null) {
-      // first time accessed.
-      return true;
-    }
+  private boolean allowVisit(Invocation invocation, ServiceCombServer server, Settings settings) {
     ServiceCombServerStats serverStats = ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(server);
-    Settings settings = createSettings(invocation);
     if (!checkThresholdAllowed(settings, serverStats)) {
       if (serverStats.isIsolated()
           && (System.currentTimeMillis() - serverStats.getLastVisitTime()) > settings.singleTestTime) {
@@ -149,10 +121,11 @@
         // checkThresholdAllowed is not concurrent control, may print several logs/events in current access.
         serverStats.markIsolated(true);
         eventBus.post(
-            new IsolationServerEvent(invocation, instance, serverStats,
+            new IsolationServerEvent(invocation, server.getInstance(), serverStats,
                 settings, Type.OPEN, server.getEndpoint()));
-        LOGGER.warn("Isolate service {}'s instance {}.", invocation.getMicroserviceName(),
-            instance.getInstanceId());
+        LOGGER.warn("Isolate service {}'s instance {}.",
+            invocation.getMicroserviceName(),
+            server.getInstance().getInstanceId());
       }
       return false;
     }
@@ -163,10 +136,11 @@
         return false;
       }
       serverStats.markIsolated(false);
-      eventBus.post(new IsolationServerEvent(invocation, instance, serverStats,
+      eventBus.post(new IsolationServerEvent(invocation, server.getInstance(), serverStats,
           settings, Type.CLOSE, server.getEndpoint()));
-      LOGGER.warn("Recover service {}'s instance {} from isolation.", invocation.getMicroserviceName(),
-          instance.getInstanceId());
+      LOGGER.warn("Recover service {}'s instance {} from isolation.",
+          invocation.getMicroserviceName(),
+          server.getInstance().getInstanceId());
     }
     return true;
   }
diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/ZoneAwareDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/ZoneAwareDiscoveryFilter.java
new file mode 100644
index 0000000..08fa092
--- /dev/null
+++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/ZoneAwareDiscoveryFilter.java
@@ -0,0 +1,88 @@
+/*
+ * 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.servicecomb.loadbalance.filterext;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.loadbalance.ServerListFilterExt;
+import org.apache.servicecomb.loadbalance.ServiceCombServer;
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
+import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+
+import com.netflix.config.DynamicPropertyFactory;
+
+public class ZoneAwareDiscoveryFilter implements ServerListFilterExt {
+
+  @Override
+  public int getOrder() {
+    return ORDER_ZONE_AWARE;
+  }
+
+  @Override
+  public boolean enabled() {
+    return DynamicPropertyFactory.getInstance()
+        .getBooleanProperty(ZONE_AWARE_FILTER_ENABLED, true)
+        .get();
+  }
+
+  @Override
+  public List<ServiceCombServer> getFilteredListOfServers(List<ServiceCombServer> servers,
+      Invocation invocation) {
+    MicroserviceInstance myself = RegistryUtils.getMicroserviceInstance();
+
+    List<ServiceCombServer> instancesRegionAndAZMatch = new ArrayList<>();
+    List<ServiceCombServer> instancesAZMatch = new ArrayList<>();
+    List<ServiceCombServer> instancesNoMatch = new ArrayList<>();
+    servers.forEach((server) -> {
+      if (regionAndAZMatch(myself, server.getInstance())) {
+        instancesRegionAndAZMatch.add(server);
+      } else if (regionMatch(myself, server.getInstance())) {
+        instancesAZMatch.add(server);
+      } else {
+        instancesNoMatch.add(server);
+      }
+    });
+    if (!instancesRegionAndAZMatch.isEmpty()) {
+      return instancesRegionAndAZMatch;
+    } else if (!instancesAZMatch.isEmpty()) {
+      return instancesAZMatch;
+    }
+    return instancesNoMatch;
+  }
+
+  private boolean regionAndAZMatch(MicroserviceInstance myself, MicroserviceInstance target) {
+    if (myself == null || myself.getDataCenterInfo() == null) {
+      // when instance have no datacenter info, it will match all other datacenters
+      return true;
+    }
+    if (target.getDataCenterInfo() != null) {
+      return myself.getDataCenterInfo().getRegion().equals(target.getDataCenterInfo().getRegion()) &&
+          myself.getDataCenterInfo().getAvailableZone().equals(target.getDataCenterInfo().getAvailableZone());
+    }
+    return false;
+  }
+
+  private boolean regionMatch(MicroserviceInstance myself, MicroserviceInstance target) {
+    if (target.getDataCenterInfo() != null) {
+      return myself.getDataCenterInfo().getRegion().equals(target.getDataCenterInfo().getRegion());
+    }
+    return false;
+  }
+}
diff --git a/handlers/handler-loadbalance/src/main/resources/META-INF/services/org.apache.servicecomb.loadbalance.ServerListFilterExt b/handlers/handler-loadbalance/src/main/resources/META-INF/services/org.apache.servicecomb.loadbalance.ServerListFilterExt
new file mode 100644
index 0000000..9e8a084
--- /dev/null
+++ b/handlers/handler-loadbalance/src/main/resources/META-INF/services/org.apache.servicecomb.loadbalance.ServerListFilterExt
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+org.apache.servicecomb.loadbalance.filterext.IsolationDiscoveryFilter
+org.apache.servicecomb.loadbalance.filterext.ZoneAwareDiscoveryFilter
\ No newline at end of file
diff --git a/handlers/handler-loadbalance/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter b/handlers/handler-loadbalance/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter
index 3a22561..445ab0e 100644
--- a/handlers/handler-loadbalance/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter
+++ b/handlers/handler-loadbalance/src/main/resources/META-INF/services/org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter
@@ -15,7 +15,5 @@
 # limitations under the License.
 #
 
-org.apache.servicecomb.loadbalance.filter.ZoneAwareDiscoveryFilter
-org.apache.servicecomb.loadbalance.filter.IsolationDiscoveryFilter
 org.apache.servicecomb.loadbalance.filter.InstancePropertyDiscoveryFilter
 org.apache.servicecomb.loadbalance.filter.PriorityInstancePropertyDiscoveryFilter
\ No newline at end of file
diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceHandler2.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceHandler2.java
index fd3effe..bf8a5df 100644
--- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceHandler2.java
+++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceHandler2.java
@@ -41,9 +41,9 @@
 import org.apache.servicecomb.foundation.common.event.EventManager;
 import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
 import org.apache.servicecomb.loadbalance.event.IsolationServerEvent;
-import org.apache.servicecomb.loadbalance.filter.IsolationDiscoveryFilter;
+import org.apache.servicecomb.loadbalance.filterext.IsolationDiscoveryFilter;
 import org.apache.servicecomb.loadbalance.filter.ServerDiscoveryFilter;
-import org.apache.servicecomb.loadbalance.filter.ZoneAwareDiscoveryFilter;
+import org.apache.servicecomb.loadbalance.filterext.ZoneAwareDiscoveryFilter;
 import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.ServiceRegistry;
 import org.apache.servicecomb.serviceregistry.api.registry.DataCenterInfo;
@@ -532,8 +532,6 @@
     ServiceCombServer server = null;
 
     DiscoveryTree discoveryTree = new DiscoveryTree();
-    discoveryTree.addFilter(new IsolationDiscoveryFilter());
-    discoveryTree.addFilter(new ZoneAwareDiscoveryFilter());
     discoveryTree.addFilter(new ServerDiscoveryFilter());
     discoveryTree.sort();
     handler = new LoadbalanceHandler(discoveryTree);
@@ -676,8 +674,6 @@
     ServiceCombServer server = null;
 
     DiscoveryTree discoveryTree = new DiscoveryTree();
-    discoveryTree.addFilter(new IsolationDiscoveryFilter());
-    discoveryTree.addFilter(new ZoneAwareDiscoveryFilter());
     discoveryTree.addFilter(new ServerDiscoveryFilter());
     discoveryTree.sort();
     handler = new LoadbalanceHandler(discoveryTree);
@@ -855,12 +851,13 @@
         });
 
     Assert.assertTrue(ServiceCombServerStats.applyForTryingChance(invocation));
-    invocation.addLocalContext(IsolationDiscoveryFilter.TRYING_INSTANCES_EXISTING, true);
+    ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.isolation.enabled", "false");
     try {
       handler.handle(invocation, (response) -> Assert.assertEquals("OK", response.getResult()));
     } catch (Exception e) {
       Assert.fail("unexpected exception " + e.getMessage());
     }
+    ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.isolation.enabled", "true");
     Assert.assertEquals("rest://127.0.0.1:8080", invocation.getEndpoint().getEndpoint());
     Assert.assertTrue(serviceCombServerStats.isIsolated());
     Assert.assertEquals(0, serviceCombServerStats.getContinuousFailureCount());
@@ -912,12 +909,13 @@
         });
 
     Assert.assertTrue(ServiceCombServerStats.applyForTryingChance(invocation));
-    invocation.addLocalContext(IsolationDiscoveryFilter.TRYING_INSTANCES_EXISTING, true);
+    ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.isolation.enabled", "false");
     try {
       handler.handle(invocation, (response) -> Assert.assertEquals("OK", response.getResult()));
     } catch (Exception e) {
       Assert.fail("unexpected exception " + e.getMessage());
     }
+    ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.isolation.enabled", "true");
     Assert.assertEquals("rest://127.0.0.1:8081", invocation.getEndpoint().getEndpoint());
     Assert.assertFalse(stats0.isIsolated());
     Assert.assertEquals(1, stats0.getContinuousFailureCount());
diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestWeightedResponseTimeRuleExt.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestWeightedResponseTimeRuleExt.java
index 10dfed3..065f7ba 100644
--- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestWeightedResponseTimeRuleExt.java
+++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestWeightedResponseTimeRuleExt.java
@@ -53,30 +53,52 @@
   }
 
   @Test
-  public void testWeighed() {
+  public void testWeighed() throws InterruptedException {
     WeightedResponseTimeRuleExt rule = new WeightedResponseTimeRuleExt();
     LoadBalancer loadBalancer = new LoadBalancer(rule, "testService");
     List<ServiceCombServer> servers = new ArrayList<>();
     Invocation invocation = Mockito.mock(Invocation.class);
-    for (int i = 0; i < 2; i++) {
-      ServiceCombServer server = Mockito.mock(ServiceCombServer.class);
-      Mockito.when(server.toString()).thenReturn("server " + i);
-      servers.add(server);
-      loadBalancer.getLoadBalancerStats().noteResponseTime(server, 20 * Math.pow(4, i + 1));
-    }
 
-    AtomicInteger server1 = new AtomicInteger(0);
-    AtomicInteger server2 = new AtomicInteger(0);
+    ServiceCombServer server1 = Mockito.mock(ServiceCombServer.class);
+    Mockito.when(server1.toString()).thenReturn("server " + 0);
+    servers.add(server1);
+    ServiceCombServer server2 = Mockito.mock(ServiceCombServer.class);
+    Mockito.when(server2.toString()).thenReturn("server " + 1);
+    servers.add(server2);
+
+    AtomicInteger serverCounter1 = new AtomicInteger(0);
+    AtomicInteger serverCounter2 = new AtomicInteger(0);
     for (int i = 0; i < 2000; i++) {
+      loadBalancer.getLoadBalancerStats().noteResponseTime(server1, 20);
+      loadBalancer.getLoadBalancerStats().noteResponseTime(server2, 400);
+      Thread.sleep(1);
       if (rule.choose(servers, invocation).toString().equals("server 0")) {
-        server1.incrementAndGet();
+        serverCounter1.incrementAndGet();
       } else {
-        server2.incrementAndGet();
+        serverCounter2.incrementAndGet();
       }
     }
-    double percent = (double) server1.get() / (server2.get() + server1.get());
+    double percent = (double) serverCounter1.get() / (serverCounter2.get() + serverCounter1.get());
     System.out.println("percent" + percent);
-    Assert.assertEquals("actually percent: " + percent, 0.70d < percent, percent < 0.90d);
+    Assert.assertTrue(percent > 0.60d);
+    Assert.assertTrue(percent < 0.90d);
+    serverCounter1.set(0);
+    serverCounter2.set(0);
+
+    Thread.sleep(1000);
+    for (int i = 0; i < 2000; i++) {
+      loadBalancer.getLoadBalancerStats().noteResponseTime(server1, 20);
+      loadBalancer.getLoadBalancerStats().noteResponseTime(server2, 20);
+      Thread.sleep(1);
+      if (rule.choose(servers, invocation).toString().equals("server 0")) {
+        serverCounter1.incrementAndGet();
+      } else {
+        serverCounter2.incrementAndGet();
+      }
+    }
+    percent = (double) serverCounter1.get() / (serverCounter2.get() + serverCounter1.get());
+    System.out.println("percent" + percent);
+    Assert.assertEquals(0.50d, percent, 0.2);
   }
 
   @Test
@@ -99,7 +121,7 @@
     }
     long taken = System.currentTimeMillis() - begin;
     System.out.println("taken " + taken);
-    Assert.assertEquals("actually taken: " + taken, taken < 1000 * 5, true); // 5 * times make slow machine happy
+    Assert.assertTrue(taken < 1000 * 5); // 5 * times make slow machine happy
   }
 
   @Test
@@ -121,6 +143,6 @@
     }
     long taken = System.currentTimeMillis() - begin;
     System.out.println("taken " + taken);
-    Assert.assertEquals("actually taken: " + taken, taken < 200 * 5, true); // 5 * times make slow machine happy
+    Assert.assertTrue(taken < 200 * 5); // 5 * times make slow machine happy
   }
 }
diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/IsolationDiscoveryFilterTest.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/IsolationDiscoveryFilterTest.java
index 0e16acb..8c8e1d4 100644
--- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/IsolationDiscoveryFilterTest.java
+++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/IsolationDiscoveryFilterTest.java
@@ -17,9 +17,9 @@
 
 package org.apache.servicecomb.loadbalance.filter;
 
+import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.List;
 
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.core.Transport;
@@ -28,11 +28,9 @@
 import org.apache.servicecomb.loadbalance.ServiceCombServer;
 import org.apache.servicecomb.loadbalance.ServiceCombServerStats;
 import org.apache.servicecomb.loadbalance.TestServiceCombServerStats;
+import org.apache.servicecomb.loadbalance.filterext.IsolationDiscoveryFilter;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
 import org.apache.servicecomb.serviceregistry.cache.CacheEndpoint;
-import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext;
-import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTreeNode;
-import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -43,15 +41,10 @@
 import mockit.Mocked;
 
 public class IsolationDiscoveryFilterTest {
-
-  private DiscoveryContext discoveryContext;
-
-  private DiscoveryTreeNode discoveryTreeNode;
-
-  private Map<String, MicroserviceInstance> data;
-
   private IsolationDiscoveryFilter filter;
 
+  private List<ServiceCombServer> servers;
+
   @Mocked
   private Transport transport = Mockito.mock(Transport.class);
 
@@ -64,22 +57,18 @@
 
   @Before
   public void before() {
-    discoveryContext = new DiscoveryContext();
-    discoveryContext.setInputParameters(invocation);
-    discoveryTreeNode = new DiscoveryTreeNode();
     Mockito.doAnswer(a -> a.getArguments()[0]).when(transport).parseAddress(Mockito.anyString());
-    data = new HashMap<>();
+    servers = new ArrayList<>();
     for (int i = 0; i < 3; ++i) {
       MicroserviceInstance instance = new MicroserviceInstance();
       instance.setInstanceId("i" + i);
       String endpoint = "rest://127.0.0.1:" + i;
       instance.setEndpoints(Collections.singletonList(endpoint));
-      data.put(instance.getInstanceId(), instance);
       ServiceCombServer serviceCombServer = new ServiceCombServer(null, transport,
           new CacheEndpoint(endpoint, instance));
+      servers.add(serviceCombServer);
       ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer);
     }
-    discoveryTreeNode.data(data);
 
     filter = new IsolationDiscoveryFilter();
     TestServiceCombServerStats.releaseTryingChance();
@@ -93,43 +82,40 @@
 
   @Test
   public void discovery_no_instance_reach_error_threshold() {
-    DiscoveryTreeNode childNode = filter.discovery(discoveryContext, discoveryTreeNode);
+    List<ServiceCombServer> filteredServers = filter.getFilteredListOfServers(servers, invocation);
 
-    Map<String, MicroserviceInstance> childNodeData = childNode.data();
-    Assert.assertThat(childNodeData.keySet(), Matchers.containsInAnyOrder("i0", "i1", "i2"));
-    Assert.assertEquals(data.get("i0"), childNodeData.get("i0"));
-    Assert.assertEquals(data.get("i1"), childNodeData.get("i1"));
-    Assert.assertEquals(data.get("i2"), childNodeData.get("i2"));
+    Assert.assertEquals(filteredServers.size(), 3);
+    Assert.assertEquals(servers.get(0), filteredServers.get(0));
+    Assert.assertEquals(servers.get(1), filteredServers.get(1));
+    Assert.assertEquals(servers.get(2), filteredServers.get(2));
   }
 
   @Test
   public void discovery_isolate_error_instance() {
-    ServiceCombServer server0 = ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServer(data.get("i0"));
+    ServiceCombServer server0 = servers.get(0);
     for (int i = 0; i < 4; ++i) {
       ServiceCombLoadBalancerStats.INSTANCE.markFailure(server0);
     }
-    DiscoveryTreeNode childNode = filter.discovery(discoveryContext, discoveryTreeNode);
-    Map<String, MicroserviceInstance> childNodeData = childNode.data();
-    Assert.assertThat(childNodeData.keySet(), Matchers.containsInAnyOrder("i0", "i1", "i2"));
-    Assert.assertEquals(data.get("i0"), childNodeData.get("i0"));
-    Assert.assertEquals(data.get("i1"), childNodeData.get("i1"));
-    Assert.assertEquals(data.get("i2"), childNodeData.get("i2"));
+    List<ServiceCombServer> filteredServers = filter.getFilteredListOfServers(servers, invocation);
+    Assert.assertEquals(filteredServers.size(), 3);
+    Assert.assertEquals(servers.get(0), filteredServers.get(0));
+    Assert.assertEquals(servers.get(1), filteredServers.get(1));
+    Assert.assertEquals(servers.get(2), filteredServers.get(2));
 
     // by default 5 times continuous failure will cause isolation
     ServiceCombLoadBalancerStats.INSTANCE.markFailure(server0);
     Assert.assertFalse(ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(server0).isIsolated());
 
-    childNode = filter.discovery(discoveryContext, discoveryTreeNode);
-    childNodeData = childNode.data();
-    Assert.assertThat(childNodeData.keySet(), Matchers.containsInAnyOrder("i1", "i2"));
-    Assert.assertEquals(data.get("i1"), childNodeData.get("i1"));
-    Assert.assertEquals(data.get("i2"), childNodeData.get("i2"));
+    filteredServers = filter.getFilteredListOfServers(servers, invocation);
+    Assert.assertEquals(filteredServers.size(), 2);
+    Assert.assertEquals(servers.get(1), filteredServers.get(0));
+    Assert.assertEquals(servers.get(2), filteredServers.get(1));
     Assert.assertTrue(ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(server0).isIsolated());
   }
 
   @Test
   public void discovery_try_isolated_instance_after_singleTestTime() {
-    ServiceCombServer server0 = ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServer(data.get("i0"));
+    ServiceCombServer server0 = servers.get(0);
     ServiceCombServerStats serviceCombServerStats = ServiceCombLoadBalancerStats.INSTANCE
         .getServiceCombServerStats(server0);
     for (int i = 0; i < 5; ++i) {
@@ -140,12 +126,11 @@
 
     Assert.assertTrue(ServiceCombServerStats.isolatedServerCanTry());
     Assert.assertNull(TestServiceCombServerStats.getTryingIsolatedServerInvocation());
-    DiscoveryTreeNode childNode = filter.discovery(discoveryContext, discoveryTreeNode);
-    Map<String, MicroserviceInstance> childNodeData = childNode.data();
-    Assert.assertThat(childNodeData.keySet(), Matchers.containsInAnyOrder("i0", "i1", "i2"));
-    Assert.assertEquals(data.get("i0"), childNodeData.get("i0"));
-    Assert.assertEquals(data.get("i1"), childNodeData.get("i1"));
-    Assert.assertEquals(data.get("i2"), childNodeData.get("i2"));
+    List<ServiceCombServer> filteredServers = filter.getFilteredListOfServers(servers, invocation);
+    Assert.assertEquals(filteredServers.size(), 3);
+    Assert.assertEquals(servers.get(0), filteredServers.get(0));
+    Assert.assertEquals(servers.get(1), filteredServers.get(1));
+    Assert.assertEquals(servers.get(2), filteredServers.get(2));
     Assert.assertTrue(serviceCombServerStats.isIsolated());
     Assert.assertFalse(ServiceCombServerStats.isolatedServerCanTry());
     Assert.assertSame(invocation, TestServiceCombServerStats.getTryingIsolatedServerInvocation());
@@ -153,7 +138,7 @@
 
   @Test
   public void discovery_not_try_isolated_instance_concurrently() {
-    ServiceCombServer server0 = ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServer(data.get("i0"));
+    ServiceCombServer server0 = servers.get(0);
     ServiceCombServerStats serviceCombServerStats = ServiceCombLoadBalancerStats.INSTANCE
         .getServiceCombServerStats(server0);
     for (int i = 0; i < 5; ++i) {
@@ -165,32 +150,28 @@
     Assert.assertTrue(ServiceCombServerStats.isolatedServerCanTry());
 
     // The first invocation can occupy the trying chance
-    DiscoveryTreeNode childNode = filter.discovery(discoveryContext, discoveryTreeNode);
-    Map<String, MicroserviceInstance> childNodeData = childNode.data();
-    Assert.assertThat(childNodeData.keySet(), Matchers.containsInAnyOrder("i0", "i1", "i2"));
-    Assert.assertEquals(data.get("i0"), childNodeData.get("i0"));
-    Assert.assertEquals(data.get("i1"), childNodeData.get("i1"));
-    Assert.assertEquals(data.get("i2"), childNodeData.get("i2"));
+    List<ServiceCombServer> filteredServers = filter.getFilteredListOfServers(servers, invocation);
+    Assert.assertEquals(filteredServers.size(), 3);
+    Assert.assertEquals(servers.get(0), filteredServers.get(0));
+    Assert.assertEquals(servers.get(1), filteredServers.get(1));
+    Assert.assertEquals(servers.get(2), filteredServers.get(2));
     Assert.assertFalse(ServiceCombServerStats.isolatedServerCanTry());
 
     // Other invocation cannot get trying chance concurrently
-    childNode = filter.discovery(discoveryContext, discoveryTreeNode);
-    childNodeData = childNode.data();
-    Assert.assertThat(childNodeData.keySet(), Matchers.containsInAnyOrder("i1", "i2"));
-    Assert.assertEquals(data.get("i1"), childNodeData.get("i1"));
-    Assert.assertEquals(data.get("i2"), childNodeData.get("i2"));
+    filteredServers = filter.getFilteredListOfServers(servers, invocation);
+    Assert.assertEquals(filteredServers.size(), 2);
+    Assert.assertEquals(servers.get(1), filteredServers.get(0));
+    Assert.assertEquals(servers.get(2), filteredServers.get(1));
 
     ServiceCombServerStats
         .checkAndReleaseTryingChance(invocation); // after the first invocation releases the trying chance
 
     // Other invocation can get the trying chance
-    childNode = filter.discovery(discoveryContext, discoveryTreeNode);
-    childNodeData = childNode.data();
-    Assert.assertThat(childNodeData.keySet(), Matchers.containsInAnyOrder("i0", "i1", "i2"));
-    Assert.assertEquals(data.get("i0"), childNodeData.get("i0"));
-    Assert.assertEquals(data.get("i1"), childNodeData.get("i1"));
-    Assert.assertEquals(data.get("i2"), childNodeData.get("i2"));
-    Assert.assertFalse(ServiceCombServerStats.isolatedServerCanTry());
+    filteredServers = filter.getFilteredListOfServers(servers, invocation);
+    Assert.assertEquals(filteredServers.size(), 3);
+    Assert.assertEquals(servers.get(0), filteredServers.get(0));
+    Assert.assertEquals(servers.get(1), filteredServers.get(1));
+    Assert.assertEquals(servers.get(2), filteredServers.get(2));
   }
 
   private ServiceCombServerStats letIsolatedInstancePassSingleTestTime(ServiceCombServerStats serviceCombServerStats) {
@@ -203,31 +184,29 @@
 
   @Test
   public void discovery_keep_minIsolationTime() {
-    ServiceCombServer server0 = ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServer(data.get("i0"));
+    ServiceCombServer server0 = servers.get(0);
     ServiceCombLoadBalancerStats.INSTANCE.markIsolated(server0, true);
     ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server0);
 
-    DiscoveryTreeNode childNode = filter.discovery(discoveryContext, discoveryTreeNode);
-    Map<String, MicroserviceInstance> childNodeData = childNode.data();
-    Assert.assertThat(childNodeData.keySet(), Matchers.containsInAnyOrder("i1", "i2"));
-    Assert.assertEquals(data.get("i1"), childNodeData.get("i1"));
-    Assert.assertEquals(data.get("i2"), childNodeData.get("i2"));
+    List<ServiceCombServer> filteredServers = filter.getFilteredListOfServers(servers, invocation);
+    Assert.assertEquals(filteredServers.size(), 2);
+    Assert.assertEquals(servers.get(1), filteredServers.get(0));
+    Assert.assertEquals(servers.get(2), filteredServers.get(1));
 
     ServiceCombServerStats serviceCombServerStats = ServiceCombLoadBalancerStats.INSTANCE
         .getServiceCombServerStats(server0);
     Deencapsulation.setField(serviceCombServerStats, "isolatedTime",
         System.currentTimeMillis() - Configuration.INSTANCE.getMinIsolationTime(invocation.getMicroserviceName()) - 1);
-    childNode = filter.discovery(discoveryContext, discoveryTreeNode);
-    childNodeData = childNode.data();
-    Assert.assertThat(childNodeData.keySet(), Matchers.containsInAnyOrder("i0", "i1", "i2"));
-    Assert.assertEquals(data.get("i0"), childNodeData.get("i0"));
-    Assert.assertEquals(data.get("i1"), childNodeData.get("i1"));
-    Assert.assertEquals(data.get("i2"), childNodeData.get("i2"));
+    filteredServers = filter.getFilteredListOfServers(servers, invocation);
+    Assert.assertEquals(filteredServers.size(), 3);
+    Assert.assertEquals(servers.get(0), filteredServers.get(0));
+    Assert.assertEquals(servers.get(1), filteredServers.get(1));
+    Assert.assertEquals(servers.get(2), filteredServers.get(2));
   }
 
   @Test
   public void discovery_recover_instance() {
-    ServiceCombServer server0 = ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServer(data.get("i0"));
+    ServiceCombServer server0 = servers.get(0);
     ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server0);
     ServiceCombServerStats serviceCombServerStats = ServiceCombLoadBalancerStats.INSTANCE
         .getServiceCombServerStats(server0);
@@ -236,12 +215,10 @@
     Deencapsulation.setField(serviceCombServerStats, "isolatedTime",
         System.currentTimeMillis() - Configuration.INSTANCE.getMinIsolationTime(invocation.getMicroserviceName()) - 1);
 
-    DiscoveryTreeNode childNode = filter.discovery(discoveryContext, discoveryTreeNode);
-    Map<String, MicroserviceInstance> childNodeData = childNode.data();
-    Assert.assertThat(childNodeData.keySet(), Matchers.containsInAnyOrder("i0", "i1", "i2"));
-    Assert.assertEquals(data.get("i0"), childNodeData.get("i0"));
-    Assert.assertEquals(data.get("i1"), childNodeData.get("i1"));
-    Assert.assertEquals(data.get("i2"), childNodeData.get("i2"));
-    Assert.assertFalse(ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(server0).isIsolated());
+    List<ServiceCombServer> filteredServers = filter.getFilteredListOfServers(servers, invocation);
+    Assert.assertEquals(filteredServers.size(), 3);
+    Assert.assertEquals(servers.get(0), filteredServers.get(0));
+    Assert.assertEquals(servers.get(1), filteredServers.get(1));
+    Assert.assertEquals(servers.get(2), filteredServers.get(2));
   }
 }
\ No newline at end of file