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


The following commit(s) were added to refs/heads/master by this push:
     new aab6a1d39 [SCB-2841]zone-aware filter support configure group size 
ratio (#4107)
aab6a1d39 is described below

commit aab6a1d393927693aa69b81bcab4562383f67004
Author: liubao68 <[email protected]>
AuthorDate: Fri Dec 8 15:12:00 2023 +0800

    [SCB-2841]zone-aware filter support configure group size ratio (#4107)
---
 .../filter/ZoneAwareDiscoveryFilter.java           |  28 +++++-
 .../loadbalance/TestLoadBalanceFilter2.java        |  16 +--
 .../filter/TestZoneAwareDiscoveryFilter.java       | 111 +++++++++++++++++++++
 3 files changed, 140 insertions(+), 15 deletions(-)

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
index 62eee1b3b..eb86fc8d5 100644
--- 
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
@@ -34,6 +34,10 @@ public class ZoneAwareDiscoveryFilter extends 
AbstractGroupDiscoveryFilter {
 
   public static final String GROUP_SIZE = "zone_aware_group_size";
 
+  public static final String CONFIG_ENABLED = 
"servicecomb.loadbalance.filter.zoneaware.enabled";
+
+  public static final String CONFIG_RATIO = 
"servicecomb.loadbalance.filter.zoneaware.ratio";
+
   private DataCenterProperties dataCenterProperties;
 
   @Autowired
@@ -49,10 +53,15 @@ public class ZoneAwareDiscoveryFilter extends 
AbstractGroupDiscoveryFilter {
 
   @Override
   public boolean enabled() {
-    return 
environment.getProperty("servicecomb.loadbalance.filter.zoneaware.enabled",
+    return environment.getProperty(CONFIG_ENABLED,
         Boolean.class, true);
   }
 
+  private int getRatio() {
+    return environment.getProperty(CONFIG_RATIO,
+        int.class, 50);
+  }
+
   @Override
   protected String contextParameter() {
     return PARAMETER;
@@ -87,16 +96,22 @@ public class ZoneAwareDiscoveryFilter extends 
AbstractGroupDiscoveryFilter {
       }
     }
 
-    if (!instancesRegionAndAZMatch.isEmpty()) {
+    int ratio = getRatio();
+
+    if (hasEnoughMembers(instances.size(), instancesRegionAndAZMatch.size(), 
ratio)) {
       parent.child(GROUP_PREFIX + groups, new DiscoveryTreeNode()
           .subName(parent, GROUP_PREFIX + 
groups).data(instancesRegionAndAZMatch));
       groups++;
+    } else {
+      instancesAZMatch.addAll(instancesRegionAndAZMatch);
     }
 
-    if (!instancesAZMatch.isEmpty()) {
+    if (hasEnoughMembers(instances.size(), instancesAZMatch.size(), ratio)) {
       parent.child(GROUP_PREFIX + groups, new DiscoveryTreeNode()
           .subName(parent, GROUP_PREFIX + groups).data(instancesAZMatch));
       groups++;
+    } else {
+      instancesNoMatch.addAll(instancesAZMatch);
     }
 
     parent.child(GROUP_PREFIX + groups, new DiscoveryTreeNode()
@@ -105,6 +120,13 @@ public class ZoneAwareDiscoveryFilter extends 
AbstractGroupDiscoveryFilter {
     parent.attribute(GROUP_SIZE, groups);
   }
 
+  private boolean hasEnoughMembers(int totalSize, int groupSize, int ratio) {
+    if (totalSize == 0 || groupSize == 0) {
+      return false;
+    }
+    return Math.floorDiv(groupSize * 100, totalSize) >= ratio;
+  }
+
   private boolean regionAndAZMatch(StatefulDiscoveryInstance target) {
     if (dataCenterProperties.getRegion() != null
         && dataCenterProperties.getAvailableZone() != null && 
target.getDataCenterInfo() != null) {
diff --git 
a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceFilter2.java
 
b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceFilter2.java
index 5e4c47e9c..e2b4418bc 100644
--- 
a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceFilter2.java
+++ 
b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceFilter2.java
@@ -57,6 +57,10 @@ public class TestLoadBalanceFilter2 {
   public void setUp() {
     
Mockito.when(environment.getProperty("servicecomb.loadbalance.userDefinedEndpoint.enabled",
         boolean.class, false)).thenReturn(false);
+    
Mockito.when(environment.getProperty("servicecomb.loadbalance.filter.zoneaware.enabled",
+        Boolean.class, true)).thenReturn(true);
+    
Mockito.when(environment.getProperty("servicecomb.loadbalance.filter.zoneaware.ratio",
+        int.class, 50)).thenReturn(0);
   }
 
   @Test
@@ -137,8 +141,6 @@ public class TestLoadBalanceFilter2 {
     zoneAwareDiscoveryFilter.setDataCenterProperties(myself);
     ServerDiscoveryFilter serverDiscoveryFilter = new ServerDiscoveryFilter();
     serverDiscoveryFilter.setScbEngine(scbEngine);
-    
Mockito.when(environment.getProperty("servicecomb.loadbalance.filter.zoneaware.enabled",
-        Boolean.class, true)).thenReturn(true);
     discoveryTree.setDiscoveryFilters(Arrays.asList(zoneAwareDiscoveryFilter,
         serverDiscoveryFilter));
     handler = new LoadBalanceFilter(new ExtensionsManager(new ArrayList<>()),
@@ -222,8 +224,6 @@ public class TestLoadBalanceFilter2 {
     ZoneAwareDiscoveryFilter zoneAwareDiscoveryFilter = new 
ZoneAwareDiscoveryFilter();
     zoneAwareDiscoveryFilter.setEnvironment(environment);
     zoneAwareDiscoveryFilter.setDataCenterProperties(myself);
-    
Mockito.when(environment.getProperty("servicecomb.loadbalance.filter.zoneaware.enabled",
-        Boolean.class, true)).thenReturn(true);
     ServerDiscoveryFilter serverDiscoveryFilter = new ServerDiscoveryFilter();
     serverDiscoveryFilter.setScbEngine(scbEngine);
     discoveryTree.setDiscoveryFilters(Arrays.asList(zoneAwareDiscoveryFilter,
@@ -318,8 +318,6 @@ public class TestLoadBalanceFilter2 {
     ZoneAwareDiscoveryFilter zoneAwareDiscoveryFilter = new 
ZoneAwareDiscoveryFilter();
     zoneAwareDiscoveryFilter.setEnvironment(environment);
     zoneAwareDiscoveryFilter.setDataCenterProperties(myself);
-    
Mockito.when(environment.getProperty("servicecomb.loadbalance.filter.zoneaware.enabled",
-        Boolean.class, true)).thenReturn(true);
     ServerDiscoveryFilter serverDiscoveryFilter = new ServerDiscoveryFilter();
     serverDiscoveryFilter.setScbEngine(scbEngine);
     discoveryTree.setDiscoveryFilters(Arrays.asList(zoneAwareDiscoveryFilter,
@@ -416,11 +414,8 @@ public class TestLoadBalanceFilter2 {
         .thenReturn(parent);
     DiscoveryTree discoveryTree = new DiscoveryTree(discoveryManager);
     ZoneAwareDiscoveryFilter zoneAwareDiscoveryFilter = new 
ZoneAwareDiscoveryFilter();
-    Environment environment = Mockito.mock(Environment.class);
     zoneAwareDiscoveryFilter.setEnvironment(environment);
     zoneAwareDiscoveryFilter.setDataCenterProperties(myself);
-    
Mockito.when(environment.getProperty("servicecomb.loadbalance.filter.zoneaware.enabled",
-        Boolean.class, true)).thenReturn(true);
     ServerDiscoveryFilter serverDiscoveryFilter = new ServerDiscoveryFilter();
     serverDiscoveryFilter.setScbEngine(scbEngine);
     discoveryTree.setDiscoveryFilters(Arrays.asList(zoneAwareDiscoveryFilter,
@@ -516,11 +511,8 @@ public class TestLoadBalanceFilter2 {
         .thenReturn(parent);
     DiscoveryTree discoveryTree = new DiscoveryTree(discoveryManager);
     ZoneAwareDiscoveryFilter zoneAwareDiscoveryFilter = new 
ZoneAwareDiscoveryFilter();
-    Environment environment = Mockito.mock(Environment.class);
     zoneAwareDiscoveryFilter.setEnvironment(environment);
     zoneAwareDiscoveryFilter.setDataCenterProperties(myself);
-    
Mockito.when(environment.getProperty("servicecomb.loadbalance.filter.zoneaware.enabled",
-        Boolean.class, true)).thenReturn(true);
     ServerDiscoveryFilter serverDiscoveryFilter = new ServerDiscoveryFilter();
     serverDiscoveryFilter.setScbEngine(scbEngine);
     discoveryTree.setDiscoveryFilters(Arrays.asList(zoneAwareDiscoveryFilter,
diff --git 
a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/TestZoneAwareDiscoveryFilter.java
 
b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/TestZoneAwareDiscoveryFilter.java
new file mode 100644
index 000000000..dfab80adc
--- /dev/null
+++ 
b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filter/TestZoneAwareDiscoveryFilter.java
@@ -0,0 +1,111 @@
+/*
+ * 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.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.servicecomb.config.DataCenterProperties;
+import org.apache.servicecomb.registry.api.DataCenterInfo;
+import org.apache.servicecomb.registry.api.DiscoveryInstance;
+import org.apache.servicecomb.registry.discovery.DiscoveryContext;
+import org.apache.servicecomb.registry.discovery.DiscoveryTreeNode;
+import org.apache.servicecomb.registry.discovery.StatefulDiscoveryInstance;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+import org.springframework.core.env.Environment;
+
+public class TestZoneAwareDiscoveryFilter {
+  Environment environment = Mockito.mock(Environment.class);
+
+  @BeforeEach
+  public void setUp() {
+    
Mockito.when(environment.getProperty("servicecomb.loadbalance.filter.zoneaware.enabled",
+        Boolean.class, true)).thenReturn(true);
+  }
+
+  @Test
+  public void test_not_enough_instance() {
+    
Mockito.when(environment.getProperty("servicecomb.loadbalance.filter.zoneaware.ratio",
+        int.class, 50)).thenReturn(50);
+
+    ZoneAwareDiscoveryFilter filter = new ZoneAwareDiscoveryFilter();
+    filter.setEnvironment(environment);
+
+    // set up data
+    DataCenterProperties myself = new DataCenterProperties();
+    myself.setName("test");
+    myself.setRegion("test-Region");
+    myself.setAvailableZone("test-zone");
+    filter.setDataCenterProperties(myself);
+
+    DiscoveryInstance discoveryInstance = 
Mockito.mock(DiscoveryInstance.class);
+    StatefulDiscoveryInstance allmatchInstance = new 
StatefulDiscoveryInstance(discoveryInstance);
+    DataCenterInfo info = new DataCenterInfo();
+    info.setName("test");
+    info.setRegion("test-Region");
+    info.setAvailableZone("test-zone");
+    List<String> allMatchEndpoint = new ArrayList<>();
+    allMatchEndpoint.add("rest://localhost:9090");
+    
Mockito.when(discoveryInstance.getEndpoints()).thenReturn(allMatchEndpoint);
+    Mockito.when(discoveryInstance.getDataCenterInfo()).thenReturn(info);
+    
Mockito.when(discoveryInstance.getInstanceId()).thenReturn("allmatchInstance");
+
+    DiscoveryInstance regionMatchDiscoveryInstance = 
Mockito.mock(DiscoveryInstance.class);
+    StatefulDiscoveryInstance regionMatchInstance = new 
StatefulDiscoveryInstance(regionMatchDiscoveryInstance);
+    DataCenterInfo regionMatchInfo = new DataCenterInfo();
+    regionMatchInfo.setName("test");
+    regionMatchInfo.setRegion("test-Region");
+    regionMatchInfo.setAvailableZone("test-zone2");
+    List<String> regionMatchEndpoint = new ArrayList<>();
+    regionMatchEndpoint.add("rest://localhost:9091");
+    
Mockito.when(regionMatchDiscoveryInstance.getEndpoints()).thenReturn(regionMatchEndpoint);
+    
Mockito.when(regionMatchDiscoveryInstance.getDataCenterInfo()).thenReturn(regionMatchInfo);
+    
Mockito.when(regionMatchDiscoveryInstance.getInstanceId()).thenReturn("regionMatchInstance");
+
+    DiscoveryInstance noneMatchDiscoveryInstance = 
Mockito.mock(DiscoveryInstance.class);
+    StatefulDiscoveryInstance noneMatchInstance = new 
StatefulDiscoveryInstance(noneMatchDiscoveryInstance);
+    DataCenterInfo noneMatchInfo = new DataCenterInfo();
+    noneMatchInfo.setName("test");
+    noneMatchInfo.setRegion("test-Region2");
+    noneMatchInfo.setAvailableZone("test-zone2");
+    List<String> noMatchEndpoint = new ArrayList<>();
+    noMatchEndpoint.add("rest://localhost:9092");
+    
Mockito.when(noneMatchDiscoveryInstance.getEndpoints()).thenReturn(noMatchEndpoint);
+    
Mockito.when(noneMatchDiscoveryInstance.getDataCenterInfo()).thenReturn(noneMatchInfo);
+    
Mockito.when(noneMatchDiscoveryInstance.getInstanceId()).thenReturn("noneMatchInstance");
+
+    // run test
+    List<StatefulDiscoveryInstance> data = Arrays.asList(allmatchInstance, 
regionMatchInstance, noneMatchInstance);
+    DiscoveryTreeNode parent = new 
DiscoveryTreeNode().name("parent").data(data);
+    DiscoveryContext context = new DiscoveryContext();
+    DiscoveryTreeNode result = filter.discovery(context, parent);
+
+    // check result
+    Integer level = context.getContextParameter(filter.contextParameter());
+    Integer groups = parent.attribute(filter.groupsSizeParameter());
+    List<StatefulDiscoveryInstance> resultData = result.data();
+    Assertions.assertEquals(1, level);
+    Assertions.assertEquals(2, groups);
+    Assertions.assertEquals(2, resultData.size());
+    Assertions.assertEquals("regionMatchInstance", 
resultData.get(0).getInstanceId());
+    Assertions.assertEquals("allmatchInstance", 
resultData.get(1).getInstanceId());
+  }
+}

Reply via email to