You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2021/01/11 11:14:34 UTC

[servicecomb-java-chassis] 01/07: [SCB-2116]improve algorithm to match when applying rules

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

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit da7b7718f493600670076b8418dbb043977ffed4
Author: liubao <bi...@qq.com>
AuthorDate: Wed Dec 30 17:45:45 2020 +0800

    [SCB-2116]improve algorithm to match when applying rules
---
 .../servicecomb/governance/InvocationContext.java} | 15 +---
 .../servicecomb/governance/MatchersManager.java    | 57 ++++++++++---
 .../governance/marker/GovHttpRequest.java          | 20 +++++
 .../governance/marker/TrafficMarker.java           | 31 +++++++
 .../governance/policy/AbstractPolicy.java          | 24 ++++--
 .../policy/{GovRule.java => GovernanceRule.java}   | 42 +++++++++-
 .../governance/properties/BulkheadProperties.java  |  2 +-
 .../properties/CircuitBreakerProperties.java       |  2 +-
 ...ovProperties.java => GovernanceProperties.java} | 19 +++--
 .../governance/properties/MatchProperties.java     |  7 +-
 .../PolicyProperties.java}                         | 25 ++----
 .../governance/properties/RateLimitProperties.java |  2 +-
 .../governance/properties/RetryProperties.java     |  2 +-
 .../governance/service/MatchersService.java        |  5 +-
 .../MatchersServiceImpl.java}                      | 46 ++++++-----
 .../governance/service/PolicyServiceImpl.java      |  6 +-
 .../servicecomb/governance/FlowControlTest.java    | 94 ++++++++++++++++++++++
 ...tiesTest.java => GovernancePropertiesTest.java} |  8 +-
 ...hersService.java => MockInvocationContext.java} | 29 +++++--
 19 files changed, 335 insertions(+), 101 deletions(-)

diff --git a/governance/src/test/java/org/apache/servicecomb/governance/MockMatchersService.java b/governance/src/main/java/org/apache/servicecomb/governance/InvocationContext.java
similarity index 69%
copy from governance/src/test/java/org/apache/servicecomb/governance/MockMatchersService.java
copy to governance/src/main/java/org/apache/servicecomb/governance/InvocationContext.java
index 1387312..07d03ce 100644
--- a/governance/src/test/java/org/apache/servicecomb/governance/MockMatchersService.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/InvocationContext.java
@@ -17,17 +17,10 @@
 
 package org.apache.servicecomb.governance;
 
-import java.util.List;
+import java.util.Map;
 
-import org.springframework.stereotype.Component;
+public interface InvocationContext {
+  Map<String, Boolean> getCalculatedMatches();
 
-import org.apache.servicecomb.governance.marker.GovHttpRequest;
-import org.apache.servicecomb.governance.service.MatchersService;
-
-@Component
-public class MockMatchersService implements MatchersService {
-  @Override
-  public List<String> getMatchedNames(GovHttpRequest govHttpRequest) {
-    return null;
-  }
+  void addMatch(String key, Boolean value);
 }
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/MatchersManager.java b/governance/src/main/java/org/apache/servicecomb/governance/MatchersManager.java
index c35c1a1..6a7ec0e 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/MatchersManager.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/MatchersManager.java
@@ -16,17 +16,18 @@
  */
 package org.apache.servicecomb.governance;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 
-import org.apache.servicecomb.governance.policy.Policy;
+import org.apache.servicecomb.governance.marker.GovHttpRequest;
+import org.apache.servicecomb.governance.policy.AbstractPolicy;
 import org.apache.servicecomb.governance.service.MatchersService;
 import org.apache.servicecomb.governance.service.PolicyService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
-import org.apache.servicecomb.governance.marker.GovHttpRequest;
-
 @Component
 public class MatchersManager {
 
@@ -36,17 +37,49 @@ public class MatchersManager {
   @Autowired
   private PolicyService policyService;
 
+  @Autowired
+  private InvocationContext invocationContext;
+
   public MatchersManager() {
   }
 
-  public Map<String, Policy> match(GovHttpRequest request) {
-    /**
-     * 1.获取该请求携带的marker
-     */
-    List<String> marks = matchersService.getMatchedNames(request);
-    /**
-     * 2.通过 marker获取到所有的policy
-     */
-    return policyService.getAllPolicies(marks);
+  public <T extends AbstractPolicy> T match(GovHttpRequest request, Map<String, T> policies) {
+    List<T> matchedPolicy = new ArrayList<>();
+    List<String> matchedKeys = new ArrayList<>();
+
+    Map<String, Boolean> calculatedMatches = invocationContext.getCalculatedMatches();
+    calculatedMatches.forEach((k, v) -> {
+      if (v) {
+        matchedKeys.add(k);
+      }
+    });
+
+    for (Entry<String, T> entry : policies.entrySet()) {
+      T policy = entry.getValue();
+
+      if (policy.match(matchedKeys)) {
+        matchedPolicy.add(policy);
+        continue;
+      }
+
+      List<String> parsedMatches = policy.getParsedMatch();
+      if (parsedMatches != null) {
+        parsedMatches.stream().forEach(key -> {
+          if (!calculatedMatches.containsKey(key)) {
+            boolean keyMatch = matchersService.checkMatch(request, key);
+            invocationContext.addMatch(key, keyMatch);
+            if (keyMatch) {
+              matchedPolicy.add(policy);
+            }
+          }
+        });
+      }
+    }
+
+    if (matchedPolicy.size() > 0) {
+      matchedPolicy.sort(AbstractPolicy::compare);
+      return matchedPolicy.get(0);
+    }
+    return null;
   }
 }
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/GovHttpRequest.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/GovHttpRequest.java
index bc4d9ea..2176ef5 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/marker/GovHttpRequest.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/GovHttpRequest.java
@@ -18,7 +18,12 @@ package org.apache.servicecomb.governance.marker;
 
 import java.util.Map;
 
+import org.springframework.util.Assert;
+
 public class GovHttpRequest {
+  private final String serviceName;
+
+  private final String version;
 
   private Map<String, String> headers;
 
@@ -26,6 +31,21 @@ public class GovHttpRequest {
 
   private String method;
 
+  public GovHttpRequest(String serviceName, String version) {
+    Assert.notNull(serviceName, "serviceName should not be null");
+    Assert.notNull(version, "version should not be null");
+    this.serviceName = serviceName;
+    this.version = version;
+  }
+
+  public String getServiceName() {
+    return serviceName;
+  }
+
+  public String getVersion() {
+    return version;
+  }
+
   public Map<String, String> getHeaders() {
     return headers;
   }
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/marker/TrafficMarker.java b/governance/src/main/java/org/apache/servicecomb/governance/marker/TrafficMarker.java
index ba4cbf7..b64c168 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/marker/TrafficMarker.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/marker/TrafficMarker.java
@@ -16,8 +16,11 @@
  */
 package org.apache.servicecomb.governance.marker;
 
+import java.util.Arrays;
 import java.util.List;
 
+import org.apache.commons.lang3.StringUtils;
+
 public class TrafficMarker {
 
   private String services;
@@ -39,4 +42,32 @@ public class TrafficMarker {
   public void setMatches(List<Matcher> matches) {
     this.matches = matches;
   }
+
+  public boolean checkMatch(GovHttpRequest govHttpRequest, RequestProcessor requestProcessor, String name) {
+    if (!servicesMatch(govHttpRequest)) {
+      return false;
+    }
+
+    return this.matches.stream().anyMatch(match ->
+        match.getName().equals(name) && requestProcessor.match(govHttpRequest, match));
+  }
+
+
+  private boolean servicesMatch(GovHttpRequest govHttpRequest) {
+    if (StringUtils.isEmpty(services)) {
+      return true;
+    }
+
+    return Arrays.stream(services.split(",")).anyMatch(ser -> {
+      String[] serviceAndVersion = ser.split(":");
+      if (serviceAndVersion.length == 1) {
+        return govHttpRequest.getServiceName().equals(serviceAndVersion[0]);
+      } else if (serviceAndVersion.length == 2) {
+        return govHttpRequest.getServiceName().equals(serviceAndVersion[0]) && govHttpRequest.getVersion()
+            .equals(serviceAndVersion[1]);
+      } else {
+        return false;
+      }
+    });
+  }
 }
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/policy/AbstractPolicy.java b/governance/src/main/java/org/apache/servicecomb/governance/policy/AbstractPolicy.java
index ae47da3..3e496c4 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/policy/AbstractPolicy.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/policy/AbstractPolicy.java
@@ -16,20 +16,19 @@
  */
 package org.apache.servicecomb.governance.policy;
 
-import java.util.Arrays;
 import java.util.List;
 
 public abstract class AbstractPolicy implements Policy {
 
   private String name;
 
-  private GovRule rules;
+  private GovernanceRule rules;
 
-  public GovRule getRules() {
+  public GovernanceRule getRules() {
     return rules;
   }
 
-  public void setRules(GovRule rules) {
+  public void setRules(GovernanceRule rules) {
     this.rules = rules;
   }
 
@@ -39,13 +38,24 @@ public abstract class AbstractPolicy implements Policy {
 
   @Override
   public boolean match(List<String> items) {
-    if (rules == null || rules.getMatch() == null) {
+    if (rules == null) {
       return false;
     }
+    return items.stream().anyMatch(item -> rules.match(item));
+  }
+
+  public static int compare(AbstractPolicy policy1, AbstractPolicy policy2) {
+    int p1 = policy1.rules == null ? 0 : policy1.rules.getPrecedence();
+    int p2 = policy2.rules == null ? 0 : policy2.rules.getPrecedence();
+    return p1 - p2;
+  }
 
-    List<String> configuredItems = Arrays.asList(rules.getMatch().split(","));
+  public List<String> getParsedMatch() {
+    if (rules == null) {
+      return null;
+    }
 
-    return items.stream().anyMatch(item -> configuredItems.contains(item));
+    return rules.getParsedMatch();
   }
 
   @Override
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/policy/GovRule.java b/governance/src/main/java/org/apache/servicecomb/governance/policy/GovernanceRule.java
similarity index 57%
copy from governance/src/main/java/org/apache/servicecomb/governance/policy/GovRule.java
copy to governance/src/main/java/org/apache/servicecomb/governance/policy/GovernanceRule.java
index 58db001..d75b250 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/policy/GovRule.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/policy/GovernanceRule.java
@@ -17,10 +17,18 @@
 
 package org.apache.servicecomb.governance.policy;
 
-public class GovRule {
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+
+public class GovernanceRule {
+  private static final String MATCH_NONE = "none";
 
   private String match;
 
+  private List<String> parsedMatch;
+
   private int precedence;
 
   public String getMatch() {
@@ -38,4 +46,36 @@ public class GovRule {
   public void setPrecedence(int precedence) {
     this.precedence = precedence;
   }
+
+  public boolean match(String name) {
+    if (StringUtils.isEmpty(this.match)) {
+      return false;
+    }
+
+    if (MATCH_NONE.equals(this.match)) {
+      return true;
+    }
+
+    if (this.parsedMatch == null) {
+      this.parsedMatch = Arrays.asList(this.match.split(","));
+    }
+
+    return parsedMatch.contains(name);
+  }
+
+  public List<String> getParsedMatch() {
+    if (StringUtils.isEmpty(this.match)) {
+      return null;
+    }
+
+    if (MATCH_NONE.equals(this.match)) {
+      return null;
+    }
+
+    if (this.parsedMatch == null) {
+      this.parsedMatch = Arrays.asList(this.match.split(","));
+    }
+
+    return parsedMatch;
+  }
 }
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/BulkheadProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/BulkheadProperties.java
index b61f4d3..2e340b7 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/properties/BulkheadProperties.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/BulkheadProperties.java
@@ -21,7 +21,7 @@ import org.apache.servicecomb.governance.policy.BulkheadPolicy;
 import org.springframework.stereotype.Component;
 
 @Component
-public class BulkheadProperties extends GovProperties<BulkheadPolicy> {
+public class BulkheadProperties extends PolicyProperties<BulkheadPolicy> {
   public static final String MATCH_BULKHEAD__KEY = "servicecomb.bulkhead";
 
   public BulkheadProperties() {
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/CircuitBreakerProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/CircuitBreakerProperties.java
index 5465f66..578d346 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/properties/CircuitBreakerProperties.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/CircuitBreakerProperties.java
@@ -20,7 +20,7 @@ import org.apache.servicecomb.governance.policy.CircuitBreakerPolicy;
 import org.springframework.stereotype.Component;
 
 @Component
-public class CircuitBreakerProperties extends GovProperties<CircuitBreakerPolicy> {
+public class CircuitBreakerProperties extends PolicyProperties<CircuitBreakerPolicy> {
   public static final String MATCH_CIRCUITBREAKER_KEY = "servicecomb.circuitBreaker";
 
   public CircuitBreakerProperties() {
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/GovProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/GovernanceProperties.java
similarity index 91%
rename from governance/src/main/java/org/apache/servicecomb/governance/properties/GovProperties.java
rename to governance/src/main/java/org/apache/servicecomb/governance/properties/GovernanceProperties.java
index 3a498e6..ab852eb 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/properties/GovProperties.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/GovernanceProperties.java
@@ -41,11 +41,12 @@ import org.yaml.snakeyaml.error.YAMLException;
 import org.yaml.snakeyaml.representer.Representer;
 
 import com.google.common.eventbus.Subscribe;
+
 import org.apache.servicecomb.governance.event.ConfigurationChangedEvent;
 import org.apache.servicecomb.governance.event.EventManager;
 
-public abstract class GovProperties<T> implements InitializingBean {
-  private static final Logger LOGGER = LoggerFactory.getLogger(GovProperties.class);
+public abstract class GovernanceProperties<T> implements InitializingBean {
+  private static final Logger LOGGER = LoggerFactory.getLogger(GovernanceProperties.class);
 
   private final Representer representer = new Representer();
 
@@ -58,7 +59,7 @@ public abstract class GovProperties<T> implements InitializingBean {
 
   protected Class<T> entityClass;
 
-  protected GovProperties(String key) {
+  protected GovernanceProperties(String key) {
     configKey = key;
     representer.getPropertyUtils().setSkipMissingProperties(true);
     EventManager.register(this);
@@ -75,7 +76,7 @@ public abstract class GovProperties<T> implements InitializingBean {
     for (String key : event.getChangedConfigurations()) {
       if (key.startsWith(configKey + ".")) {
         // 删除的情况, 从配置文件读取配置。 需要保证 environment 已经刷新配置值。
-        T entityItem = parseEntityItem(environment.getProperty(key));
+        T entityItem = parseEntityItem(key, environment.getProperty(key));
         String mapKey = key.substring((configKey + ".").length());
         if (entityItem == null) {
           parsedEntity.remove(mapKey);
@@ -142,7 +143,7 @@ public abstract class GovProperties<T> implements InitializingBean {
 
     Map<String, T> resultMap = new HashMap<>();
     for (Entry<String, String> entry : yamlEntity.entrySet()) {
-      T marker = parseEntityItem(entry.getValue());
+      T marker = parseEntityItem(entry.getKey(), entry.getValue());
       if (marker != null) {
         resultMap.put(entry.getKey(), marker);
       }
@@ -152,14 +153,18 @@ public abstract class GovProperties<T> implements InitializingBean {
 
   protected abstract Class<T> getEntityClass();
 
-  protected T parseEntityItem(String value) {
+  protected abstract void setName(T value, String key);
+
+  protected T parseEntityItem(String key, String value) {
     if (StringUtils.isEmpty(value)) {
       return null;
     }
 
     try {
       Yaml entityParser = new Yaml(new Constructor(new TypeDescription(entityClass, entityClass)), representer);
-      return entityParser.loadAs(value, entityClass);
+      T result = entityParser.loadAs(value, entityClass);
+      setName(result, key);
+      return result;
     } catch (YAMLException e) {
       LOGGER.error("governance config yaml is illegal : {}", e.getMessage());
     }
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/MatchProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/MatchProperties.java
index c910518..7a2a5ae 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/properties/MatchProperties.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/MatchProperties.java
@@ -20,7 +20,7 @@ import org.apache.servicecomb.governance.marker.TrafficMarker;
 import org.springframework.stereotype.Component;
 
 @Component
-public class MatchProperties extends GovProperties<TrafficMarker> {
+public class MatchProperties extends GovernanceProperties<TrafficMarker> {
   public static final String MATCH_POLICY_KEY = "servicecomb.matchGroup";
 
   public MatchProperties() {
@@ -31,4 +31,9 @@ public class MatchProperties extends GovProperties<TrafficMarker> {
   public Class<TrafficMarker> getEntityClass() {
     return TrafficMarker.class;
   }
+
+  @Override
+  protected void setName(TrafficMarker value, String key) {
+    // do nothing
+  }
 }
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/policy/GovRule.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/PolicyProperties.java
similarity index 68%
rename from governance/src/main/java/org/apache/servicecomb/governance/policy/GovRule.java
rename to governance/src/main/java/org/apache/servicecomb/governance/properties/PolicyProperties.java
index 58db001..73a3a07 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/policy/GovRule.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/PolicyProperties.java
@@ -15,27 +15,16 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.governance.policy;
+package org.apache.servicecomb.governance.properties;
 
-public class GovRule {
+import org.apache.servicecomb.governance.policy.AbstractPolicy;
 
-  private String match;
-
-  private int precedence;
-
-  public String getMatch() {
-    return match;
-  }
-
-  public void setMatch(String match) {
-    this.match = match;
-  }
-
-  public int getPrecedence() {
-    return precedence;
+public abstract class PolicyProperties<T extends AbstractPolicy> extends GovernanceProperties<T> {
+  protected PolicyProperties(String key) {
+    super(key);
   }
 
-  public void setPrecedence(int precedence) {
-    this.precedence = precedence;
+  protected void setName(T value, String key) {
+    value.setName(key);
   }
 }
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/RateLimitProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/RateLimitProperties.java
index e1a2653..472901c 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/properties/RateLimitProperties.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/RateLimitProperties.java
@@ -21,7 +21,7 @@ import org.apache.servicecomb.governance.policy.RateLimitingPolicy;
 import org.springframework.stereotype.Component;
 
 @Component
-public class RateLimitProperties extends GovProperties<RateLimitingPolicy> {
+public class RateLimitProperties extends PolicyProperties<RateLimitingPolicy> {
   public static final String MATCH_RATE_LIMIT_KEY = "servicecomb.rateLimiting";
 
   public RateLimitProperties() {
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/properties/RetryProperties.java b/governance/src/main/java/org/apache/servicecomb/governance/properties/RetryProperties.java
index 9c87ba2..483ea52 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/properties/RetryProperties.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/properties/RetryProperties.java
@@ -20,7 +20,7 @@ import org.apache.servicecomb.governance.policy.RetryPolicy;
 import org.springframework.stereotype.Component;
 
 @Component
-public class RetryProperties extends GovProperties<RetryPolicy> {
+public class RetryProperties extends PolicyProperties<RetryPolicy> {
   public static final String MATCH_RETRY_KEY = "servicecomb.retry";
 
   public RetryProperties() {
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/service/MatchersService.java b/governance/src/main/java/org/apache/servicecomb/governance/service/MatchersService.java
index 265e632..bb01422 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/service/MatchersService.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/service/MatchersService.java
@@ -18,9 +18,6 @@ package org.apache.servicecomb.governance.service;
 
 import org.apache.servicecomb.governance.marker.GovHttpRequest;
 
-import java.util.List;
-
 public interface MatchersService {
-
-  List<String> getMatchedNames(GovHttpRequest govHttpRequest);
+  boolean checkMatch(GovHttpRequest govHttpRequest, String key);
 }
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/MatchersManager.java b/governance/src/main/java/org/apache/servicecomb/governance/service/MatchersServiceImpl.java
similarity index 54%
copy from governance/src/main/java/org/apache/servicecomb/governance/MatchersManager.java
copy to governance/src/main/java/org/apache/servicecomb/governance/service/MatchersServiceImpl.java
index c35c1a1..0df3159 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/MatchersManager.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/service/MatchersServiceImpl.java
@@ -14,39 +14,41 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.servicecomb.governance;
 
-import java.util.List;
+package org.apache.servicecomb.governance.service;
+
 import java.util.Map;
 
-import org.apache.servicecomb.governance.policy.Policy;
-import org.apache.servicecomb.governance.service.MatchersService;
-import org.apache.servicecomb.governance.service.PolicyService;
+import org.apache.servicecomb.governance.marker.GovHttpRequest;
+import org.apache.servicecomb.governance.marker.RequestProcessor;
+import org.apache.servicecomb.governance.marker.TrafficMarker;
+import org.apache.servicecomb.governance.properties.MatchProperties;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
-import org.apache.servicecomb.governance.marker.GovHttpRequest;
-
 @Component
-public class MatchersManager {
-
+public class MatchersServiceImpl implements MatchersService {
   @Autowired
-  private MatchersService matchersService;
+  private RequestProcessor requestProcessor;
 
   @Autowired
-  private PolicyService policyService;
+  private MatchProperties matchProperties;
 
-  public MatchersManager() {
-  }
+  @Override
+  public boolean checkMatch(GovHttpRequest govHttpRequest, String key) {
+    Map<String, TrafficMarker> parsedEntity = matchProperties.getParsedEntity();
+
+    String[] subKeys = key.split("\\.");
+    if (subKeys.length != 2) {
+      return false;
+    }
+
+    TrafficMarker trafficMarker = parsedEntity.get(subKeys[0]);
+
+    if (trafficMarker == null) {
+      return false;
+    }
 
-  public Map<String, Policy> match(GovHttpRequest request) {
-    /**
-     * 1.获取该请求携带的marker
-     */
-    List<String> marks = matchersService.getMatchedNames(request);
-    /**
-     * 2.通过 marker获取到所有的policy
-     */
-    return policyService.getAllPolicies(marks);
+    return trafficMarker.checkMatch(govHttpRequest, requestProcessor, subKeys[1]);
   }
 }
diff --git a/governance/src/main/java/org/apache/servicecomb/governance/service/PolicyServiceImpl.java b/governance/src/main/java/org/apache/servicecomb/governance/service/PolicyServiceImpl.java
index 03f1a1b..47fa0d6 100644
--- a/governance/src/main/java/org/apache/servicecomb/governance/service/PolicyServiceImpl.java
+++ b/governance/src/main/java/org/apache/servicecomb/governance/service/PolicyServiceImpl.java
@@ -29,7 +29,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 
-import org.apache.servicecomb.governance.properties.GovProperties;
+import org.apache.servicecomb.governance.properties.GovernanceProperties;
 
 @Component
 public class PolicyServiceImpl implements PolicyService {
@@ -37,7 +37,7 @@ public class PolicyServiceImpl implements PolicyService {
   private static final String MATCH_NONE = "none";
 
   @Autowired
-  private List<GovProperties<? extends AbstractPolicy>> propertiesList;
+  private List<GovernanceProperties<? extends AbstractPolicy>> propertiesList;
 
   @Override
   public Map<String, Policy> getAllPolicies(List<String> marks) {
@@ -47,7 +47,7 @@ public class PolicyServiceImpl implements PolicyService {
       return policies;
     }
 
-    for (GovProperties<? extends AbstractPolicy> properties : propertiesList) {
+    for (GovernanceProperties<? extends AbstractPolicy> properties : propertiesList) {
       Policy policy = match(properties.getParsedEntity(), marks);
       if (policy != null) {
         policies.put(properties.getClass().getName(), policy);
diff --git a/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java b/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java
new file mode 100644
index 0000000..8aeddba
--- /dev/null
+++ b/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.governance;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.servicecomb.governance.handler.RateLimitingHandler;
+import org.apache.servicecomb.governance.marker.GovHttpRequest;
+import org.apache.servicecomb.governance.policy.Policy;
+import org.apache.servicecomb.governance.properties.RateLimitProperties;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.ConfigFileApplicationContextInitializer;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import io.github.resilience4j.decorators.Decorators;
+import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier;
+import io.github.resilience4j.ratelimiter.RequestNotPermitted;
+
+@RunWith(SpringRunner.class)
+@ContextConfiguration(locations = "classpath:META-INF/spring/*.xml", initializers = ConfigFileApplicationContextInitializer.class)
+public class FlowControlTest {
+  @Autowired
+  private RateLimitingHandler rateLimitingHandler;
+
+  @Autowired
+  private RateLimitProperties rateLimitProperties;
+
+  @Autowired
+  private MatchersManager matchersManager;
+
+  @Test
+  public void test_rate_limiting_work() throws Throwable {
+    DecorateCheckedSupplier<Object> ds = Decorators.ofCheckedSupplier(() -> {
+      return "test";
+    });
+
+    GovHttpRequest request = new GovHttpRequest("testService", "1.0");
+    request.setUri("/hello");
+    Policy policy = matchersManager.match(request, rateLimitProperties.getParsedEntity());
+    Assert.assertNotNull(policy);
+    DecorateCheckedSupplier<Object> dcs = rateLimitingHandler.process(ds, policy);
+
+    Assert.assertEquals("test", dcs.get());
+
+    // flow control
+    CountDownLatch cd = new CountDownLatch(10);
+    AtomicBoolean expected = new AtomicBoolean(false);
+    AtomicBoolean notExpected = new AtomicBoolean(false);
+    for (int i = 0; i < 10; i++) {
+      new Thread() {
+        public void run() {
+          try {
+            DecorateCheckedSupplier<Object> dcs = rateLimitingHandler.process(ds, policy);
+            Object result = dcs.get();
+            if (!"test".equals(result)) {
+              notExpected.set(true);
+            }
+          } catch (Throwable e) {
+            if (e instanceof RequestNotPermitted) {
+              expected.set(true);
+            } else {
+              notExpected.set(true);
+            }
+          }
+          cd.countDown();
+        }
+      }.start();
+    }
+    cd.await(1, TimeUnit.SECONDS);
+    Assert.assertTrue(expected.get());
+    Assert.assertFalse(notExpected.get());
+  }
+}
diff --git a/governance/src/test/java/org/apache/servicecomb/governance/GovPropertiesTest.java b/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java
similarity index 97%
rename from governance/src/test/java/org/apache/servicecomb/governance/GovPropertiesTest.java
rename to governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java
index 9b4d3c9..560bf05 100644
--- a/governance/src/test/java/org/apache/servicecomb/governance/GovPropertiesTest.java
+++ b/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java
@@ -47,17 +47,17 @@ import org.apache.servicecomb.governance.policy.RateLimitingPolicy;
 import org.apache.servicecomb.governance.policy.RetryPolicy;
 import org.apache.servicecomb.governance.properties.BulkheadProperties;
 import org.apache.servicecomb.governance.properties.CircuitBreakerProperties;
-import org.apache.servicecomb.governance.properties.GovProperties;
+import org.apache.servicecomb.governance.properties.GovernanceProperties;
 import org.apache.servicecomb.governance.properties.MatchProperties;
 import org.apache.servicecomb.governance.properties.RateLimitProperties;
 import org.apache.servicecomb.governance.properties.RetryProperties;
 
 @RunWith(SpringRunner.class)
 @ContextConfiguration(locations = "classpath:META-INF/spring/*.xml", initializers = ConfigFileApplicationContextInitializer.class)
-public class GovPropertiesTest {
+public class GovernancePropertiesTest {
 
   @Autowired
-  private List<GovProperties<? extends AbstractPolicy>> propertiesList;
+  private List<GovernanceProperties<? extends AbstractPolicy>> propertiesList;
 
   @Autowired
   private MatchProperties matchProperties;
@@ -79,7 +79,7 @@ public class GovPropertiesTest {
 
   private Map<String, Object> dynamicValues = new HashMap<>();
 
-  public GovPropertiesTest() {
+  public GovernancePropertiesTest() {
     System.out.print(1);
   }
 
diff --git a/governance/src/test/java/org/apache/servicecomb/governance/MockMatchersService.java b/governance/src/test/java/org/apache/servicecomb/governance/MockInvocationContext.java
similarity index 58%
rename from governance/src/test/java/org/apache/servicecomb/governance/MockMatchersService.java
rename to governance/src/test/java/org/apache/servicecomb/governance/MockInvocationContext.java
index 1387312..bde9b38 100644
--- a/governance/src/test/java/org/apache/servicecomb/governance/MockMatchersService.java
+++ b/governance/src/test/java/org/apache/servicecomb/governance/MockInvocationContext.java
@@ -17,17 +17,32 @@
 
 package org.apache.servicecomb.governance;
 
-import java.util.List;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.springframework.stereotype.Component;
 
-import org.apache.servicecomb.governance.marker.GovHttpRequest;
-import org.apache.servicecomb.governance.service.MatchersService;
-
 @Component
-public class MockMatchersService implements MatchersService {
+public class MockInvocationContext implements InvocationContext {
+  private ThreadLocal<Map<String, Boolean>> context = new ThreadLocal<>();
+
+  @Override
+  public Map<String, Boolean> getCalculatedMatches() {
+    Map<String, Boolean> result = context.get();
+    if (result == null) {
+      return Collections.emptyMap();
+    }
+    return result;
+  }
+
   @Override
-  public List<String> getMatchedNames(GovHttpRequest govHttpRequest) {
-    return null;
+  public void addMatch(String key, Boolean value) {
+    Map<String, Boolean> result = context.get();
+    if (result == null) {
+      result = new HashMap<>();
+      context.set(result);
+    }
+    result.put(key, value);
   }
 }