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/incubator-servicecomb-java-chassis.git

commit 5ad67e04fa299b1ee07f7783380885f76ced80b2
Author: liubao <[email protected]>
AuthorDate: Sat Aug 25 17:50:52 2018 +0800

    [SBC-870] change weights to Robin Weights and change algorithm
---
 .../servicecomb/loadbalance/LoadBalancer.java      |   5 +-
 .../loadbalance/LoadbalanceHandler.java            |   8 +-
 .../loadbalance/ServiceCombLoadBalancerStats.java  |  11 +-
 .../loadbalance/ServiceCombServerStats.java        |  19 +---
 .../loadbalance/WeightedResponseTimeRuleExt.java   |  76 +++++++++----
 .../loadbalance/TestLoadBalanceHandler2.java       |  16 +--
 .../loadbalance/TestRoundRobinRuleExt.java         |  76 +++++++++++++
 .../TestServiceCombLoadBalancerStats.java          |  18 +--
 .../loadbalance/TestServiceCombServerStats.java    |  22 ++--
 .../TestWeightedResponseTimeRuleExt.java           | 126 +++++++++++++++++++++
 10 files changed, 302 insertions(+), 75 deletions(-)

diff --git 
a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadBalancer.java
 
b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadBalancer.java
index 463ea19..bcc9fea 100644
--- 
a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadBalancer.java
+++ 
b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadBalancer.java
@@ -18,6 +18,7 @@
 package org.apache.servicecomb.loadbalance;
 
 import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
@@ -29,6 +30,8 @@ import com.netflix.loadbalancer.LoadBalancerStats;
  *  A load balancer with RuleExt and ServerListFilterExt
  */
 public class LoadBalancer {
+  private static AtomicInteger id = new AtomicInteger(0);
+
   private RuleExt rule;
 
   private LoadBalancerStats lbStats;
@@ -40,7 +43,7 @@ public class LoadBalancer {
   public LoadBalancer(RuleExt rule, String microServiceName) {
     this.microServiceName = microServiceName;
     this.rule = rule;
-    this.lbStats = new LoadBalancerStats(null);
+    this.lbStats = new LoadBalancerStats(microServiceName + 
id.getAndDecrement());
     // load new instances, because filters work on service information
     this.filters = 
SPIServiceUtils.loadSortedService(ServerListFilterExt.class);
     this.rule.setLoadBalancer(this);
diff --git 
a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadbalanceHandler.java
 
b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadbalanceHandler.java
index 30ee21b..95db713 100644
--- 
a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadbalanceHandler.java
+++ 
b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/LoadbalanceHandler.java
@@ -205,10 +205,10 @@ public class LoadbalanceHandler implements Handler {
       chosenLB.getLoadBalancerStats().noteResponseTime(server, 
(System.currentTimeMillis() - time));
       if (isFailedResponse(resp)) {
         
chosenLB.getLoadBalancerStats().incrementSuccessiveConnectionFailureCount(server);
-        ServiceCombLoadBalancerStats.INSTANCE.markFailure(server, 
System.currentTimeMillis() - time);
+        ServiceCombLoadBalancerStats.INSTANCE.markFailure(server);
       } else {
         chosenLB.getLoadBalancerStats().incrementActiveRequestsCount(server);
-        ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server, 
(System.currentTimeMillis() - time));
+        ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server);
       }
       asyncResp.handle(resp);
     });
@@ -315,13 +315,13 @@ public class LoadbalanceHandler implements Handler {
                     ((Throwable) resp.getResult()).getMessage(),
                     s);
                 
chosenLB.getLoadBalancerStats().incrementSuccessiveConnectionFailureCount(s);
-                ServiceCombLoadBalancerStats.INSTANCE.markFailure(server, 
System.currentTimeMillis() - time);
+                ServiceCombLoadBalancerStats.INSTANCE.markFailure(server);
                 f.onError(resp.getResult());
               } else {
                 
chosenLB.getLoadBalancerStats().incrementActiveRequestsCount(s);
                 chosenLB.getLoadBalancerStats().noteResponseTime(s,
                     (System.currentTimeMillis() - time));
-                ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server, 
(System.currentTimeMillis() - time));
+                ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server);
                 f.onNext(resp);
                 f.onCompleted();
               }
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 ac01152..ffde2d7 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
@@ -78,17 +78,17 @@ public class ServiceCombLoadBalancerStats {
     }
   }
 
-  public void markSuccess(ServiceCombServer server, long execTime) {
+  public void markSuccess(ServiceCombServer server) {
     try {
-      serverStatsCache.get(server).markSuccess(execTime);
+      serverStatsCache.get(server).markSuccess();
     } catch (ExecutionException e) {
       LOGGER.error("Not expected to happen, maybe a bug.", e);
     }
   }
 
-  public void markFailure(ServiceCombServer server, long execTime) {
+  public void markFailure(ServiceCombServer server) {
     try {
-      serverStatsCache.get(server).markFailure(execTime);
+      serverStatsCache.get(server).markFailure();
     } catch (ExecutionException e) {
       LOGGER.error("Not expected to happen, maybe a bug.", e);
     }
@@ -167,11 +167,10 @@ public class ServiceCombLoadBalancerStats {
           while (instances.hasNext()) {
             ServiceCombServer server = instances.next();
             ServiceCombServerStats stats = allServers.get(server);
-            long startTime = System.currentTimeMillis();
             if ((System.currentTimeMillis() - stats.getLastVisitTime() > 
timerIntervalInMilis) && !ping
                 .ping(server.getInstance())) {
               LOGGER.info("ping mark server {} failure.", 
server.getInstance().getInstanceId());
-              stats.markFailure(System.currentTimeMillis() - startTime);
+              stats.markFailure();
             }
           }
           serverStatsCache.cleanUp();
diff --git 
a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombServerStats.java
 
b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombServerStats.java
index 03b458e..b33771b 100644
--- 
a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombServerStats.java
+++ 
b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServiceCombServerStats.java
@@ -45,47 +45,33 @@ public class ServiceCombServerStats {
 
   private boolean isolated = false;
 
-  private long averageResponseTime = 0;
-
-  public long getAverageResponseTime() {
-    return averageResponseTime;
-  }
-
   public void markIsolated(boolean isolated) {
     this.isolated = isolated;
   }
 
-  public void markSuccess(long execTime) {
+  public void markSuccess() {
     long time = System.currentTimeMillis();
     ensureWindow(time);
     lastVisitTime = time;
     lastActiveTime = time;
-    updateAvgTime(execTime);
     totalRequests.incrementAndGet();
     successRequests.incrementAndGet();
     continuousFailureCount.set(0);
   }
 
-  public void markFailure(long execTime) {
+  public void markFailure() {
     long time = System.currentTimeMillis();
     ensureWindow(time);
     lastVisitTime = time;
 
     // when isolated, do not update any failure statistics, or we can not 
recover from failure very quickly
     if (!isolated) {
-      updateAvgTime(execTime);
       totalRequests.incrementAndGet();
       failedRequests.incrementAndGet();
       continuousFailureCount.incrementAndGet();
     }
   }
 
-  private void updateAvgTime(long execTime) {
-    // There maybe concurrent problems. But we do not care.
-    long total = totalRequests.get();
-    averageResponseTime = (averageResponseTime * total + execTime) / (total + 
1);
-  }
-
   private void ensureWindow(long time) {
     if (time - lastWindow > TIME_WINDOW_IN_MILLISECONDS) {
       synchronized (lock) {
@@ -95,7 +81,6 @@ public class ServiceCombServerStats {
             totalRequests.set(0);
             successRequests.set(0);
             failedRequests.set(0);
-            averageResponseTime = 0;
           }
           lastWindow = time;
         }
diff --git 
a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/WeightedResponseTimeRuleExt.java
 
b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/WeightedResponseTimeRuleExt.java
index 06aba4f..529c0a3 100644
--- 
a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/WeightedResponseTimeRuleExt.java
+++ 
b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/WeightedResponseTimeRuleExt.java
@@ -20,46 +20,84 @@ package org.apache.servicecomb.loadbalance;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Random;
-import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.servicecomb.core.Invocation;
 
+import com.netflix.loadbalancer.ServerStats;
+
 /**
  * Rule based on response time.
  */
 public class WeightedResponseTimeRuleExt extends RoundRobinRuleExt {
   // 10ms
-  private static final int MIN_GAP = 10;
+  private static final double MIN_GAP = 10d;
+
+  private static final int RANDOM_PERCENT = 10;
 
   private Random random = new Random();
 
+  private LoadBalancer loadBalancer;
+
+  private double totalWeightsCache = 0d;
+
+  @Override
+  public void setLoadBalancer(LoadBalancer loadBalancer) {
+    this.loadBalancer = loadBalancer;
+  }
+
   @Override
   public ServiceCombServer choose(List<ServiceCombServer> servers, Invocation 
invocation) {
-    List<AtomicInteger> stats = new ArrayList<>(servers.size());
-    int totalWeights = 0;
+    List<Double> stats = calculateTotalWeights(servers);
+
+    if (stats.size() > 0) {
+      double finalTotal = stats.get(stats.size() - 1);
+      List<Double> weights = new ArrayList<>(servers.size());
+      for (int i = 0; i < stats.size() - 1; i++) {
+        weights.add(finalTotal - stats.get(i));
+      }
+      double ran = random.nextDouble() * finalTotal * (servers.size() - 1);
+      for (int i = 0; i < weights.size(); i++) {
+        ran -= weights.get(i);
+        if (ran < 0) {
+          return servers.get(i);
+        }
+      }
+      return servers.get(servers.size() - 1);
+    }
+    return super.choose(servers, invocation);
+  }
+
+  private List<Double> calculateTotalWeights(List<ServiceCombServer> servers) {
+    if (totalWeightsCache > MIN_GAP * servers.size()) {
+      return doCalculateTotalWeights(servers);
+    }
+    // 10% possibilities to use weighed response rule when the normal access 
is very fast.
+    if (random.nextInt(RANDOM_PERCENT) == 0) {
+      return doCalculateTotalWeights(servers);
+    } else {
+      return new ArrayList<>();
+    }
+  }
+
+  private List<Double> doCalculateTotalWeights(List<ServiceCombServer> 
servers) {
+    List<Double> stats = new ArrayList<>(servers.size() + 1);
+    double totalWeights = 0;
     boolean needRandom = false;
     for (ServiceCombServer server : servers) {
-      ServiceCombServerStats serverStats = 
ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(server);
-      int avgTime = (int) serverStats.getAverageResponseTime();
+      ServerStats serverStats = 
loadBalancer.getLoadBalancerStats().getSingleServerStat(server);
+      double avgTime = serverStats.getResponseTimeAvg();
       if (!needRandom && avgTime > MIN_GAP) {
         needRandom = true;
       }
       totalWeights += avgTime;
-      stats.add(new AtomicInteger(avgTime));
+      stats.add(avgTime);
     }
-
+    stats.add(totalWeights);
+    totalWeightsCache = totalWeights;
     if (needRandom) {
-      int finalTotal = totalWeights;
-      stats.forEach(item -> item.set(finalTotal - item.get()));
-      int ran = random
-          .nextInt(Math.max(totalWeights * stats.size() - totalWeights, 1));
-      for (int i = 0; i < stats.size(); i++) {
-        ran -= stats.get(i).get();
-        if (ran < 0) {
-          return servers.get(i);
-        }
-      }
+      return stats;
+    } else {
+      return new ArrayList<>();
     }
-    return super.choose(servers, invocation);
   }
 }
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 3dbfa32..276e454 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
@@ -163,11 +163,11 @@ public class TestLoadBalanceHandler2 {
     server = (ServiceCombServer) loadBalancer.chooseServer(invocation);
     Assert.assertEquals(server.getEndpoint().getEndpoint(), 
"rest://localhost:9090");
 
-    ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server, 0);
-    ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server, 0);
-    ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server, 0);
-    ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server, 0);
-    ServiceCombLoadBalancerStats.INSTANCE.markFailure(server, 0);
+    ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server);
+    ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server);
+    ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server);
+    ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server);
+    ServiceCombLoadBalancerStats.INSTANCE.markFailure(server);
 
     //if errorThresholdPercentage is 0,that means errorThresholdPercentage is 
not active.
     
ArchaiusUtils.setProperty("servicecomb.loadbalance.isolation.errorThresholdPercentage",
 "0");
@@ -181,12 +181,12 @@ public class TestLoadBalanceHandler2 {
     loadBalancer = handler.getOrCreateLoadBalancer(invocation);
     server = (ServiceCombServer) loadBalancer.chooseServer(invocation);
     Assert.assertEquals(server.getEndpoint().getEndpoint(), 
"rest://localhost:9091");
-    ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server2, 0);
+    ServiceCombLoadBalancerStats.INSTANCE.markSuccess(server2);
     loadBalancer = handler.getOrCreateLoadBalancer(invocation);
     server = (ServiceCombServer) loadBalancer.chooseServer(invocation);
     Assert.assertEquals(server.getEndpoint().getEndpoint(), 
"rest://localhost:9090");
-    ServiceCombLoadBalancerStats.INSTANCE.markFailure(server2, 0);
-    ServiceCombLoadBalancerStats.INSTANCE.markFailure(server2, 0);
+    ServiceCombLoadBalancerStats.INSTANCE.markFailure(server2);
+    ServiceCombLoadBalancerStats.INSTANCE.markFailure(server2);
     loadBalancer = handler.getOrCreateLoadBalancer(invocation);
     server = (ServiceCombServer) loadBalancer.chooseServer(invocation);
     Assert.assertEquals(server.getEndpoint().getEndpoint(), 
"rest://localhost:9091");
diff --git 
a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestRoundRobinRuleExt.java
 
b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestRoundRobinRuleExt.java
new file mode 100644
index 0000000..d80f17c
--- /dev/null
+++ 
b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestRoundRobinRuleExt.java
@@ -0,0 +1,76 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.servicecomb.core.Invocation;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class TestRoundRobinRuleExt {
+  @Test
+  public void testRoundRobin() {
+    RoundRobinRuleExt rule = new RoundRobinRuleExt();
+    LoadBalancer loadBalancer = new LoadBalancer(rule, "testService");
+    List<ServiceCombServer> servers = new ArrayList<>();
+    Invocation invocation = Mockito.mock(Invocation.class);
+    for (int i = 0; i < 2; i++) {
+      ServiceCombServer server = Mockito.mock(ServiceCombServer.class);
+      Mockito.when(server.toString()).thenReturn("server " + i);
+      servers.add(server);
+      loadBalancer.getLoadBalancerStats().noteResponseTime(server, 1);
+    }
+
+    AtomicInteger server1 = new AtomicInteger(0);
+    AtomicInteger server2 = new AtomicInteger(0);
+    for (int i = 0; i < 2000; i++) {
+      if (rule.choose(servers, invocation).toString().equals("server 0")) {
+        server1.incrementAndGet();
+      } else {
+        server2.incrementAndGet();
+      }
+    }
+    Assert.assertEquals(server1.get(), server2.get());
+  }
+
+  @Test
+  public void testBenchmarkRobin() {
+    // less than 0.001ms
+    RoundRobinRuleExt rule = new RoundRobinRuleExt();
+    LoadBalancer loadBalancer = new LoadBalancer(rule, "testService");
+    List<ServiceCombServer> servers = new ArrayList<>();
+    Invocation invocation = Mockito.mock(Invocation.class);
+    for (int i = 0; i < 100; i++) {
+      ServiceCombServer server = Mockito.mock(ServiceCombServer.class);
+      Mockito.when(server.toString()).thenReturn("server " + i);
+      servers.add(server);
+      loadBalancer.getLoadBalancerStats().noteResponseTime(server, 2);
+    }
+    long begin = System.currentTimeMillis();
+    for (int i = 0; i < 10000; i++) {
+      rule.choose(servers, invocation);
+    }
+    long taken = System.currentTimeMillis() - begin;
+    System.out.println("taken " + taken);
+    Assert.assertEquals(taken < 10 * 2, true);  // 2 * times make slow machine 
happy
+  }
+}
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 23352c8..fb88452 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
@@ -64,7 +64,7 @@ public class TestServiceCombLoadBalancerStats {
 
     ServiceCombServer serviceCombServer = new ServiceCombServer(transport,
         new CacheEndpoint("rest://localhost:8080", instance));
-    serviceCombLoadBalancerStats.markSuccess(serviceCombServer, 0);
+    serviceCombLoadBalancerStats.markSuccess(serviceCombServer);
     ServiceCombServerStats stats = 
serviceCombLoadBalancerStats.getServiceCombServerStats(serviceCombServer);
     Assert.assertEquals(serviceCombLoadBalancerStats.getPingView().size(), 1);
     await().atMost(5, TimeUnit.SECONDS)
@@ -83,16 +83,16 @@ public class TestServiceCombLoadBalancerStats {
     instance.setInstanceId("instance1");
     ServiceCombServer serviceCombServer = new ServiceCombServer(transport,
         new CacheEndpoint("rest://localhost:8080", instance));
-    ServiceCombLoadBalancerStats.INSTANCE.markFailure(serviceCombServer, 0);
-    ServiceCombLoadBalancerStats.INSTANCE.markFailure(serviceCombServer, 0);
+    ServiceCombLoadBalancerStats.INSTANCE.markFailure(serviceCombServer);
+    ServiceCombLoadBalancerStats.INSTANCE.markFailure(serviceCombServer);
     Assert.assertEquals(
         
ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getCountinuousFailureCount(),
         2);
-    ServiceCombLoadBalancerStats.INSTANCE.markSuccess(serviceCombServer, 0);
+    ServiceCombLoadBalancerStats.INSTANCE.markSuccess(serviceCombServer);
     Assert.assertEquals(
         
ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getCountinuousFailureCount(),
         0);
-    ServiceCombLoadBalancerStats.INSTANCE.markSuccess(serviceCombServer, 0);
+    ServiceCombLoadBalancerStats.INSTANCE.markSuccess(serviceCombServer);
     Assert
         .assertEquals(
             
ServiceCombLoadBalancerStats.INSTANCE.getServiceCombServerStats(serviceCombServer).getTotalRequests(),
 4);
@@ -119,10 +119,10 @@ public class TestServiceCombLoadBalancerStats {
     for (int i = 0; i < 10; i++) {
       new Thread() {
         public void run() {
-          ServiceCombLoadBalancerStats.INSTANCE.markFailure(serviceCombServer, 
0);
-          ServiceCombLoadBalancerStats.INSTANCE.markFailure(serviceCombServer, 
0);
-          ServiceCombLoadBalancerStats.INSTANCE.markSuccess(serviceCombServer, 
0);
-          ServiceCombLoadBalancerStats.INSTANCE.markSuccess(serviceCombServer, 
0);
+          ServiceCombLoadBalancerStats.INSTANCE.markFailure(serviceCombServer);
+          ServiceCombLoadBalancerStats.INSTANCE.markFailure(serviceCombServer);
+          ServiceCombLoadBalancerStats.INSTANCE.markSuccess(serviceCombServer);
+          ServiceCombLoadBalancerStats.INSTANCE.markSuccess(serviceCombServer);
           latch.countDown();
         }
       }.start();
diff --git 
a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombServerStats.java
 
b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombServerStats.java
index 3fda339..3010368 100644
--- 
a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombServerStats.java
+++ 
b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestServiceCombServerStats.java
@@ -31,12 +31,12 @@ public class TestServiceCombServerStats {
   public void testSimpleThread() {
     long time = System.currentTimeMillis();
     ServiceCombServerStats stats = new ServiceCombServerStats();
-    stats.markFailure(0);
-    stats.markFailure(0);
+    stats.markFailure();
+    stats.markFailure();
     Assert.assertEquals(stats.getCountinuousFailureCount(), 2);
-    stats.markSuccess(0);
+    stats.markSuccess();
     Assert.assertEquals(stats.getCountinuousFailureCount(), 0);
-    stats.markSuccess(0);
+    stats.markSuccess();
     Assert.assertEquals(stats.getTotalRequests(), 4);
     Assert.assertEquals(stats.getFailedRate(), 50);
     Assert.assertEquals(stats.getSuccessRate(), 50);
@@ -52,10 +52,10 @@ public class TestServiceCombServerStats {
     for (int i = 0; i < 10; i++) {
       new Thread() {
         public void run() {
-          stats.markFailure(0);
-          stats.markFailure(0);
-          stats.markSuccess(0);
-          stats.markSuccess(0);
+          stats.markFailure();
+          stats.markFailure();
+          stats.markSuccess();
+          stats.markSuccess();
           latch.countDown();
         }
       }.start();
@@ -78,8 +78,8 @@ public class TestServiceCombServerStats {
     };
     ServiceCombServerStats stats = new ServiceCombServerStats();
     Assert.assertEquals(stats.getLastVisitTime(), 1000);
-    stats.markSuccess(0);
-    stats.markFailure(0);
+    stats.markSuccess();
+    stats.markFailure();
     Assert.assertEquals(stats.getTotalRequests(), 2);
     Assert.assertEquals(stats.getFailedRate(), 50);
     Assert.assertEquals(stats.getSuccessRate(), 50);
@@ -89,7 +89,7 @@ public class TestServiceCombServerStats {
         return 60000 + 2000;
       }
     };
-    stats.markSuccess(0);
+    stats.markSuccess();
     Assert.assertEquals(stats.getTotalRequests(), 1);
     Assert.assertEquals(stats.getFailedRate(), 0);
     Assert.assertEquals(stats.getSuccessRate(), 100);
diff --git 
a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestWeightedResponseTimeRuleExt.java
 
b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestWeightedResponseTimeRuleExt.java
new file mode 100644
index 0000000..54e1663
--- /dev/null
+++ 
b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestWeightedResponseTimeRuleExt.java
@@ -0,0 +1,126 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.servicecomb.core.Invocation;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class TestWeightedResponseTimeRuleExt {
+  @Test
+  public void testRoundRobin() {
+    WeightedResponseTimeRuleExt rule = new WeightedResponseTimeRuleExt();
+    LoadBalancer loadBalancer = new LoadBalancer(rule, "testService");
+    List<ServiceCombServer> servers = new ArrayList<>();
+    Invocation invocation = Mockito.mock(Invocation.class);
+    for (int i = 0; i < 2; i++) {
+      ServiceCombServer server = Mockito.mock(ServiceCombServer.class);
+      Mockito.when(server.toString()).thenReturn("server " + i);
+      servers.add(server);
+      loadBalancer.getLoadBalancerStats().noteResponseTime(server, 1);
+    }
+
+    AtomicInteger server1 = new AtomicInteger(0);
+    AtomicInteger server2 = new AtomicInteger(0);
+    for (int i = 0; i < 2000; i++) {
+      if (rule.choose(servers, invocation).toString().equals("server 0")) {
+        server1.incrementAndGet();
+      } else {
+        server2.incrementAndGet();
+      }
+    }
+    Assert.assertEquals(server1.get(), server2.get());
+  }
+
+  @Test
+  public void testWeighed() {
+    WeightedResponseTimeRuleExt rule = new WeightedResponseTimeRuleExt();
+    LoadBalancer loadBalancer = new LoadBalancer(rule, "testService");
+    List<ServiceCombServer> servers = new ArrayList<>();
+    Invocation invocation = Mockito.mock(Invocation.class);
+    for (int i = 0; i < 2; i++) {
+      ServiceCombServer server = Mockito.mock(ServiceCombServer.class);
+      Mockito.when(server.toString()).thenReturn("server " + i);
+      servers.add(server);
+      loadBalancer.getLoadBalancerStats().noteResponseTime(server, 20 * 
Math.pow(4, i + 1));
+    }
+
+    AtomicInteger server1 = new AtomicInteger(0);
+    AtomicInteger server2 = new AtomicInteger(0);
+    for (int i = 0; i < 2000; i++) {
+      if (rule.choose(servers, invocation).toString().equals("server 0")) {
+        server1.incrementAndGet();
+      } else {
+        server2.incrementAndGet();
+      }
+    }
+    double percent = (double) server1.get() / (server2.get() + server1.get());
+    System.out.println("percent" + percent);
+    Assert.assertEquals(0.70d < percent, percent < 0.90d);
+  }
+
+  @Test
+  public void testBenchmark() {
+    // 100 instances will taken less than 0.1ms. Because we use weighed rule 
when response time more than 10ms,
+    // This only taken 1/1000 time.
+    WeightedResponseTimeRuleExt rule = new WeightedResponseTimeRuleExt();
+    LoadBalancer loadBalancer = new LoadBalancer(rule, "testService");
+    List<ServiceCombServer> servers = new ArrayList<>();
+    Invocation invocation = Mockito.mock(Invocation.class);
+    for (int i = 0; i < 100; i++) {
+      ServiceCombServer server = Mockito.mock(ServiceCombServer.class);
+      Mockito.when(server.toString()).thenReturn("server " + i);
+      servers.add(server);
+      loadBalancer.getLoadBalancerStats().noteResponseTime(server, i);
+    }
+    long begin = System.currentTimeMillis();
+    for (int i = 0; i < 10000; i++) {
+      rule.choose(servers, invocation);
+    }
+    long taken = System.currentTimeMillis() - begin;
+    System.out.println("taken " + taken);
+    Assert.assertEquals(taken < 1000 * 2, true); // 2 * times make slow 
machine happy
+  }
+
+  @Test
+  public void testBenchmarkRobin() {
+    // 100 instances will taken less than 0.02ms. Not as good as 
RoundRobinRule, which taken less than 0.001ms
+    WeightedResponseTimeRuleExt rule = new WeightedResponseTimeRuleExt();
+    LoadBalancer loadBalancer = new LoadBalancer(rule, "testService");
+    List<ServiceCombServer> servers = new ArrayList<>();
+    Invocation invocation = Mockito.mock(Invocation.class);
+    for (int i = 0; i < 100; i++) {
+      ServiceCombServer server = Mockito.mock(ServiceCombServer.class);
+      Mockito.when(server.toString()).thenReturn("server " + i);
+      servers.add(server);
+      loadBalancer.getLoadBalancerStats().noteResponseTime(server, 2);
+    }
+    long begin = System.currentTimeMillis();
+    for (int i = 0; i < 10000; i++) {
+      rule.choose(servers, invocation);
+    }
+    long taken = System.currentTimeMillis() - begin;
+    System.out.println("taken " + taken);
+    Assert.assertEquals(taken < 200 * 2, true); // 2 * times make slow machine 
happy
+  }
+}

Reply via email to