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 2023/12/08 07:11:53 UTC
(servicecomb-java-chassis) branch 2.8.x updated: [SCB-2841]zone-aware filter support configure group size ratio (#4108)
This is an automated email from the ASF dual-hosted git repository.
liubao pushed a commit to branch 2.8.x
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git
The following commit(s) were added to refs/heads/2.8.x by this push:
new 9695b5baa [SCB-2841]zone-aware filter support configure group size ratio (#4108)
9695b5baa is described below
commit 9695b5baa1d0656071c9736d7636c7dcfb2ccdb8
Author: liubao68 <bi...@qq.com>
AuthorDate: Fri Dec 8 15:11:48 2023 +0800
[SCB-2841]zone-aware filter support configure group size ratio (#4108)
---
.../filterext/ZoneAwareDiscoveryFilter.java | 26 ++-
.../loadbalance/TestLoadBalanceHandler2.java | 16 +-
.../filterext/TestZoneAwareDiscoveryFilter.java | 193 +++++++++++++++++++++
3 files changed, 227 insertions(+), 8 deletions(-)
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
index d31597b5e..fd308c282 100644
--- 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
@@ -29,6 +29,7 @@ import org.apache.servicecomb.registry.api.registry.MicroserviceInstance;
import com.netflix.config.DynamicPropertyFactory;
public class ZoneAwareDiscoveryFilter implements ServerListFilterExt {
+ public static final String CONFIG_RATIO = "servicecomb.loadbalance.filter.zoneaware.ratio";
@Override
public int getOrder() {
@@ -42,6 +43,11 @@ public class ZoneAwareDiscoveryFilter implements ServerListFilterExt {
.get();
}
+ private int getRatio() {
+ return DynamicPropertyFactory.getInstance()
+ .getIntProperty(CONFIG_RATIO, 50).get();
+ }
+
@Override
public List<ServiceCombServer> getFilteredListOfServers(List<ServiceCombServer> servers,
Invocation invocation) {
@@ -59,14 +65,30 @@ public class ZoneAwareDiscoveryFilter implements ServerListFilterExt {
instancesNoMatch.add(server);
}
});
- if (!instancesRegionAndAZMatch.isEmpty()) {
+
+ int ratio = getRatio();
+
+ if (hasEnoughMembers(servers.size(), instancesRegionAndAZMatch.size(), ratio)) {
return instancesRegionAndAZMatch;
- } else if (!instancesAZMatch.isEmpty()) {
+ } else {
+ instancesAZMatch.addAll(instancesRegionAndAZMatch);
+ }
+
+ if (hasEnoughMembers(servers.size(), instancesAZMatch.size(), ratio)) {
return instancesAZMatch;
+ } else {
+ instancesNoMatch.addAll(instancesAZMatch);
}
return instancesNoMatch;
}
+ 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(MicroserviceInstance myself, MicroserviceInstance target) {
if (myself == null || myself.getDataCenterInfo() == null) {
// when instance have no datacenter info, it will match all other datacenters
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 e2a353db4..2008445ae 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
@@ -17,6 +17,8 @@
package org.apache.servicecomb.loadbalance;
+import static org.mockito.Mockito.when;
+
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -40,6 +42,7 @@ 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.ServerDiscoveryFilter;
+import org.apache.servicecomb.loadbalance.filterext.ZoneAwareDiscoveryFilter;
import org.apache.servicecomb.localregistry.LocalRegistryStore;
import org.apache.servicecomb.registry.DiscoveryManager;
import org.apache.servicecomb.registry.api.registry.DataCenterInfo;
@@ -62,8 +65,6 @@ import com.google.common.eventbus.Subscribe;
import mockit.Mock;
import mockit.MockUp;
-import static org.mockito.Mockito.when;
-
public class TestLoadBalanceHandler2 {
private Holder<Long> mockTimeMillis;
@@ -85,7 +86,7 @@ public class TestLoadBalanceHandler2 {
@Before
public void setUp() {
-
+ ArchaiusUtils.setProperty(ZoneAwareDiscoveryFilter.CONFIG_RATIO, 0);
// avoid mock
ServiceCombLoadBalancerStats.INSTANCE.init();
TestServiceCombServerStats.releaseTryingChance();
@@ -472,7 +473,8 @@ public class TestLoadBalanceHandler2 {
@Test
public void testZoneAwareAndIsolationFilterUsingMockedInvocationWorks() throws Exception {
- Invocation invocation = new NonSwaggerInvocation("testApp", "testMicroserviceName", "0.0.0+", (inv, aysnc) -> aysnc.success("OK"));
+ Invocation invocation = new NonSwaggerInvocation("testApp", "testMicroserviceName", "0.0.0+",
+ (inv, aysnc) -> aysnc.success("OK"));
InstanceCacheManager instanceCacheManager = Mockito.mock(InstanceCacheManager.class);
TransportManager transportManager = Mockito.mock(TransportManager.class);
@@ -602,7 +604,8 @@ public class TestLoadBalanceHandler2 {
public void testStatusFilterUsingMockedInvocationWorks() throws Exception {
ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.status.enabled", "false");
- Invocation invocation = new NonSwaggerInvocation("testApp", "testMicroserviceName", "0.0.0+", (inv, aysnc) -> aysnc.success("OK"));
+ Invocation invocation = new NonSwaggerInvocation("testApp", "testMicroserviceName", "0.0.0+",
+ (inv, aysnc) -> aysnc.success("OK"));
InstanceCacheManager instanceCacheManager = Mockito.mock(InstanceCacheManager.class);
TransportManager transportManager = Mockito.mock(TransportManager.class);
@@ -790,7 +793,8 @@ public class TestLoadBalanceHandler2 {
} catch (Exception e) {
}
- Assertions.assertEquals("rest://127.0.0.1:8080?sslEnabled=true&protocol=http2", invocation.getEndpoint().getEndpoint());
+ Assertions.assertEquals("rest://127.0.0.1:8080?sslEnabled=true&protocol=http2",
+ invocation.getEndpoint().getEndpoint());
// reset
invocation.setEndpoint(null);
diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filterext/TestZoneAwareDiscoveryFilter.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filterext/TestZoneAwareDiscoveryFilter.java
new file mode 100644
index 000000000..9d7e722ee
--- /dev/null
+++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/filterext/TestZoneAwareDiscoveryFilter.java
@@ -0,0 +1,193 @@
+/*
+ * 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.Arrays;
+import java.util.List;
+
+import org.apache.servicecomb.config.ConfigUtil;
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.core.Transport;
+import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
+import org.apache.servicecomb.loadbalance.ServiceCombServer;
+import org.apache.servicecomb.registry.RegistrationManager;
+import org.apache.servicecomb.registry.api.registry.DataCenterInfo;
+import org.apache.servicecomb.registry.api.registry.MicroserviceInstance;
+import org.apache.servicecomb.registry.cache.CacheEndpoint;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+public class TestZoneAwareDiscoveryFilter {
+ @BeforeEach
+ public void setUp() {
+ ConfigUtil.createLocalConfig();
+ }
+
+ @AfterEach
+ public void tearDown() {
+ ArchaiusUtils.resetConfig();
+ RegistrationManager.renewInstance();
+ }
+
+ @Test
+ public void test_not_enough_instance() {
+ ZoneAwareDiscoveryFilter filter = new ZoneAwareDiscoveryFilter();
+
+ // set up data
+ MicroserviceInstance myself = Mockito.mock(MicroserviceInstance.class);
+ RegistrationManager registrationManager = Mockito.mock(RegistrationManager.class);
+ Mockito.when(registrationManager.getMicroserviceInstance()).thenReturn(myself);
+ RegistrationManager.setINSTANCE(registrationManager);
+ DataCenterInfo myDcInfo = new DataCenterInfo();
+ myDcInfo.setName("test");
+ myDcInfo.setRegion("test-Region");
+ myDcInfo.setAvailableZone("test-zone");
+ Mockito.when(myself.getDataCenterInfo()).thenReturn(myDcInfo);
+
+ MicroserviceInstance discoveryInstance = Mockito.mock(MicroserviceInstance.class);
+ List<String> allMatchEndpoint = new ArrayList<>();
+ allMatchEndpoint.add("rest://localhost:9090");
+ Mockito.when(discoveryInstance.getEndpoints()).thenReturn(allMatchEndpoint);
+ CacheEndpoint allmatchCacheEndpoint = Mockito.mock(CacheEndpoint.class);
+ Mockito.when(allmatchCacheEndpoint.getEndpoint()).thenReturn("rest://localhost:9090");
+ Transport transport = Mockito.mock(Transport.class);
+ Mockito.when(allmatchCacheEndpoint.getInstance()).thenReturn(discoveryInstance);
+ ServiceCombServer allmatchInstance = new ServiceCombServer("test", transport, allmatchCacheEndpoint);
+ DataCenterInfo info = new DataCenterInfo();
+ info.setName("test");
+ info.setRegion("test-Region");
+ info.setAvailableZone("test-zone");
+ Mockito.when(discoveryInstance.getDataCenterInfo()).thenReturn(info);
+ Mockito.when(discoveryInstance.getInstanceId()).thenReturn("allmatchInstance");
+
+ MicroserviceInstance regionMatchDiscoveryInstance = Mockito.mock(MicroserviceInstance.class);
+ List<String> regionMatchEndpoint = new ArrayList<>();
+ regionMatchEndpoint.add("rest://localhost:9091");
+ Mockito.when(regionMatchDiscoveryInstance.getEndpoints()).thenReturn(regionMatchEndpoint);
+ CacheEndpoint regionMatchCacheEndpoint = Mockito.mock(CacheEndpoint.class);
+ Mockito.when(regionMatchCacheEndpoint.getEndpoint()).thenReturn("rest://localhost:9091");
+ Mockito.when(regionMatchCacheEndpoint.getInstance()).thenReturn(regionMatchDiscoveryInstance);
+ ServiceCombServer regionMatchInstance = new ServiceCombServer("test", transport, regionMatchCacheEndpoint);
+ DataCenterInfo regionMatchInfo = new DataCenterInfo();
+ regionMatchInfo.setName("test");
+ regionMatchInfo.setRegion("test-Region");
+ regionMatchInfo.setAvailableZone("test-zone2");
+ Mockito.when(regionMatchDiscoveryInstance.getDataCenterInfo()).thenReturn(regionMatchInfo);
+ Mockito.when(regionMatchDiscoveryInstance.getInstanceId()).thenReturn("regionMatchInstance");
+
+ MicroserviceInstance noneMatchDiscoveryInstance = Mockito.mock(MicroserviceInstance.class);
+ List<String> noMatchEndpoint = new ArrayList<>();
+ noMatchEndpoint.add("rest://localhost:9092");
+ Mockito.when(noneMatchDiscoveryInstance.getEndpoints()).thenReturn(noMatchEndpoint);
+ CacheEndpoint noneMatchCacheEndpoint = Mockito.mock(CacheEndpoint.class);
+ Mockito.when(noneMatchCacheEndpoint.getEndpoint()).thenReturn("rest://localhost:9092");
+ Mockito.when(noneMatchCacheEndpoint.getInstance()).thenReturn(noneMatchDiscoveryInstance);
+ ServiceCombServer noneMatchInstance = new ServiceCombServer("test", transport, noneMatchCacheEndpoint);
+ DataCenterInfo noneMatchInfo = new DataCenterInfo();
+ noneMatchInfo.setName("test");
+ noneMatchInfo.setRegion("test-Region2");
+ noneMatchInfo.setAvailableZone("test-zone2");
+ Mockito.when(noneMatchDiscoveryInstance.getDataCenterInfo()).thenReturn(noneMatchInfo);
+ Mockito.when(noneMatchDiscoveryInstance.getInstanceId()).thenReturn("noneMatchInstance");
+
+ // run test
+ Invocation invocation = Mockito.mock(Invocation.class);
+ List<ServiceCombServer> data = Arrays.asList(allmatchInstance, regionMatchInstance, noneMatchInstance);
+ List<ServiceCombServer> result = filter.getFilteredListOfServers(data, invocation);
+
+ // check result
+ Assertions.assertEquals(2, result.size());
+ Assertions.assertEquals("regionMatchInstance", result.get(0).getInstance().getInstanceId());
+ Assertions.assertEquals("allmatchInstance", result.get(1).getInstance().getInstanceId());
+ }
+
+ @Test
+ public void test_enough_instance() {
+ ArchaiusUtils.setProperty(ZoneAwareDiscoveryFilter.CONFIG_RATIO, 0);
+ ZoneAwareDiscoveryFilter filter = new ZoneAwareDiscoveryFilter();
+
+ // set up data
+ MicroserviceInstance myself = Mockito.mock(MicroserviceInstance.class);
+ RegistrationManager registrationManager = Mockito.mock(RegistrationManager.class);
+ Mockito.when(registrationManager.getMicroserviceInstance()).thenReturn(myself);
+ RegistrationManager.setINSTANCE(registrationManager);
+ DataCenterInfo myDcInfo = new DataCenterInfo();
+ myDcInfo.setName("test");
+ myDcInfo.setRegion("test-Region");
+ myDcInfo.setAvailableZone("test-zone");
+ Mockito.when(myself.getDataCenterInfo()).thenReturn(myDcInfo);
+
+ MicroserviceInstance discoveryInstance = Mockito.mock(MicroserviceInstance.class);
+ List<String> allMatchEndpoint = new ArrayList<>();
+ allMatchEndpoint.add("rest://localhost:9090");
+ Mockito.when(discoveryInstance.getEndpoints()).thenReturn(allMatchEndpoint);
+ CacheEndpoint allmatchCacheEndpoint = Mockito.mock(CacheEndpoint.class);
+ Mockito.when(allmatchCacheEndpoint.getEndpoint()).thenReturn("rest://localhost:9090");
+ Transport transport = Mockito.mock(Transport.class);
+ Mockito.when(allmatchCacheEndpoint.getInstance()).thenReturn(discoveryInstance);
+ ServiceCombServer allmatchInstance = new ServiceCombServer("test", transport, allmatchCacheEndpoint);
+ DataCenterInfo info = new DataCenterInfo();
+ info.setName("test");
+ info.setRegion("test-Region");
+ info.setAvailableZone("test-zone");
+ Mockito.when(discoveryInstance.getDataCenterInfo()).thenReturn(info);
+ Mockito.when(discoveryInstance.getInstanceId()).thenReturn("allmatchInstance");
+
+ MicroserviceInstance regionMatchDiscoveryInstance = Mockito.mock(MicroserviceInstance.class);
+ List<String> regionMatchEndpoint = new ArrayList<>();
+ regionMatchEndpoint.add("rest://localhost:9091");
+ Mockito.when(regionMatchDiscoveryInstance.getEndpoints()).thenReturn(regionMatchEndpoint);
+ CacheEndpoint regionMatchCacheEndpoint = Mockito.mock(CacheEndpoint.class);
+ Mockito.when(regionMatchCacheEndpoint.getEndpoint()).thenReturn("rest://localhost:9091");
+ Mockito.when(regionMatchCacheEndpoint.getInstance()).thenReturn(regionMatchDiscoveryInstance);
+ ServiceCombServer regionMatchInstance = new ServiceCombServer("test", transport, regionMatchCacheEndpoint);
+ DataCenterInfo regionMatchInfo = new DataCenterInfo();
+ regionMatchInfo.setName("test");
+ regionMatchInfo.setRegion("test-Region");
+ regionMatchInfo.setAvailableZone("test-zone2");
+ Mockito.when(regionMatchDiscoveryInstance.getDataCenterInfo()).thenReturn(regionMatchInfo);
+ Mockito.when(regionMatchDiscoveryInstance.getInstanceId()).thenReturn("regionMatchInstance");
+
+ MicroserviceInstance noneMatchDiscoveryInstance = Mockito.mock(MicroserviceInstance.class);
+ List<String> noMatchEndpoint = new ArrayList<>();
+ noMatchEndpoint.add("rest://localhost:9092");
+ Mockito.when(noneMatchDiscoveryInstance.getEndpoints()).thenReturn(noMatchEndpoint);
+ CacheEndpoint noneMatchCacheEndpoint = Mockito.mock(CacheEndpoint.class);
+ Mockito.when(noneMatchCacheEndpoint.getEndpoint()).thenReturn("rest://localhost:9092");
+ Mockito.when(noneMatchCacheEndpoint.getInstance()).thenReturn(noneMatchDiscoveryInstance);
+ ServiceCombServer noneMatchInstance = new ServiceCombServer("test", transport, noneMatchCacheEndpoint);
+ DataCenterInfo noneMatchInfo = new DataCenterInfo();
+ noneMatchInfo.setName("test");
+ noneMatchInfo.setRegion("test-Region2");
+ noneMatchInfo.setAvailableZone("test-zone2");
+ Mockito.when(noneMatchDiscoveryInstance.getDataCenterInfo()).thenReturn(noneMatchInfo);
+ Mockito.when(noneMatchDiscoveryInstance.getInstanceId()).thenReturn("noneMatchInstance");
+
+ // run test
+ Invocation invocation = Mockito.mock(Invocation.class);
+ List<ServiceCombServer> data = Arrays.asList(allmatchInstance, regionMatchInstance, noneMatchInstance);
+ List<ServiceCombServer> result = filter.getFilteredListOfServers(data, invocation);
+
+ // check result
+ Assertions.assertEquals(1, result.size());
+ Assertions.assertEquals("allmatchInstance", result.get(0).getInstance().getInstanceId());
+ }
+}