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());
+  }
 }

Reply via email to