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 b87a06977 [perf]When a microservice instance is isolated and taken
offline, reduce unnecessary network communication (#4747)
b87a06977 is described below
commit b87a069779a8f1af706c42f87df6b64fe17e65e9
Author: singleo <[email protected]>
AuthorDate: Wed Apr 2 17:16:54 2025 +0800
[perf]When a microservice instance is isolated and taken offline, reduce
unnecessary network communication (#4747)
---
.../registry/consumer/MicroserviceVersions.java | 4 +
.../loadbalance/ServiceCombLoadBalancerStats.java | 29 +++++-
.../TestServiceCombLoadBalancerStats.java | 101 +++++++++++++++++++--
3 files changed, 123 insertions(+), 11 deletions(-)
diff --git
a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/consumer/MicroserviceVersions.java
b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/consumer/MicroserviceVersions.java
index 99bc20219..c84925a47 100644
---
a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/consumer/MicroserviceVersions.java
+++
b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/consumer/MicroserviceVersions.java
@@ -148,6 +148,10 @@ public class MicroserviceVersions {
return pulledInstances;
}
+ public List<MicroserviceInstance> getInstances() {
+ return new ArrayList<MicroserviceInstance>(instances);
+ }
+
public long getLastPullTime() {
return lastPullTime;
}
diff --git
a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombLoadBalancerStats.java
b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombLoadBalancerStats.java
index 0b99139c3..2f23a6f7e 100644
---
a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombLoadBalancerStats.java
+++
b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombLoadBalancerStats.java
@@ -17,6 +17,7 @@
package org.apache.servicecomb.loadbalance;
+import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
@@ -27,6 +28,11 @@ import java.util.concurrent.TimeUnit;
import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
import org.apache.servicecomb.registry.api.registry.MicroserviceInstance;
import org.apache.servicecomb.registry.consumer.MicroserviceInstancePing;
+import org.apache.servicecomb.registry.DiscoveryManager;
+import org.apache.servicecomb.registry.RegistrationManager;
+import org.apache.servicecomb.registry.consumer.MicroserviceVersions;
+
+import org.apache.servicecomb.registry.definition.MicroserviceNameParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -157,17 +163,30 @@ public class ServiceCombLoadBalancerStats {
timer = new Timer("LoadBalancerStatsTimer", true);
timer.schedule(new TimerTask() {
- private final MicroserviceInstancePing ping =
SPIServiceUtils.getPriorityHighestService(MicroserviceInstancePing.class);
+ private final MicroserviceInstancePing ping = SPIServiceUtils
+ .getPriorityHighestService(MicroserviceInstancePing.class);
@Override
public void run() {
try {
Map<ServiceCombServer, ServiceCombServerStats> allServers = pingView;
allServers.forEach((server, stats) -> {
- if ((System.currentTimeMillis() - stats.getLastVisitTime() >
timerIntervalInMillis) && !ping
- .ping(server.getInstance())) {
- LOGGER.info("ping mark server {} failure.",
server.getInstance().getInstanceId());
- stats.markFailure();
+ //get all microservice instances
+ MicroserviceVersions microserviceVersions =
DiscoveryManager.INSTANCE.getOrCreateMicroserviceVersions(
+ new
MicroserviceNameParser(RegistrationManager.INSTANCE.getAppId(),
server.getMicroserviceName())
+ .getAppId(), server.getMicroserviceName());
+ List<MicroserviceInstance> microserviceInstanceList =
microserviceVersions.getInstances();
+ for (MicroserviceInstance instance : microserviceInstanceList) {
+ //check if the instance still up
+ if
(server.getInstance().getInstanceId().equals(instance.getInstanceId())) {
+ //check test interval
+ if ((System.currentTimeMillis() - stats.getLastVisitTime() >
timerIntervalInMillis)
+ && !ping.ping(server.getInstance())) {
+ LOGGER.info("ping mark server {} failure.",
server.getInstance().getInstanceId());
+ stats.markFailure();
+ }
+ break;
+ }
}
});
serverStatsCache.cleanUp();
diff --git
a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombLoadBalancerStats.java
b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombLoadBalancerStats.java
index c3172b1a6..a16bf1c31 100644
---
a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombLoadBalancerStats.java
+++
b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombLoadBalancerStats.java
@@ -17,27 +17,39 @@
package org.apache.servicecomb.loadbalance;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import mockit.Deencapsulation;
+import mockit.Expectations;
+import mockit.Injectable;
+import mockit.Mock;
+import mockit.MockUp;
+import mockit.Mocked;
+
import org.apache.servicecomb.core.Transport;
import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
+import org.apache.servicecomb.registry.DiscoveryManager;
+import org.apache.servicecomb.registry.RegistrationManager;
import org.apache.servicecomb.registry.api.registry.MicroserviceInstance;
import org.apache.servicecomb.registry.cache.CacheEndpoint;
+import org.apache.servicecomb.registry.consumer.AppManager;
import org.apache.servicecomb.registry.consumer.MicroserviceInstancePing;
+import org.apache.servicecomb.registry.consumer.MicroserviceVersions;
import org.awaitility.Awaitility;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
-import mockit.Deencapsulation;
-import mockit.Expectations;
-import mockit.Injectable;
-import mockit.Mocked;
import org.junit.jupiter.api.Assertions;
public class TestServiceCombLoadBalancerStats {
+
+ List<MicroserviceInstance> instanceList = new ArrayList<>();
+
@Before
public void before() {
// Ensure clean all of mocked server cache before running testMultiThread
@@ -46,6 +58,33 @@ public class TestServiceCombLoadBalancerStats {
Deencapsulation.getField(ServiceCombLoadBalancerStats.INSTANCE,
"pingView");
pingView.clear();
ServiceCombLoadBalancerStats.INSTANCE.init();
+ MicroserviceInstance instance1 = new MicroserviceInstance();
+ instance1.setInstanceId("instance1");
+ instanceList.add(instance1);
+ MicroserviceInstance instance2 = new MicroserviceInstance();
+ instance2.setInstanceId("instance2");
+ instanceList.add(instance2);
+ MockUp mockUpRegistrationManager = new MockUp<RegistrationManager>() {
+ @Mock
+ public String getAppId() {
+ return "test_app";
+ }
+ };
+ MockUp mockUpMicroserviceVersions = new MockUp<MicroserviceVersions>() {
+ @Mock
+ public List<MicroserviceInstance> getInstances() {
+ return instanceList;
+ }
+ };
+ AppManager appManager = new AppManager();
+ MicroserviceVersions microserviceVersions = new
MicroserviceVersions(appManager, "test_app", "test_microservice");
+ MockUp mockUpDiscoveryManager = new MockUp<DiscoveryManager>() {
+
+ @Mock
+ public MicroserviceVersions getOrCreateMicroserviceVersions(String
appId, String microserviceName) {
+ return microserviceVersions;
+ }
+ };
}
@AfterClass
@@ -76,7 +115,7 @@ public class TestServiceCombLoadBalancerStats {
serviceCombLoadBalancerStats.setTimerIntervalInMillis(500);
serviceCombLoadBalancerStats.init();
- ServiceCombServer serviceCombServer = new ServiceCombServer(null,
transport,
+ ServiceCombServer serviceCombServer = new
ServiceCombServer("test_microservice", transport,
new CacheEndpoint("rest://localhost:8080", instance));
serviceCombLoadBalancerStats.markSuccess(serviceCombServer);
ServiceCombServerStats stats =
serviceCombLoadBalancerStats.getServiceCombServerStats(serviceCombServer);
@@ -124,7 +163,7 @@ public class TestServiceCombLoadBalancerStats {
long time = System.currentTimeMillis();
MicroserviceInstance instance = new MicroserviceInstance();
instance.setInstanceId("instance2");
- ServiceCombServer serviceCombServer = new ServiceCombServer(null,
transport,
+ ServiceCombServer serviceCombServer = new
ServiceCombServer("test_microservice", transport,
new CacheEndpoint("rest://localhost:8080", instance));
CountDownLatch latch = new CountDownLatch(10);
@@ -171,4 +210,54 @@ public class TestServiceCombLoadBalancerStats {
ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getFailedRequests()
> 20);
}
+
+ @Test
+ public void testMultiThread2(@Injectable Transport transport) throws
Exception {
+ long time = System.currentTimeMillis();
+ MicroserviceInstance instance = new MicroserviceInstance();
+ instance.setInstanceId("instance2");
+ //clear instances to mock instance2 down in cse
+ instanceList.clear();
+ ServiceCombServer serviceCombServer = new
ServiceCombServer("test_microservice", transport,
+ new CacheEndpoint("rest://localhost:8080", instance));
+
+ CountDownLatch latch = new CountDownLatch(10);
+ for (int i = 0; i < 10; i++) {
+ new Thread(() -> {
+ ServiceCombLoadBalancerStats.INSTANCE.markFailure(serviceCombServer);
+ ServiceCombLoadBalancerStats.INSTANCE.markFailure(serviceCombServer);
+ ServiceCombLoadBalancerStats.INSTANCE.markSuccess(serviceCombServer);
+ ServiceCombLoadBalancerStats.INSTANCE.markSuccess(serviceCombServer);
+ latch.countDown();
+ }).start();
+ }
+ latch.await(30, TimeUnit.SECONDS);
+ Assertions.assertEquals(
+
ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getTotalRequests(),
+ 4 * 10);
+ Assertions.assertEquals(
+
ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getFailedRate(),
50);
+ Assertions.assertEquals(
+
ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getSuccessRate(),
50);
+ Assertions.assertEquals(
+
ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getSuccessRequests(),
20);
+ Assertions.assertTrue(
+
ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getLastVisitTime()
<= System
+ .currentTimeMillis()
+ &&
ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getLastVisitTime()
+ >= time);
+
+ // time consuming test for timers, taking about 20 seconds. ping timer
will not update instance status because instance2 is out of up instances
+ Assertions.assertTrue(
+
ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getFailedRate()
<= 50);
+ long beginTime = System.currentTimeMillis();
+ long rate =
ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getFailedRequests();
+ while (System.currentTimeMillis() - beginTime <= 22000) {
+ Thread.sleep(2000);
+ System.out.println("failedRequests: " + rate);
+ }
+
+ Assertions.assertEquals(20,
+
ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getFailedRequests());
+ }
}