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 2025/04/02 09:16:59 UTC
(servicecomb-java-chassis) branch 2.8.x updated: [perf]When a microservice instance is isolated and taken offline, reduce unnecessary network communication (#4747)
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 <69...@users.noreply.github.com>
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());
+ }
}