From 3cd16f678f4b0abbdad42afa109d9257488e8f58 Mon Sep 17 00:00:00 2001 From: chengyouling Date: Thu, 14 Nov 2024 11:35:53 +0800 Subject: [PATCH 01/16] [#4598] Supports traffic warm-up when the service is just started --- .../src/main/resources/application.yml | 4 + .../src/main/resources/application.yml | 4 + .../servicecomb/samples/HelloWorldIT.java | 22 +++ .../loadbalance/ServerListFilterExt.java | 6 + .../filterext/WarmUpDiscoveryFilter.java | 134 ++++++++++++++++++ ...ervicecomb.loadbalance.ServerListFilterExt | 3 +- 6 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java diff --git a/demo/demo-cse-v1/provider-canary/src/main/resources/application.yml b/demo/demo-cse-v1/provider-canary/src/main/resources/application.yml index 81bf7aaffb7..f287d6f61b4 100644 --- a/demo/demo-cse-v1/provider-canary/src/main/resources/application.yml +++ b/demo/demo-cse-v1/provider-canary/src/main/resources/application.yml @@ -19,6 +19,10 @@ servicecomb-config-order: 10 servicecomb: + instance: + properties: + warmupTime: 60 + warmupCurve: 2 service: application: demo-java-chassis-cse-v1 name: provider diff --git a/demo/demo-cse-v1/provider/src/main/resources/application.yml b/demo/demo-cse-v1/provider/src/main/resources/application.yml index 370c3cd975e..1570e1a0ad5 100644 --- a/demo/demo-cse-v1/provider/src/main/resources/application.yml +++ b/demo/demo-cse-v1/provider/src/main/resources/application.yml @@ -19,6 +19,10 @@ servicecomb-config-order: 10 servicecomb: + instance: + properties: + warmupTime: 30 + warmupCurve: 2 service: application: demo-java-chassis-cse-v1 name: provider diff --git a/demo/demo-cse-v1/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java b/demo/demo-cse-v1/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java index e0f4d3d6610..b0585a908ef 100644 --- a/demo/demo-cse-v1/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java +++ b/demo/demo-cse-v1/test-client/src/main/java/org/apache/servicecomb/samples/HelloWorldIT.java @@ -41,6 +41,7 @@ public void testRestTransport() throws Exception { testHelloWorldeEptyProtectionCloseWeightLess100(); testHelloWorldEmptyProtectionCloseFallback(); testHelloWorldEmptyProtectionCloseWeight100Two(); + testHelloWorldWarmUp(); } private void testHelloWorld() { @@ -200,4 +201,25 @@ private void testHelloWorldEmptyProtectionCloseWeight100Two() { TestMgr.check(failCount == succCount, true); } + + private void testHelloWorldWarmUp() throws InterruptedException { + int oldCount = 0; + int newCount = 0; + + for (int i = 0; i < 100; i++) { + String result = template + .getForObject(Config.GATEWAY_URL + "/sayHello?name=World", String.class); + Thread.sleep(1000); + if (result.equals("\"Hello World\"")) { + oldCount++; + } else if (result.equals("\"Hello in canary World\"")) { + newCount++; + } else { + TestMgr.fail("not expected result testHelloWorldCanary"); + return; + } + } + + TestMgr.check(oldCount > newCount, true); + } } diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServerListFilterExt.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServerListFilterExt.java index 002bb3a92a7..3e574db16eb 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServerListFilterExt.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServerListFilterExt.java @@ -17,6 +17,8 @@ package org.apache.servicecomb.loadbalance; +import io.swagger.models.auth.In; + import java.util.List; import org.apache.servicecomb.core.Invocation; @@ -34,12 +36,16 @@ public interface ServerListFilterExt { int ORDER_ZONE_AWARE = 200; + int ORDER_WARM_UP = Integer.MAX_VALUE; + String EMPTY_INSTANCE_PROTECTION = "servicecomb.loadbalance.filter.isolation.emptyInstanceProtectionEnabled"; String ISOLATION_FILTER_ENABLED = "servicecomb.loadbalance.filter.isolation.enabled"; String ZONE_AWARE_FILTER_ENABLED = "servicecomb.loadbalance.filter.zoneaware.enabled"; + String WARM_UP_FILTER_ENABLED = "servicecomb.loadbalance.filter.service.warmup.enabled"; + default int getOrder() { return ORDER_NORMAL; } diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java new file mode 100644 index 00000000000..4b8ccf2f3a2 --- /dev/null +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java @@ -0,0 +1,134 @@ +/* + * 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 com.netflix.config.DynamicPropertyFactory; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.loadbalance.ServerListFilterExt; +import org.apache.servicecomb.loadbalance.ServiceCombServer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Random; + +public class WarmUpDiscoveryFilter implements ServerListFilterExt { + private static final Logger LOGGER = LoggerFactory.getLogger(WarmUpDiscoveryFilter.class); + + private static final int INSTANCE_WEIGHT = 100; + + // Default time for warm up, the unit is second + private static final String DEFAULT_WARM_UP_TIME = "0"; + + private static final String WARM_TIME_KEY = "warmupTime"; + + private static final String WARM_CURVE_KEY = "warmupCurve"; + + // Preheat calculates curve value + private static final String DEFAULT_WARM_UP_CURVE = "2"; + + private final Random random = new Random(); + + @Override + public int getOrder() { + return ORDER_WARM_UP; + } + + @Override + public boolean enabled() { + return DynamicPropertyFactory.getInstance() + .getBooleanProperty(WARM_UP_FILTER_ENABLED, true) + .get(); + } + + @Override + public List getFilteredListOfServers(List servers, + Invocation invocation) { + if (servers.size() <= 1) { + return servers; + } + boolean isAllInstanceWarmUp = true; + int[] weights = new int[servers.size()]; + int totalWeight = 0; + int index = 0; + for (ServiceCombServer server : servers) { + Map properties = server.getInstance().getProperties(); + boolean isWarmed = calculateAndCheckIsWarmUp(properties, weights, index, server.getInstance().getTimestamp()); + isAllInstanceWarmUp &= isWarmed; + totalWeight += weights[index++]; + } + if (!isAllInstanceWarmUp) { + return chooseServer(totalWeight, weights, servers); + } + return servers; + } + + private List chooseServer(int totalWeight, int[] weights, List servers) { + if (totalWeight <= 0) { + return servers; + } + int position = random.nextInt(totalWeight); + for (int i = 0; i < weights.length; i++) { + position -= weights[i]; + if (position < 0) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("warm up choose service instance: " + servers.get(i).getInstance().getInstanceId()); + } + return Collections.singletonList(servers.get(i)); + } + } + return servers; + } + + private boolean calculateAndCheckIsWarmUp(Map metadata, int[] weights, int index, + String registerTimeStr) { + final int warmUpCurve = Integer.parseInt(metadata.getOrDefault(WARM_CURVE_KEY, DEFAULT_WARM_UP_CURVE)); + final long warmUpTime = Long.parseLong(metadata.getOrDefault(WARM_TIME_KEY, DEFAULT_WARM_UP_TIME)); + final long registerTime = Long.parseLong(registerTimeStr); + final int weight = calculateWeight(registerTime, warmUpTime, warmUpCurve); + weights[index] = weight; + return isWarmed(registerTime, warmUpTime); + } + + private int calculateWeight(long registerTime, long warmUpTime, int warmUpCurve) { + if (warmUpTime <= 0 || registerTime <= 0) { + return INSTANCE_WEIGHT; + } + if (warmUpCurve <= 0) { + warmUpCurve = Integer.parseInt(DEFAULT_WARM_UP_CURVE); + } + // calculated in seconds + final long runTime = System.currentTimeMillis() / 1000 - registerTime; + if (runTime > 0 && runTime < warmUpTime) { + return calculateWarmUpWeight(runTime, warmUpTime, warmUpCurve); + } + return INSTANCE_WEIGHT; + } + + private int calculateWarmUpWeight(double runtime, double warmUpTime, int warmUpCurve) { + final int round = (int) Math.round(Math.pow(runtime / warmUpTime, warmUpCurve) * INSTANCE_WEIGHT); + return round < 1 ? 1 : Math.min(round, INSTANCE_WEIGHT); + } + + private boolean isWarmed(long registerTime, long warmUpTime) { + return registerTime == 0L || System.currentTimeMillis() / 1000 - registerTime > warmUpTime; + } +} diff --git a/handlers/handler-loadbalance/src/main/resources/META-INF/services/org.apache.servicecomb.loadbalance.ServerListFilterExt b/handlers/handler-loadbalance/src/main/resources/META-INF/services/org.apache.servicecomb.loadbalance.ServerListFilterExt index a355341ff46..53676e8b1f8 100644 --- a/handlers/handler-loadbalance/src/main/resources/META-INF/services/org.apache.servicecomb.loadbalance.ServerListFilterExt +++ b/handlers/handler-loadbalance/src/main/resources/META-INF/services/org.apache.servicecomb.loadbalance.ServerListFilterExt @@ -16,4 +16,5 @@ # org.apache.servicecomb.loadbalance.filterext.IsolationServerListFilterExt -org.apache.servicecomb.loadbalance.filterext.ZoneAwareDiscoveryFilter \ No newline at end of file +org.apache.servicecomb.loadbalance.filterext.ZoneAwareDiscoveryFilter +org.apache.servicecomb.loadbalance.filterext.WarmUpDiscoveryFilter \ No newline at end of file From 7864c4dda7a60a4db1fb5198454cfbe35d0ef8bd Mon Sep 17 00:00:00 2001 From: chengyouling Date: Thu, 14 Nov 2024 11:45:45 +0800 Subject: [PATCH 02/16] =?UTF-8?q?=E8=B0=83=E6=95=B4=E9=A2=84=E7=83=AD?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/servicecomb/loadbalance/ServerListFilterExt.java | 2 -- .../loadbalance/filterext/WarmUpDiscoveryFilter.java | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServerListFilterExt.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServerListFilterExt.java index 3e574db16eb..124e8f13563 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServerListFilterExt.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/ServerListFilterExt.java @@ -17,8 +17,6 @@ package org.apache.servicecomb.loadbalance; -import io.swagger.models.auth.In; - import java.util.List; import org.apache.servicecomb.core.Invocation; diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java index 4b8ccf2f3a2..10cc4ce3e4a 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java @@ -36,7 +36,7 @@ public class WarmUpDiscoveryFilter implements ServerListFilterExt { private static final int INSTANCE_WEIGHT = 100; // Default time for warm up, the unit is second - private static final String DEFAULT_WARM_UP_TIME = "0"; + private static final String DEFAULT_WARM_UP_TIME = "30"; private static final String WARM_TIME_KEY = "warmupTime"; From f034a64970ad83398a50dee3ae9b96c87dd4c0fc Mon Sep 17 00:00:00 2001 From: chengyouling Date: Thu, 14 Nov 2024 15:01:16 +0800 Subject: [PATCH 03/16] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=9C=AC=E5=9C=B0?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E6=97=A0=E6=B3=A8=E5=86=8C=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E6=B5=8B=E8=AF=95=E5=A4=B1=E8=B4=A5=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../loadbalance/filterext/WarmUpDiscoveryFilter.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java index 10cc4ce3e4a..ee14cacc94c 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java @@ -19,6 +19,7 @@ import com.netflix.config.DynamicPropertyFactory; +import org.apache.commons.lang3.StringUtils; import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.loadbalance.ServerListFilterExt; import org.apache.servicecomb.loadbalance.ServiceCombServer; @@ -71,7 +72,9 @@ public List getFilteredListOfServers(List int index = 0; for (ServiceCombServer server : servers) { Map properties = server.getInstance().getProperties(); - boolean isWarmed = calculateAndCheckIsWarmUp(properties, weights, index, server.getInstance().getTimestamp()); + String registerTimeStr = StringUtils.isBlank(server.getInstance().getTimestamp()) ? "0" : + server.getInstance().getTimestamp(); + boolean isWarmed = calculateAndCheckIsWarmUp(properties, weights, index, registerTimeStr); isAllInstanceWarmUp &= isWarmed; totalWeight += weights[index++]; } From 54114eaf5190b8868e9c697be6d633ca38f96021 Mon Sep 17 00:00:00 2001 From: chengyouling Date: Thu, 14 Nov 2024 15:28:16 +0800 Subject: [PATCH 04/16] =?UTF-8?q?=E5=85=B3=E9=97=ADedge=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E4=B8=AD=E9=A2=84=E7=83=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demo/demo-edge/consumer/src/main/resources/microservice.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/demo/demo-edge/consumer/src/main/resources/microservice.yaml b/demo/demo-edge/consumer/src/main/resources/microservice.yaml index 53c1e23475a..51d8691f101 100644 --- a/demo/demo-edge/consumer/src/main/resources/microservice.yaml +++ b/demo/demo-edge/consumer/src/main/resources/microservice.yaml @@ -27,6 +27,9 @@ servicecomb: client.http2.useAlpnEnabled: false loadbalance: filter: + service: + warmup: + enabled: false operation: enabled: true handler: From 8c4e8fd4fe8d5464a2ec73e1719e5af1a3002ade Mon Sep 17 00:00:00 2001 From: chengyouling Date: Thu, 14 Nov 2024 16:05:43 +0800 Subject: [PATCH 05/16] =?UTF-8?q?=E5=85=B3=E9=97=ADedge=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E4=B8=AD=E9=A2=84=E7=83=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../edge-service/src/main/resources/microservice.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/demo/demo-edge/edge-service/src/main/resources/microservice.yaml b/demo/demo-edge/edge-service/src/main/resources/microservice.yaml index cb336471948..9941cb19761 100644 --- a/demo/demo-edge/edge-service/src/main/resources/microservice.yaml +++ b/demo/demo-edge/edge-service/src/main/resources/microservice.yaml @@ -38,6 +38,9 @@ servicecomb: http2.useAlpnEnabled: false loadbalance: filter: + service: + warmup: + enabled: false operation: enabled: true handler: From 5e533e1027e0daea6119c447181dbe6debe06bff Mon Sep 17 00:00:00 2001 From: chengyouling Date: Mon, 18 Nov 2024 11:12:00 +0800 Subject: [PATCH 06/16] set register time to instance property --- .../src/main/resources/microservice.yaml | 3 --- .../src/main/resources/microservice.yaml | 3 --- .../api/registry/MicroserviceInstance.java | 4 ++++ .../config/InstancePropertiesConst.java | 22 +++++++++++++++++++ .../filterext/WarmUpDiscoveryFilter.java | 19 ++++++++-------- 5 files changed, 35 insertions(+), 16 deletions(-) create mode 100644 foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/config/InstancePropertiesConst.java diff --git a/demo/demo-edge/consumer/src/main/resources/microservice.yaml b/demo/demo-edge/consumer/src/main/resources/microservice.yaml index 51d8691f101..53c1e23475a 100644 --- a/demo/demo-edge/consumer/src/main/resources/microservice.yaml +++ b/demo/demo-edge/consumer/src/main/resources/microservice.yaml @@ -27,9 +27,6 @@ servicecomb: client.http2.useAlpnEnabled: false loadbalance: filter: - service: - warmup: - enabled: false operation: enabled: true handler: diff --git a/demo/demo-edge/edge-service/src/main/resources/microservice.yaml b/demo/demo-edge/edge-service/src/main/resources/microservice.yaml index 9941cb19761..cb336471948 100644 --- a/demo/demo-edge/edge-service/src/main/resources/microservice.yaml +++ b/demo/demo-edge/edge-service/src/main/resources/microservice.yaml @@ -38,9 +38,6 @@ servicecomb: http2.useAlpnEnabled: false loadbalance: filter: - service: - warmup: - enabled: false operation: enabled: true handler: diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/registry/MicroserviceInstance.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/registry/MicroserviceInstance.java index f7d41bf3a45..9f6fd372095 100644 --- a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/registry/MicroserviceInstance.java +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/registry/MicroserviceInstance.java @@ -25,6 +25,7 @@ import org.apache.commons.configuration.Configuration; import org.apache.commons.lang3.StringUtils; import org.apache.servicecomb.config.BootStrapProperties; +import org.apache.servicecomb.registry.config.InstancePropertiesConst; import org.apache.servicecomb.registry.config.InstancePropertiesLoader; import org.apache.servicecomb.registry.definition.DefinitionConst; @@ -188,6 +189,9 @@ public static MicroserviceInstance createFromDefinition(Configuration configurat // load properties Map propertiesMap = InstancePropertiesLoader.INSTANCE.loadProperties(configuration); + + // add register time for warm up + propertiesMap.put(InstancePropertiesConst.REGISTER_TIME_KEY, String.valueOf(System.currentTimeMillis())); microserviceInstance.setProperties(propertiesMap); // load data center information diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/config/InstancePropertiesConst.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/config/InstancePropertiesConst.java new file mode 100644 index 00000000000..befeb0f03ba --- /dev/null +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/config/InstancePropertiesConst.java @@ -0,0 +1,22 @@ +/* + * 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.registry.config; + +public class InstancePropertiesConst { + public static final String REGISTER_TIME_KEY = "registerTime"; +} diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java index ee14cacc94c..098503e2aac 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java @@ -23,6 +23,7 @@ import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.loadbalance.ServerListFilterExt; import org.apache.servicecomb.loadbalance.ServiceCombServer; +import org.apache.servicecomb.registry.config.InstancePropertiesConst; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,8 +37,8 @@ public class WarmUpDiscoveryFilter implements ServerListFilterExt { private static final int INSTANCE_WEIGHT = 100; - // Default time for warm up, the unit is second - private static final String DEFAULT_WARM_UP_TIME = "30"; + // Default time for warm up, the unit is milliseconds + private static final String DEFAULT_WARM_UP_TIME = "30000"; private static final String WARM_TIME_KEY = "warmupTime"; @@ -72,9 +73,7 @@ public List getFilteredListOfServers(List int index = 0; for (ServiceCombServer server : servers) { Map properties = server.getInstance().getProperties(); - String registerTimeStr = StringUtils.isBlank(server.getInstance().getTimestamp()) ? "0" : - server.getInstance().getTimestamp(); - boolean isWarmed = calculateAndCheckIsWarmUp(properties, weights, index, registerTimeStr); + boolean isWarmed = calculateAndCheckIsWarmUp(properties, weights, index); isAllInstanceWarmUp &= isWarmed; totalWeight += weights[index++]; } @@ -101,11 +100,11 @@ private List chooseServer(int totalWeight, int[] weights, Lis return servers; } - private boolean calculateAndCheckIsWarmUp(Map metadata, int[] weights, int index, - String registerTimeStr) { + private boolean calculateAndCheckIsWarmUp(Map metadata, int[] weights, int index) { final int warmUpCurve = Integer.parseInt(metadata.getOrDefault(WARM_CURVE_KEY, DEFAULT_WARM_UP_CURVE)); final long warmUpTime = Long.parseLong(metadata.getOrDefault(WARM_TIME_KEY, DEFAULT_WARM_UP_TIME)); - final long registerTime = Long.parseLong(registerTimeStr); + String registerTimeStr = metadata.get(InstancePropertiesConst.REGISTER_TIME_KEY); + final long registerTime = Long.parseLong(StringUtils.isEmpty(registerTimeStr) ? "0" : registerTimeStr); final int weight = calculateWeight(registerTime, warmUpTime, warmUpCurve); weights[index] = weight; return isWarmed(registerTime, warmUpTime); @@ -119,7 +118,7 @@ private int calculateWeight(long registerTime, long warmUpTime, int warmUpCurve) warmUpCurve = Integer.parseInt(DEFAULT_WARM_UP_CURVE); } // calculated in seconds - final long runTime = System.currentTimeMillis() / 1000 - registerTime; + final long runTime = System.currentTimeMillis() - registerTime; if (runTime > 0 && runTime < warmUpTime) { return calculateWarmUpWeight(runTime, warmUpTime, warmUpCurve); } @@ -132,6 +131,6 @@ private int calculateWarmUpWeight(double runtime, double warmUpTime, int warmUpC } private boolean isWarmed(long registerTime, long warmUpTime) { - return registerTime == 0L || System.currentTimeMillis() / 1000 - registerTime > warmUpTime; + return registerTime == 0L || System.currentTimeMillis() - registerTime > warmUpTime; } } From 2af2bf19220f56345b1e1ce6b7d660830cf53146 Mon Sep 17 00:00:00 2001 From: chengyouling Date: Mon, 18 Nov 2024 11:25:20 +0800 Subject: [PATCH 07/16] change test warm time --- .../provider-canary/src/main/resources/application.yml | 2 +- demo/demo-cse-v1/provider/src/main/resources/application.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/demo/demo-cse-v1/provider-canary/src/main/resources/application.yml b/demo/demo-cse-v1/provider-canary/src/main/resources/application.yml index f287d6f61b4..2b9bb6f6270 100644 --- a/demo/demo-cse-v1/provider-canary/src/main/resources/application.yml +++ b/demo/demo-cse-v1/provider-canary/src/main/resources/application.yml @@ -21,7 +21,7 @@ servicecomb-config-order: 10 servicecomb: instance: properties: - warmupTime: 60 + warmupTime: 60000 warmupCurve: 2 service: application: demo-java-chassis-cse-v1 diff --git a/demo/demo-cse-v1/provider/src/main/resources/application.yml b/demo/demo-cse-v1/provider/src/main/resources/application.yml index 1570e1a0ad5..10e0ebd8580 100644 --- a/demo/demo-cse-v1/provider/src/main/resources/application.yml +++ b/demo/demo-cse-v1/provider/src/main/resources/application.yml @@ -21,7 +21,7 @@ servicecomb-config-order: 10 servicecomb: instance: properties: - warmupTime: 30 + warmupTime: 30000 warmupCurve: 2 service: application: demo-java-chassis-cse-v1 From 6afd6f9155c627626f86326be8e7905da02ea5c8 Mon Sep 17 00:00:00 2001 From: chengyouling Date: Mon, 18 Nov 2024 14:25:56 +0800 Subject: [PATCH 08/16] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=94=A8=E4=BE=8B=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../serviceregistry/config/TestPropertiesLoader.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/config/TestPropertiesLoader.java b/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/config/TestPropertiesLoader.java index 2cbadda9cf6..95c3cc75d02 100644 --- a/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/config/TestPropertiesLoader.java +++ b/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/config/TestPropertiesLoader.java @@ -26,6 +26,7 @@ import org.apache.servicecomb.registry.api.registry.Microservice; import org.apache.servicecomb.registry.api.registry.MicroserviceFactory; import org.apache.servicecomb.registry.api.registry.MicroserviceInstance; +import org.apache.servicecomb.registry.config.InstancePropertiesConst; import org.apache.servicecomb.serviceregistry.registry.LocalServiceRegistryFactory; import org.junit.Test; import org.junit.jupiter.api.Assertions; @@ -89,6 +90,7 @@ public void testMicroservicePropertiesLoader() throws Exception { public void testInstancePropertiesLoader() { Microservice microservice = LocalServiceRegistryFactory.createLocal().getMicroservice(); MicroserviceInstance instance = microservice.getInstance(); + instance.getProperties().remove(InstancePropertiesConst.REGISTER_TIME_KEY); Map expectedMap = new HashMap<>(); expectedMap.put("key0", "value0"); expectedMap.put("ek0", "ev0"); From 292889382dda85d6d1446091ddc00e8b599a71b6 Mon Sep 17 00:00:00 2001 From: chengyouling Date: Mon, 18 Nov 2024 20:23:41 +0800 Subject: [PATCH 09/16] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=9D=83=E9=87=8D?= =?UTF-8?q?=E8=AE=A1=E7=AE=97=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filterext/WarmUpDiscoveryFilter.java | 44 +++++++++++-------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java index 098503e2aac..e4ef00bcffe 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java @@ -26,11 +26,13 @@ import org.apache.servicecomb.registry.config.InstancePropertiesConst; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Random; +import java.util.stream.Collectors; public class WarmUpDiscoveryFilter implements ServerListFilterExt { private static final Logger LOGGER = LoggerFactory.getLogger(WarmUpDiscoveryFilter.class); @@ -67,20 +69,30 @@ public List getFilteredListOfServers(List if (servers.size() <= 1) { return servers; } - boolean isAllInstanceWarmUp = true; + if (CollectionUtils.isEmpty(existNeedWarmUpInstances(servers))) { + return servers; + } int[] weights = new int[servers.size()]; int totalWeight = 0; int index = 0; for (ServiceCombServer server : servers) { - Map properties = server.getInstance().getProperties(); - boolean isWarmed = calculateAndCheckIsWarmUp(properties, weights, index); - isAllInstanceWarmUp &= isWarmed; + weights[index] = calculate(server.getInstance().getProperties()); totalWeight += weights[index++]; } - if (!isAllInstanceWarmUp) { - return chooseServer(totalWeight, weights, servers); - } - return servers; + return chooseServer(totalWeight, weights, servers); + } + + private List existNeedWarmUpInstances(List servers) { + return servers.stream() + .filter(server -> isInstanceNeedWarmUp(server.getInstance().getProperties())) + .collect(Collectors.toList()); + } + + private boolean isInstanceNeedWarmUp(Map properties) { + final long warmUpTime = Long.parseLong(properties.getOrDefault(WARM_TIME_KEY, DEFAULT_WARM_UP_TIME)); + String registerTimeStr = properties.get(InstancePropertiesConst.REGISTER_TIME_KEY); + final long registerTime = Long.parseLong(StringUtils.isEmpty(registerTimeStr) ? "0" : registerTimeStr); + return registerTime != 0L && System.currentTimeMillis() - registerTime < warmUpTime; } private List chooseServer(int totalWeight, int[] weights, List servers) { @@ -100,14 +112,12 @@ private List chooseServer(int totalWeight, int[] weights, Lis return servers; } - private boolean calculateAndCheckIsWarmUp(Map metadata, int[] weights, int index) { - final int warmUpCurve = Integer.parseInt(metadata.getOrDefault(WARM_CURVE_KEY, DEFAULT_WARM_UP_CURVE)); - final long warmUpTime = Long.parseLong(metadata.getOrDefault(WARM_TIME_KEY, DEFAULT_WARM_UP_TIME)); - String registerTimeStr = metadata.get(InstancePropertiesConst.REGISTER_TIME_KEY); + private int calculate(Map properties) { + final int warmUpCurve = Integer.parseInt(properties.getOrDefault(WARM_CURVE_KEY, DEFAULT_WARM_UP_CURVE)); + final long warmUpTime = Long.parseLong(properties.getOrDefault(WARM_TIME_KEY, DEFAULT_WARM_UP_TIME)); + String registerTimeStr = properties.get(InstancePropertiesConst.REGISTER_TIME_KEY); final long registerTime = Long.parseLong(StringUtils.isEmpty(registerTimeStr) ? "0" : registerTimeStr); - final int weight = calculateWeight(registerTime, warmUpTime, warmUpCurve); - weights[index] = weight; - return isWarmed(registerTime, warmUpTime); + return calculateWeight(registerTime, warmUpTime, warmUpCurve); } private int calculateWeight(long registerTime, long warmUpTime, int warmUpCurve) { @@ -129,8 +139,4 @@ private int calculateWarmUpWeight(double runtime, double warmUpTime, int warmUpC final int round = (int) Math.round(Math.pow(runtime / warmUpTime, warmUpCurve) * INSTANCE_WEIGHT); return round < 1 ? 1 : Math.min(round, INSTANCE_WEIGHT); } - - private boolean isWarmed(long registerTime, long warmUpTime) { - return registerTime == 0L || System.currentTimeMillis() - registerTime > warmUpTime; - } } From df413aee62c8f4ceb5c05593fdc65230e67aee92 Mon Sep 17 00:00:00 2001 From: chengyouling Date: Thu, 21 Nov 2024 17:51:13 +0800 Subject: [PATCH 10/16] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E8=A2=AB=E8=B0=83=E7=94=A8=E6=97=B6=E9=97=B4=E8=AE=A1=E7=AE=97?= =?UTF-8?q?=E6=9D=83=E9=87=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filterext/WarmUpDiscoveryFilter.java | 54 ++++++++++++++----- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java index e4ef00bcffe..ebf57ca82cb 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java @@ -29,6 +29,7 @@ import org.springframework.util.CollectionUtils; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; @@ -49,8 +50,13 @@ public class WarmUpDiscoveryFilter implements ServerListFilterExt { // Preheat calculates curve value private static final String DEFAULT_WARM_UP_CURVE = "2"; + // provider run time, the unit is milliseconds + private static final long PROVIDER_RUN_TIME = 30 * 60 * 1000; + private final Random random = new Random(); + private final Map instanceInvokeTime = new HashMap<>(); + @Override public int getOrder() { return ORDER_WARM_UP; @@ -76,7 +82,7 @@ public List getFilteredListOfServers(List int totalWeight = 0; int index = 0; for (ServiceCombServer server : servers) { - weights[index] = calculate(server.getInstance().getProperties()); + weights[index] = calculate(server.getInstance().getProperties(), server.getInstance().getInstanceId()); totalWeight += weights[index++]; } return chooseServer(totalWeight, weights, servers); @@ -84,15 +90,28 @@ public List getFilteredListOfServers(List private List existNeedWarmUpInstances(List servers) { return servers.stream() - .filter(server -> isInstanceNeedWarmUp(server.getInstance().getProperties())) + .filter(server -> isInstanceNeedWarmUp(server.getInstance().getProperties(), + server.getInstance().getInstanceId())) .collect(Collectors.toList()); } - private boolean isInstanceNeedWarmUp(Map properties) { - final long warmUpTime = Long.parseLong(properties.getOrDefault(WARM_TIME_KEY, DEFAULT_WARM_UP_TIME)); + private boolean isInstanceNeedWarmUp(Map properties, String instanceId) { String registerTimeStr = properties.get(InstancePropertiesConst.REGISTER_TIME_KEY); - final long registerTime = Long.parseLong(StringUtils.isEmpty(registerTimeStr) ? "0" : registerTimeStr); - return registerTime != 0L && System.currentTimeMillis() - registerTime < warmUpTime; + long registerTime = Long.parseLong(StringUtils.isEmpty(registerTimeStr) ? "0" : registerTimeStr); + + // Provider run time greater than 30 minute, can be regarded as not need warn up. + // To ensure that the consumer is restarted but the provider is not restarted. + if (System.currentTimeMillis() - registerTime > PROVIDER_RUN_TIME) { + return false; + } + Long invokeTime = instanceInvokeTime.get(instanceId); + + // instance have not been invoked need to be warn-up + if (invokeTime == null) { + return true; + } + final long warmUpTime = Long.parseLong(properties.getOrDefault(WARM_TIME_KEY, DEFAULT_WARM_UP_TIME)); + return System.currentTimeMillis() - invokeTime < warmUpTime; } private List chooseServer(int totalWeight, int[] weights, List servers) { @@ -106,29 +125,36 @@ private List chooseServer(int totalWeight, int[] weights, Lis if (LOGGER.isDebugEnabled()) { LOGGER.debug("warm up choose service instance: " + servers.get(i).getInstance().getInstanceId()); } + setInstanceStartInvokeTime(servers.get(i)); return Collections.singletonList(servers.get(i)); } } return servers; } - private int calculate(Map properties) { + private void setInstanceStartInvokeTime(ServiceCombServer server) { + instanceInvokeTime.putIfAbsent(server.getInstance().getInstanceId(), System.currentTimeMillis()); + } + + private int calculate(Map properties, String instanceId) { + // if instance wasn't called, return default weight, will have higher weight be selected, better into warn up + if (instanceInvokeTime.get(instanceId) == null) { + return INSTANCE_WEIGHT; + } final int warmUpCurve = Integer.parseInt(properties.getOrDefault(WARM_CURVE_KEY, DEFAULT_WARM_UP_CURVE)); final long warmUpTime = Long.parseLong(properties.getOrDefault(WARM_TIME_KEY, DEFAULT_WARM_UP_TIME)); - String registerTimeStr = properties.get(InstancePropertiesConst.REGISTER_TIME_KEY); - final long registerTime = Long.parseLong(StringUtils.isEmpty(registerTimeStr) ? "0" : registerTimeStr); - return calculateWeight(registerTime, warmUpTime, warmUpCurve); + return calculateWeight(instanceInvokeTime.get(instanceId), warmUpTime, warmUpCurve); } - private int calculateWeight(long registerTime, long warmUpTime, int warmUpCurve) { - if (warmUpTime <= 0 || registerTime <= 0) { + private int calculateWeight(long invokeStartTime, long warmUpTime, int warmUpCurve) { + if (warmUpTime <= 0) { return INSTANCE_WEIGHT; } if (warmUpCurve <= 0) { warmUpCurve = Integer.parseInt(DEFAULT_WARM_UP_CURVE); } - // calculated in seconds - final long runTime = System.currentTimeMillis() - registerTime; + // calculated in milliseconds + final long runTime = System.currentTimeMillis() - invokeStartTime; if (runTime > 0 && runTime < warmUpTime) { return calculateWarmUpWeight(runTime, warmUpTime, warmUpCurve); } From df7902e4767d480e703cdc18fed606fb1560138b Mon Sep 17 00:00:00 2001 From: chengyouling Date: Thu, 21 Nov 2024 18:45:17 +0800 Subject: [PATCH 11/16] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filterext/WarmUpDiscoveryFilter.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java index ebf57ca82cb..a70b842c081 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java @@ -96,12 +96,7 @@ private List existNeedWarmUpInstances(List } private boolean isInstanceNeedWarmUp(Map properties, String instanceId) { - String registerTimeStr = properties.get(InstancePropertiesConst.REGISTER_TIME_KEY); - long registerTime = Long.parseLong(StringUtils.isEmpty(registerTimeStr) ? "0" : registerTimeStr); - - // Provider run time greater than 30 minute, can be regarded as not need warn up. - // To ensure that the consumer is restarted but the provider is not restarted. - if (System.currentTimeMillis() - registerTime > PROVIDER_RUN_TIME) { + if (isRunTimeUpBaseStartupTime(properties)) { return false; } Long invokeTime = instanceInvokeTime.get(instanceId); @@ -114,6 +109,15 @@ private boolean isInstanceNeedWarmUp(Map properties, String inst return System.currentTimeMillis() - invokeTime < warmUpTime; } + private boolean isRunTimeUpBaseStartupTime(Map properties) { + String registerTimeStr = properties.get(InstancePropertiesConst.REGISTER_TIME_KEY); + long registerTime = Long.parseLong(StringUtils.isEmpty(registerTimeStr) ? "0" : registerTimeStr); + + // Provider run time greater than 30 minute, can be regarded as not need warn up. + // To ensure that the consumer is restarted but the provider is not restarted. + return System.currentTimeMillis() - registerTime > PROVIDER_RUN_TIME; + } + private List chooseServer(int totalWeight, int[] weights, List servers) { if (totalWeight <= 0) { return servers; @@ -133,6 +137,9 @@ private List chooseServer(int totalWeight, int[] weights, Lis } private void setInstanceStartInvokeTime(ServiceCombServer server) { + if (isRunTimeUpBaseStartupTime(server.getInstance().getProperties())) { + return; + } instanceInvokeTime.putIfAbsent(server.getInstance().getInstanceId(), System.currentTimeMillis()); } From 3191fd4c5716fd611c9c2e61b188e1c114615e1b Mon Sep 17 00:00:00 2001 From: chengyouling Date: Fri, 22 Nov 2024 17:25:59 +0800 Subject: [PATCH 12/16] =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=B8=BA=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E4=B8=8D=E4=BD=BF=E7=94=A8=E9=A2=84=E7=83=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filterext/WarmUpDiscoveryFilter.java | 76 ++++++++++++++----- 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java index a70b842c081..ffcaf2cffd0 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java @@ -17,6 +17,7 @@ package org.apache.servicecomb.loadbalance.filterext; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.netflix.config.DynamicPropertyFactory; import org.apache.commons.lang3.StringUtils; @@ -28,16 +29,22 @@ import org.slf4j.LoggerFactory; import org.springframework.util.CollectionUtils; +import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; public class WarmUpDiscoveryFilter implements ServerListFilterExt { private static final Logger LOGGER = LoggerFactory.getLogger(WarmUpDiscoveryFilter.class); + private static final String IGNORE_WARN_UP_TIME = "servicecomb.loadbalance.filter.service.warmup.ignoreWarmUpTime"; + private static final int INSTANCE_WEIGHT = 100; // Default time for warm up, the unit is milliseconds @@ -51,11 +58,39 @@ public class WarmUpDiscoveryFilter implements ServerListFilterExt { private static final String DEFAULT_WARM_UP_CURVE = "2"; // provider run time, the unit is milliseconds - private static final long PROVIDER_RUN_TIME = 30 * 60 * 1000; + private final long ignoreWarmUpTime; private final Random random = new Random(); - private final Map instanceInvokeTime = new HashMap<>(); + private final Map instanceInvokeTime = new ConcurrentHashMap<>(); + + public WarmUpDiscoveryFilter() { + ScheduledExecutorService executor = Executors.newScheduledThreadPool(1, + new ThreadFactoryBuilder() + .setNameFormat("warm-up-cache-refresh-%d") + .build()); + ignoreWarmUpTime = getIgnoreWarmUpTime(); + executor.scheduleAtFixedRate(this::refreshMapCache, 0, 10, TimeUnit.MINUTES); + } + + private long getIgnoreWarmUpTime() { + return DynamicPropertyFactory.getInstance() + .getLongProperty(IGNORE_WARN_UP_TIME, 30 * 60 * 1000) + .get(); + } + + private void refreshMapCache() { + List removeKeys = new ArrayList<>(); + for (Map.Entry entry : instanceInvokeTime.entrySet()) { + if (System.currentTimeMillis() - entry.getValue() > ignoreWarmUpTime) { + removeKeys.add(entry.getKey()); + } + } + if (CollectionUtils.isEmpty(removeKeys)) { + return; + } + removeKeys.forEach(instanceInvokeTime::remove); + } @Override public int getOrder() { @@ -65,7 +100,7 @@ public int getOrder() { @Override public boolean enabled() { return DynamicPropertyFactory.getInstance() - .getBooleanProperty(WARM_UP_FILTER_ENABLED, true) + .getBooleanProperty(WARM_UP_FILTER_ENABLED, false) .get(); } @@ -75,9 +110,16 @@ public List getFilteredListOfServers(List if (servers.size() <= 1) { return servers; } - if (CollectionUtils.isEmpty(existNeedWarmUpInstances(servers))) { + List notInvokedInstances = new ArrayList<>(); + if (CollectionUtils.isEmpty(existNeedWarmUpInstances(servers, notInvokedInstances))) { return servers; } + + // If exist not invoked instances, choose one that let it into warm up. + if (!CollectionUtils.isEmpty(notInvokedInstances)) { + setInstanceStartInvokeTime(notInvokedInstances.get(0)); + return Collections.singletonList(notInvokedInstances.get(0)); + } int[] weights = new int[servers.size()]; int totalWeight = 0; int index = 0; @@ -88,34 +130,37 @@ public List getFilteredListOfServers(List return chooseServer(totalWeight, weights, servers); } - private List existNeedWarmUpInstances(List servers) { + private List existNeedWarmUpInstances(List servers, + List notInvokedInstances) { return servers.stream() - .filter(server -> isInstanceNeedWarmUp(server.getInstance().getProperties(), - server.getInstance().getInstanceId())) + .filter(server -> isInstanceNeedWarmUp(server, notInvokedInstances)) .collect(Collectors.toList()); } - private boolean isInstanceNeedWarmUp(Map properties, String instanceId) { - if (isRunTimeUpBaseStartupTime(properties)) { + private boolean isInstanceNeedWarmUp(ServiceCombServer server, List notInvokedInstances) { + Map properties = server.getInstance().getProperties(); + String instanceId = server.getInstance().getInstanceId(); + if (isUpIgnoreWarmUpTime(properties)) { return false; } Long invokeTime = instanceInvokeTime.get(instanceId); // instance have not been invoked need to be warn-up if (invokeTime == null) { + notInvokedInstances.add(server); return true; } final long warmUpTime = Long.parseLong(properties.getOrDefault(WARM_TIME_KEY, DEFAULT_WARM_UP_TIME)); return System.currentTimeMillis() - invokeTime < warmUpTime; } - private boolean isRunTimeUpBaseStartupTime(Map properties) { + private boolean isUpIgnoreWarmUpTime(Map properties) { String registerTimeStr = properties.get(InstancePropertiesConst.REGISTER_TIME_KEY); long registerTime = Long.parseLong(StringUtils.isEmpty(registerTimeStr) ? "0" : registerTimeStr); - // Provider run time greater than 30 minute, can be regarded as not need warn up. + // Provider run time greater than 30 minute, can be regarded as don't need warn up. // To ensure that the consumer is restarted but the provider is not restarted. - return System.currentTimeMillis() - registerTime > PROVIDER_RUN_TIME; + return System.currentTimeMillis() - registerTime > ignoreWarmUpTime; } private List chooseServer(int totalWeight, int[] weights, List servers) { @@ -129,7 +174,6 @@ private List chooseServer(int totalWeight, int[] weights, Lis if (LOGGER.isDebugEnabled()) { LOGGER.debug("warm up choose service instance: " + servers.get(i).getInstance().getInstanceId()); } - setInstanceStartInvokeTime(servers.get(i)); return Collections.singletonList(servers.get(i)); } } @@ -137,14 +181,10 @@ private List chooseServer(int totalWeight, int[] weights, Lis } private void setInstanceStartInvokeTime(ServiceCombServer server) { - if (isRunTimeUpBaseStartupTime(server.getInstance().getProperties())) { - return; - } instanceInvokeTime.putIfAbsent(server.getInstance().getInstanceId(), System.currentTimeMillis()); } private int calculate(Map properties, String instanceId) { - // if instance wasn't called, return default weight, will have higher weight be selected, better into warn up if (instanceInvokeTime.get(instanceId) == null) { return INSTANCE_WEIGHT; } From 46b427e36402a9f017ad1c72a6652f94820e54e5 Mon Sep 17 00:00:00 2001 From: chengyouling Date: Tue, 26 Nov 2024 09:35:31 +0800 Subject: [PATCH 13/16] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E8=AE=A1=E7=AE=97=E6=9D=83=E9=87=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/registry/MicroserviceInstance.java | 4 - .../config/InstancePropertiesConst.java | 22 ------ .../filterext/WarmUpDiscoveryFilter.java | 76 +++++++++---------- .../config/TestPropertiesLoader.java | 2 - 4 files changed, 37 insertions(+), 67 deletions(-) delete mode 100644 foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/config/InstancePropertiesConst.java diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/registry/MicroserviceInstance.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/registry/MicroserviceInstance.java index 9f6fd372095..f7d41bf3a45 100644 --- a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/registry/MicroserviceInstance.java +++ b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/api/registry/MicroserviceInstance.java @@ -25,7 +25,6 @@ import org.apache.commons.configuration.Configuration; import org.apache.commons.lang3.StringUtils; import org.apache.servicecomb.config.BootStrapProperties; -import org.apache.servicecomb.registry.config.InstancePropertiesConst; import org.apache.servicecomb.registry.config.InstancePropertiesLoader; import org.apache.servicecomb.registry.definition.DefinitionConst; @@ -189,9 +188,6 @@ public static MicroserviceInstance createFromDefinition(Configuration configurat // load properties Map propertiesMap = InstancePropertiesLoader.INSTANCE.loadProperties(configuration); - - // add register time for warm up - propertiesMap.put(InstancePropertiesConst.REGISTER_TIME_KEY, String.valueOf(System.currentTimeMillis())); microserviceInstance.setProperties(propertiesMap); // load data center information diff --git a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/config/InstancePropertiesConst.java b/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/config/InstancePropertiesConst.java deleted file mode 100644 index befeb0f03ba..00000000000 --- a/foundations/foundation-registry/src/main/java/org/apache/servicecomb/registry/config/InstancePropertiesConst.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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.registry.config; - -public class InstancePropertiesConst { - public static final String REGISTER_TIME_KEY = "registerTime"; -} diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java index ffcaf2cffd0..cd0970355ab 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java @@ -17,34 +17,31 @@ package org.apache.servicecomb.loadbalance.filterext; -import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.netflix.config.DynamicPropertyFactory; -import org.apache.commons.lang3.StringUtils; import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.loadbalance.ServerListFilterExt; import org.apache.servicecomb.loadbalance.ServiceCombServer; -import org.apache.servicecomb.registry.config.InstancePropertiesConst; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.CollectionUtils; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; public class WarmUpDiscoveryFilter implements ServerListFilterExt { private static final Logger LOGGER = LoggerFactory.getLogger(WarmUpDiscoveryFilter.class); - private static final String IGNORE_WARN_UP_TIME = "servicecomb.loadbalance.filter.service.warmup.ignoreWarmUpTime"; - private static final int INSTANCE_WEIGHT = 100; // Default time for warm up, the unit is milliseconds @@ -57,32 +54,26 @@ public class WarmUpDiscoveryFilter implements ServerListFilterExt { // Preheat calculates curve value private static final String DEFAULT_WARM_UP_CURVE = "2"; - // provider run time, the unit is milliseconds - private final long ignoreWarmUpTime; - private final Random random = new Random(); private final Map instanceInvokeTime = new ConcurrentHashMap<>(); - public WarmUpDiscoveryFilter() { - ScheduledExecutorService executor = Executors.newScheduledThreadPool(1, - new ThreadFactoryBuilder() - .setNameFormat("warm-up-cache-refresh-%d") - .build()); - ignoreWarmUpTime = getIgnoreWarmUpTime(); - executor.scheduleAtFixedRate(this::refreshMapCache, 0, 10, TimeUnit.MINUTES); - } + private final Executor warmUpExecutor = Executors.newSingleThreadExecutor((r) -> { + Thread thread = new Thread(r); + thread.setName("warm-up-cache-refresh"); + return thread; + }); - private long getIgnoreWarmUpTime() { - return DynamicPropertyFactory.getInstance() - .getLongProperty(IGNORE_WARN_UP_TIME, 30 * 60 * 1000) - .get(); - } + private long initTime = System.currentTimeMillis(); + + // 10 minutes + private static final long REFRESH_TIME = 10 * 60 * 1000; private void refreshMapCache() { List removeKeys = new ArrayList<>(); for (Map.Entry entry : instanceInvokeTime.entrySet()) { - if (System.currentTimeMillis() - entry.getValue() > ignoreWarmUpTime) { + String[] ipAndPort = entry.getKey().split("@"); + if (!checkProviderExist(ipAndPort[0], Integer.parseInt(ipAndPort[1]))) { removeKeys.add(entry.getKey()); } } @@ -115,6 +106,12 @@ public List getFilteredListOfServers(List return servers; } + // Refresh every 10 minutes + if (System.currentTimeMillis() - initTime >= REFRESH_TIME) { + warmUpExecutor.execute(this::refreshMapCache); + initTime = System.currentTimeMillis(); + } + // If exist not invoked instances, choose one that let it into warm up. if (!CollectionUtils.isEmpty(notInvokedInstances)) { setInstanceStartInvokeTime(notInvokedInstances.get(0)); @@ -139,11 +136,7 @@ private List existNeedWarmUpInstances(List private boolean isInstanceNeedWarmUp(ServiceCombServer server, List notInvokedInstances) { Map properties = server.getInstance().getProperties(); - String instanceId = server.getInstance().getInstanceId(); - if (isUpIgnoreWarmUpTime(properties)) { - return false; - } - Long invokeTime = instanceInvokeTime.get(instanceId); + Long invokeTime = instanceInvokeTime.get(buildCacheKey(server)); // instance have not been invoked need to be warn-up if (invokeTime == null) { @@ -154,15 +147,6 @@ private boolean isInstanceNeedWarmUp(ServiceCombServer server, List properties) { - String registerTimeStr = properties.get(InstancePropertiesConst.REGISTER_TIME_KEY); - long registerTime = Long.parseLong(StringUtils.isEmpty(registerTimeStr) ? "0" : registerTimeStr); - - // Provider run time greater than 30 minute, can be regarded as don't need warn up. - // To ensure that the consumer is restarted but the provider is not restarted. - return System.currentTimeMillis() - registerTime > ignoreWarmUpTime; - } - private List chooseServer(int totalWeight, int[] weights, List servers) { if (totalWeight <= 0) { return servers; @@ -181,7 +165,11 @@ private List chooseServer(int totalWeight, int[] weights, Lis } private void setInstanceStartInvokeTime(ServiceCombServer server) { - instanceInvokeTime.putIfAbsent(server.getInstance().getInstanceId(), System.currentTimeMillis()); + instanceInvokeTime.putIfAbsent(buildCacheKey(server), System.currentTimeMillis()); + } + + private String buildCacheKey(ServiceCombServer server) { + return server.getInstance().getHostName() + "@" + server.getPort(); } private int calculate(Map properties, String instanceId) { @@ -200,6 +188,7 @@ private int calculateWeight(long invokeStartTime, long warmUpTime, int warmUpCur if (warmUpCurve <= 0) { warmUpCurve = Integer.parseInt(DEFAULT_WARM_UP_CURVE); } + // calculated in milliseconds final long runTime = System.currentTimeMillis() - invokeStartTime; if (runTime > 0 && runTime < warmUpTime) { @@ -212,4 +201,13 @@ private int calculateWarmUpWeight(double runtime, double warmUpTime, int warmUpC final int round = (int) Math.round(Math.pow(runtime / warmUpTime, warmUpCurve) * INSTANCE_WEIGHT); return round < 1 ? 1 : Math.min(round, INSTANCE_WEIGHT); } + + private boolean checkProviderExist(String host, int port) { + try (Socket s = new Socket()) { + s.connect(new InetSocketAddress(host, port), 3000); + return true; + } catch (IOException e) { + return false; + } + } } diff --git a/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/config/TestPropertiesLoader.java b/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/config/TestPropertiesLoader.java index 95c3cc75d02..2cbadda9cf6 100644 --- a/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/config/TestPropertiesLoader.java +++ b/service-registry/registry-service-center/src/test/java/org/apache/servicecomb/serviceregistry/config/TestPropertiesLoader.java @@ -26,7 +26,6 @@ import org.apache.servicecomb.registry.api.registry.Microservice; import org.apache.servicecomb.registry.api.registry.MicroserviceFactory; import org.apache.servicecomb.registry.api.registry.MicroserviceInstance; -import org.apache.servicecomb.registry.config.InstancePropertiesConst; import org.apache.servicecomb.serviceregistry.registry.LocalServiceRegistryFactory; import org.junit.Test; import org.junit.jupiter.api.Assertions; @@ -90,7 +89,6 @@ public void testMicroservicePropertiesLoader() throws Exception { public void testInstancePropertiesLoader() { Microservice microservice = LocalServiceRegistryFactory.createLocal().getMicroservice(); MicroserviceInstance instance = microservice.getInstance(); - instance.getProperties().remove(InstancePropertiesConst.REGISTER_TIME_KEY); Map expectedMap = new HashMap<>(); expectedMap.put("key0", "value0"); expectedMap.put("ek0", "ev0"); From 2a14a5fc1841ef7e4b46c9dfbc3e660fc7a75f7b Mon Sep 17 00:00:00 2001 From: chengyouling Date: Wed, 27 Nov 2024 21:11:04 +0800 Subject: [PATCH 14/16] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AE=9E=E4=BE=8B?= =?UTF-8?q?=E9=A2=84=E7=83=AD=E6=9C=9F=E9=97=B4=E6=9C=80=E5=A4=A7=E6=B5=81?= =?UTF-8?q?=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filterext/WarmUpDiscoveryFilter.java | 123 ++++++++++++++---- 1 file changed, 99 insertions(+), 24 deletions(-) diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java index cd0970355ab..84472386df0 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java @@ -47,17 +47,35 @@ public class WarmUpDiscoveryFilter implements ServerListFilterExt { // Default time for warm up, the unit is milliseconds private static final String DEFAULT_WARM_UP_TIME = "30000"; - private static final String WARM_TIME_KEY = "warmupTime"; - - private static final String WARM_CURVE_KEY = "warmupCurve"; - // Preheat calculates curve value private static final String DEFAULT_WARM_UP_CURVE = "2"; + private static final String DEFAULT_WARM_UP_MAX_CALL = "50"; + + private static final String WARM_UP_TIME = "servicecomb.loadbalance.filter.service.warmup.warm-up-time"; + + private static final String WARM_UP_CURVE = "servicecomb.loadbalance.filter.service.warmup.warm-up-curve"; + + // Maximum requests for instance that need warm up during the warm-up period + private static final String WARM_UP_MAX_CALL = "servicecomb.loadbalance.filter.service.warmup.warm-up-max-call"; + + // Maximum requests for instance that have been warmed up during the warm-up period + private static final String WARMED_MAX_CALL = "servicecomb.loadbalance.filter.service.warmup.warmed-max-call"; + + private final long warmUpTime; + + private final int warmUpCurve; + + private final int warmUpMaxCall; + + private final int warmedMaxCall; + private final Random random = new Random(); private final Map instanceInvokeTime = new ConcurrentHashMap<>(); + private final Map> instanceRequestTimestamps = new ConcurrentHashMap<>(); + private final Executor warmUpExecutor = Executors.newSingleThreadExecutor((r) -> { Thread thread = new Thread(r); thread.setName("warm-up-cache-refresh"); @@ -69,6 +87,13 @@ public class WarmUpDiscoveryFilter implements ServerListFilterExt { // 10 minutes private static final long REFRESH_TIME = 10 * 60 * 1000; + public WarmUpDiscoveryFilter() { + warmUpTime = Long.parseLong(getDynamicProperty(WARM_UP_TIME, DEFAULT_WARM_UP_TIME)); + warmUpCurve = Integer.parseInt(getDynamicProperty(WARM_UP_CURVE, DEFAULT_WARM_UP_CURVE)); + warmUpMaxCall = Integer.parseInt(getDynamicProperty(WARM_UP_MAX_CALL, DEFAULT_WARM_UP_MAX_CALL)); + warmedMaxCall = Integer.parseInt(getDynamicProperty(WARMED_MAX_CALL, warmUpMaxCall * 5 + "")); + } + private void refreshMapCache() { List removeKeys = new ArrayList<>(); for (Map.Entry entry : instanceInvokeTime.entrySet()) { @@ -102,7 +127,8 @@ public List getFilteredListOfServers(List return servers; } List notInvokedInstances = new ArrayList<>(); - if (CollectionUtils.isEmpty(existNeedWarmUpInstances(servers, notInvokedInstances))) { + List needWarmUpInstances = getNeedWarmUpInstances(servers, notInvokedInstances); + if (CollectionUtils.isEmpty(needWarmUpInstances)) { return servers; } @@ -115,19 +141,30 @@ public List getFilteredListOfServers(List // If exist not invoked instances, choose one that let it into warm up. if (!CollectionUtils.isEmpty(notInvokedInstances)) { setInstanceStartInvokeTime(notInvokedInstances.get(0)); + setInstanceRequestTimestamps(notInvokedInstances.get(0)); return Collections.singletonList(notInvokedInstances.get(0)); } + + // check instances allow request + List callableServers = getCallableServers(servers, needWarmUpInstances); + if(callableServers.size() == 1) { + setInstanceRequestTimestamps(callableServers.get(0)); + return callableServers; + } + if (CollectionUtils.isEmpty(callableServers)) { + callableServers = servers; + } int[] weights = new int[servers.size()]; int totalWeight = 0; int index = 0; - for (ServiceCombServer server : servers) { - weights[index] = calculate(server.getInstance().getProperties(), server.getInstance().getInstanceId()); + for (ServiceCombServer server : callableServers) { + weights[index] = calculateWeight(server.getInstance().getInstanceId()); totalWeight += weights[index++]; } return chooseServer(totalWeight, weights, servers); } - private List existNeedWarmUpInstances(List servers, + private List getNeedWarmUpInstances(List servers, List notInvokedInstances) { return servers.stream() .filter(server -> isInstanceNeedWarmUp(server, notInvokedInstances)) @@ -135,7 +172,6 @@ private List existNeedWarmUpInstances(List } private boolean isInstanceNeedWarmUp(ServiceCombServer server, List notInvokedInstances) { - Map properties = server.getInstance().getProperties(); Long invokeTime = instanceInvokeTime.get(buildCacheKey(server)); // instance have not been invoked need to be warn-up @@ -143,7 +179,6 @@ private boolean isInstanceNeedWarmUp(ServiceCombServer server, List chooseServer(int totalWeight, int[] weights, Lis if (LOGGER.isDebugEnabled()) { LOGGER.debug("warm up choose service instance: " + servers.get(i).getInstance().getInstanceId()); } + setInstanceRequestTimestamps(servers.get(i)); return Collections.singletonList(servers.get(i)); } } @@ -172,22 +208,11 @@ private String buildCacheKey(ServiceCombServer server) { return server.getInstance().getHostName() + "@" + server.getPort(); } - private int calculate(Map properties, String instanceId) { - if (instanceInvokeTime.get(instanceId) == null) { - return INSTANCE_WEIGHT; - } - final int warmUpCurve = Integer.parseInt(properties.getOrDefault(WARM_CURVE_KEY, DEFAULT_WARM_UP_CURVE)); - final long warmUpTime = Long.parseLong(properties.getOrDefault(WARM_TIME_KEY, DEFAULT_WARM_UP_TIME)); - return calculateWeight(instanceInvokeTime.get(instanceId), warmUpTime, warmUpCurve); - } - - private int calculateWeight(long invokeStartTime, long warmUpTime, int warmUpCurve) { - if (warmUpTime <= 0) { + private int calculateWeight(String instanceId) { + if (warmUpTime <= 0 || instanceInvokeTime.get(instanceId) == null) { return INSTANCE_WEIGHT; } - if (warmUpCurve <= 0) { - warmUpCurve = Integer.parseInt(DEFAULT_WARM_UP_CURVE); - } + long invokeStartTime = instanceInvokeTime.get(instanceId); // calculated in milliseconds final long runTime = System.currentTimeMillis() - invokeStartTime; @@ -210,4 +235,54 @@ private boolean checkProviderExist(String host, int port) { return false; } } + + public boolean allowRequest(Map requestTimestamps, int maxRequests) { + // if maxRequests less or equal 0 that mean not need limit + if (maxRequests <= 0) { + return true; + } + long currentTime = System.currentTimeMillis(); + requestTimestamps.entrySet().removeIf(entry -> currentTime - entry.getKey() > warmUpTime); + return requestTimestamps.size() <= maxRequests; + } + + private String getDynamicProperty(String key, String defaultValue) { + return DynamicPropertyFactory.getInstance() + .getStringProperty(key, defaultValue) + .get(); + } + + private List getCallableServers(List servers, + List needWarmUpInstances) { + List instanceIds = new ArrayList<>(); + List result = new ArrayList<>(); + + // check need warm up instance current requests. + needWarmUpInstances.forEach(server -> { + String instanceId = server.getInstance().getInstanceId(); + instanceIds.add(instanceId); + if (allowRequest(instanceRequestTimestamps.get(instanceId), warmUpMaxCall)) { + result.add(server); + } + }); + + // check warmed instances requests + servers.forEach(server -> { + String instanceId = server.getInstance().getInstanceId(); + if (!instanceIds.contains(instanceId)) { + if (allowRequest(instanceRequestTimestamps.get(instanceId), warmedMaxCall)) { + result.add(server); + } + } + }); + return result; + } + + private void setInstanceRequestTimestamps(ServiceCombServer server) { + String instanceId = server.getInstance().getInstanceId(); + if (instanceRequestTimestamps.get(instanceId) == null) { + instanceRequestTimestamps.put(instanceId, new ConcurrentHashMap<>()); + } + instanceRequestTimestamps.get(instanceId).put(System.currentTimeMillis(), 1); + } } From 92c50220477f99f636cf980819d44767a2a0a1ca Mon Sep 17 00:00:00 2001 From: chengyouling Date: Wed, 27 Nov 2024 21:24:44 +0800 Subject: [PATCH 15/16] fixed checkstyle --- .../loadbalance/filterext/WarmUpDiscoveryFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java index 84472386df0..294f878957b 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java @@ -147,7 +147,7 @@ public List getFilteredListOfServers(List // check instances allow request List callableServers = getCallableServers(servers, needWarmUpInstances); - if(callableServers.size() == 1) { + if (callableServers.size() == 1) { setInstanceRequestTimestamps(callableServers.get(0)); return callableServers; } From 8adf9d57a2ad07829a0d935ed7fc6d841c569d4f Mon Sep 17 00:00:00 2001 From: chengyouling Date: Thu, 28 Nov 2024 14:05:37 +0800 Subject: [PATCH 16/16] =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=B8=BA=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E8=8E=B7=E5=8F=96=E9=A2=84=E7=83=AD=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E3=80=81=E9=A2=84=E7=83=AD=E5=AE=9E=E4=BE=8B=E6=9C=80=E5=A4=A7?= =?UTF-8?q?=E6=B5=81=E9=87=8F=E7=AD=89=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application.yml | 6 ++ .../src/main/resources/application.yml | 6 ++ .../filterext/WarmUpDiscoveryFilter.java | 70 +++++++++++-------- 3 files changed, 51 insertions(+), 31 deletions(-) diff --git a/demo/demo-cse-v1/consumer/src/main/resources/application.yml b/demo/demo-cse-v1/consumer/src/main/resources/application.yml index 2b50e1a670c..7f52f380b9b 100644 --- a/demo/demo-cse-v1/consumer/src/main/resources/application.yml +++ b/demo/demo-cse-v1/consumer/src/main/resources/application.yml @@ -36,6 +36,12 @@ servicecomb: rest: address: 0.0.0.0:9092 # should be same with server.port to use web container + loadbalance: + filter: + service: + warmup: + enabled: true + routeRule: provider: | - precedence: 1 diff --git a/demo/demo-cse-v1/gateway/src/main/resources/application.yml b/demo/demo-cse-v1/gateway/src/main/resources/application.yml index 9f8b8c0b8ef..d0a6edd158b 100644 --- a/demo/demo-cse-v1/gateway/src/main/resources/application.yml +++ b/demo/demo-cse-v1/gateway/src/main/resources/application.yml @@ -35,6 +35,12 @@ servicecomb: rest: address: 0.0.0.0:9090?sslEnabled=false + loadbalance: + filter: + service: + warmup: + enabled: true + http: dispatcher: edge: diff --git a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java index 294f878957b..54c40d95f18 100644 --- a/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java +++ b/handlers/handler-loadbalance/src/main/java/org/apache/servicecomb/loadbalance/filterext/WarmUpDiscoveryFilter.java @@ -45,12 +45,12 @@ public class WarmUpDiscoveryFilter implements ServerListFilterExt { private static final int INSTANCE_WEIGHT = 100; // Default time for warm up, the unit is milliseconds - private static final String DEFAULT_WARM_UP_TIME = "30000"; + private static final long DEFAULT_WARM_UP_TIME = 30000L; // Preheat calculates curve value - private static final String DEFAULT_WARM_UP_CURVE = "2"; + private static final int DEFAULT_WARM_UP_CURVE = 2; - private static final String DEFAULT_WARM_UP_MAX_CALL = "50"; + private static final int DEFAULT_WARM_UP_MAX_CALL = 50; private static final String WARM_UP_TIME = "servicecomb.loadbalance.filter.service.warmup.warm-up-time"; @@ -62,14 +62,6 @@ public class WarmUpDiscoveryFilter implements ServerListFilterExt { // Maximum requests for instance that have been warmed up during the warm-up period private static final String WARMED_MAX_CALL = "servicecomb.loadbalance.filter.service.warmup.warmed-max-call"; - private final long warmUpTime; - - private final int warmUpCurve; - - private final int warmUpMaxCall; - - private final int warmedMaxCall; - private final Random random = new Random(); private final Map instanceInvokeTime = new ConcurrentHashMap<>(); @@ -82,17 +74,10 @@ public class WarmUpDiscoveryFilter implements ServerListFilterExt { return thread; }); - private long initTime = System.currentTimeMillis(); + private long refreshFlagTime = System.currentTimeMillis(); // 10 minutes - private static final long REFRESH_TIME = 10 * 60 * 1000; - - public WarmUpDiscoveryFilter() { - warmUpTime = Long.parseLong(getDynamicProperty(WARM_UP_TIME, DEFAULT_WARM_UP_TIME)); - warmUpCurve = Integer.parseInt(getDynamicProperty(WARM_UP_CURVE, DEFAULT_WARM_UP_CURVE)); - warmUpMaxCall = Integer.parseInt(getDynamicProperty(WARM_UP_MAX_CALL, DEFAULT_WARM_UP_MAX_CALL)); - warmedMaxCall = Integer.parseInt(getDynamicProperty(WARMED_MAX_CALL, warmUpMaxCall * 5 + "")); - } + private static final long REFRESH_INTERVAL_TIME = 10 * 60 * 1000; private void refreshMapCache() { List removeKeys = new ArrayList<>(); @@ -133,9 +118,9 @@ public List getFilteredListOfServers(List } // Refresh every 10 minutes - if (System.currentTimeMillis() - initTime >= REFRESH_TIME) { + if (System.currentTimeMillis() - refreshFlagTime >= REFRESH_INTERVAL_TIME) { warmUpExecutor.execute(this::refreshMapCache); - initTime = System.currentTimeMillis(); + refreshFlagTime = System.currentTimeMillis(); } // If exist not invoked instances, choose one that let it into warm up. @@ -179,7 +164,7 @@ private boolean isInstanceNeedWarmUp(ServiceCombServer server, List chooseServer(int totalWeight, int[] weights, List servers) { @@ -209,6 +194,7 @@ private String buildCacheKey(ServiceCombServer server) { } private int calculateWeight(String instanceId) { + long warmUpTime = getWarmUpTime(); if (warmUpTime <= 0 || instanceInvokeTime.get(instanceId) == null) { return INSTANCE_WEIGHT; } @@ -217,12 +203,13 @@ private int calculateWeight(String instanceId) { // calculated in milliseconds final long runTime = System.currentTimeMillis() - invokeStartTime; if (runTime > 0 && runTime < warmUpTime) { - return calculateWarmUpWeight(runTime, warmUpTime, warmUpCurve); + return calculateWarmUpWeight(runTime, warmUpTime); } return INSTANCE_WEIGHT; } - private int calculateWarmUpWeight(double runtime, double warmUpTime, int warmUpCurve) { + private int calculateWarmUpWeight(double runtime, double warmUpTime) { + int warmUpCurve = getWarmUpCurve(); final int round = (int) Math.round(Math.pow(runtime / warmUpTime, warmUpCurve) * INSTANCE_WEIGHT); return round < 1 ? 1 : Math.min(round, INSTANCE_WEIGHT); } @@ -242,22 +229,18 @@ public boolean allowRequest(Map requestTimestamps, int maxRequest return true; } long currentTime = System.currentTimeMillis(); + long warmUpTime = getWarmUpTime(); requestTimestamps.entrySet().removeIf(entry -> currentTime - entry.getKey() > warmUpTime); return requestTimestamps.size() <= maxRequests; } - private String getDynamicProperty(String key, String defaultValue) { - return DynamicPropertyFactory.getInstance() - .getStringProperty(key, defaultValue) - .get(); - } - private List getCallableServers(List servers, List needWarmUpInstances) { List instanceIds = new ArrayList<>(); List result = new ArrayList<>(); // check need warm up instance current requests. + int warmUpMaxCall = getWarmUpMaxCall(); needWarmUpInstances.forEach(server -> { String instanceId = server.getInstance().getInstanceId(); instanceIds.add(instanceId); @@ -265,6 +248,7 @@ private List getCallableServers(List serve result.add(server); } }); + int warmedMaxCall = getWarmedMaxCall(warmUpMaxCall * 5); // check warmed instances requests servers.forEach(server -> { @@ -285,4 +269,28 @@ private void setInstanceRequestTimestamps(ServiceCombServer server) { } instanceRequestTimestamps.get(instanceId).put(System.currentTimeMillis(), 1); } + + private long getWarmUpTime() { + return DynamicPropertyFactory.getInstance() + .getLongProperty(WARM_UP_TIME, DEFAULT_WARM_UP_TIME) + .get(); + } + + private int getWarmUpCurve() { + return DynamicPropertyFactory.getInstance() + .getIntProperty(WARM_UP_CURVE, DEFAULT_WARM_UP_CURVE) + .get(); + } + + private int getWarmUpMaxCall() { + return DynamicPropertyFactory.getInstance() + .getIntProperty(WARM_UP_MAX_CALL, DEFAULT_WARM_UP_MAX_CALL) + .get(); + } + + private int getWarmedMaxCall(int defaultValue) { + return DynamicPropertyFactory.getInstance() + .getIntProperty(WARMED_MAX_CALL, defaultValue) + .get(); + } }