diff --git a/CHANGELOG.md b/CHANGELOG.md index 33c973583..622d977b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,4 +16,5 @@ - [feature: optimize polaris-discovery-example/discovery-callee-service, add client-ip return.](https://github.com/Tencent/spring-cloud-tencent/commit/d2d66dccbef4b9b858885ae365e8f90e0e5555af) - [docs:prevent the release of the final version of the sdk.](https://github.com/Tencent/spring-cloud-tencent/commit/be4dc8063bf8feb45d1430de979e9a85339b53c8) - [feature: add config for customized local port.](https://github.com/Tencent/spring-cloud-tencent/commit/099508ea04687094e7ede8e5bb39eccc43287e5a) -- [feat:support webclient and gateway report call metrics]() +- [feat:support webclient and gateway report call metrics](https://github.com/Tencent/spring-cloud-tencent/commit/2e8074b16363d437e106b965003b9261157f6a9d) +- [feature: add polaris ring hash load balancer.]() diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java index 26d5fbb88..60f9359a0 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java @@ -39,7 +39,8 @@ import com.tencent.cloud.common.pojo.PolarisServer; import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.cloud.polaris.loadbalancer.LoadBalancerUtils; import com.tencent.cloud.polaris.loadbalancer.PolarisLoadBalancer; -import com.tencent.cloud.polaris.loadbalancer.PolarisWeightedRule; +import com.tencent.cloud.polaris.loadbalancer.PolarisRingHashRule; +import com.tencent.cloud.polaris.loadbalancer.PolarisWeightedRandomRule; import com.tencent.cloud.polaris.loadbalancer.config.PolarisLoadBalancerProperties; import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor; import com.tencent.cloud.polaris.router.spi.RouterResponseInterceptor; @@ -72,7 +73,8 @@ public class PolarisLoadBalancerCompositeRule extends AbstractLoadBalancerRule { final static String STRATEGY_RANDOM = "random"; final static String STRATEGY_ROUND_ROBIN = "roundRobin"; - final static String STRATEGY_WEIGHT = "polarisWeighted"; + final static String STRATEGY_WEIGHT = "polarisWeightedRandom"; + final static String STRATEGY_HASH_RING = "polarisRingHash"; final static String STRATEGY_RETRY = "retry"; final static String STRATEGY_RESPONSE_TIME_WEIGHTED = "responseTimeWeighted"; final static String STRATEGY_BEST_AVAILABLE = "bestAvailable"; @@ -228,7 +230,9 @@ public class PolarisLoadBalancerCompositeRule extends AbstractLoadBalancerRule { case STRATEGY_RANDOM: return new RandomRule(); case STRATEGY_WEIGHT: - return new PolarisWeightedRule(routerAPI); + return new PolarisWeightedRandomRule(routerAPI); + case STRATEGY_HASH_RING: + return new PolarisRingHashRule(routerAPI); case STRATEGY_RETRY: return new RetryRule(); case STRATEGY_RESPONSE_TIME_WEIGHTED: diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java index f3d8c0de9..66c53c52a 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java @@ -41,7 +41,7 @@ import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.pojo.PolarisServer; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; -import com.tencent.cloud.polaris.loadbalancer.PolarisWeightedRule; +import com.tencent.cloud.polaris.loadbalancer.PolarisWeightedRandomRule; import com.tencent.cloud.polaris.loadbalancer.config.PolarisLoadBalancerProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; @@ -140,7 +140,7 @@ public class PolarisLoadBalancerCompositeRuleTest { AbstractLoadBalancerRule lbRule = compositeRule.getRule(); - assertThat(lbRule).isInstanceOf(PolarisWeightedRule.class); + assertThat(lbRule).isInstanceOf(PolarisWeightedRandomRule.class); } @Test diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/pojo/PolarisServiceInstance.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/pojo/PolarisServiceInstance.java index 9bb0f793c..e4fc2934c 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/pojo/PolarisServiceInstance.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/pojo/PolarisServiceInstance.java @@ -51,6 +51,10 @@ public class PolarisServiceInstance implements ServiceInstance { } } + public Instance getPolarisInstance() { + return instance; + } + @Override public String getInstanceId() { return instance.getId(); diff --git a/spring-cloud-tencent-examples/polaris-discovery-example/discovery-caller-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-discovery-example/discovery-caller-service/src/main/resources/bootstrap.yml index 042246db0..cea3a922c 100644 --- a/spring-cloud-tencent-examples/polaris-discovery-example/discovery-caller-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/polaris-discovery-example/discovery-caller-service/src/main/resources/bootstrap.yml @@ -18,6 +18,8 @@ spring: stat: enabled: true port: 28081 + loadbalancer: + strategy: polarisWeightedRandom tencent: rpc-enhancement: reporter: diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancerRingHashKeyProvider.java b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancerRingHashKeyProvider.java new file mode 100644 index 000000000..8a94f799b --- /dev/null +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancerRingHashKeyProvider.java @@ -0,0 +1,42 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 com.tencent.cloud.polaris.loadbalancer; + +import com.tencent.cloud.common.metadata.MetadataContextHolder; + +/** + * PolarisLoadBalancerRingHashKeyProvider. + * + * @author seanthefish + */ +public final class PolarisLoadBalancerRingHashKeyProvider { + + private static final String LOAD_BALANCER_HASH_KEY = "LOAD_BALANCER_HASH_KEY"; + + private PolarisLoadBalancerRingHashKeyProvider() { + } + + public static void hashKey(String key) { + MetadataContextHolder.get().setLoadbalancer(LOAD_BALANCER_HASH_KEY, key); + } + + static String getHashKey() { + return MetadataContextHolder.get().getLoadbalancerMetadata().get(LOAD_BALANCER_HASH_KEY); + } + +} diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisRingHashRule.java b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisRingHashRule.java new file mode 100644 index 000000000..deba08ce5 --- /dev/null +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisRingHashRule.java @@ -0,0 +1,94 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 com.tencent.cloud.polaris.loadbalancer; + +import java.util.List; +import java.util.Optional; + +import com.netflix.client.config.IClientConfig; +import com.netflix.loadbalancer.AbstractServerPredicate; +import com.netflix.loadbalancer.AvailabilityPredicate; +import com.netflix.loadbalancer.CompositePredicate; +import com.netflix.loadbalancer.PredicateBasedRule; +import com.netflix.loadbalancer.Server; +import com.tencent.cloud.common.pojo.PolarisServer; +import com.tencent.polaris.api.config.consumer.LoadBalanceConfig; +import com.tencent.polaris.api.pojo.Instance; +import com.tencent.polaris.api.pojo.ServiceInstances; +import com.tencent.polaris.api.rpc.Criteria; +import com.tencent.polaris.router.api.core.RouterAPI; +import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceRequest; +import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceResponse; + +import org.springframework.util.CollectionUtils; + +/** + * Polaris weighted load balancer. + * + * @author lepdou 2022-05-17 + */ +public class PolarisRingHashRule extends PredicateBasedRule { + + private final RouterAPI routerAPI; + private CompositePredicate compositePredicate; + + public PolarisRingHashRule(RouterAPI routerAPI) { + this.routerAPI = routerAPI; + } + + @Override + public void initWithNiwsConfig(IClientConfig clientConfig) { + AvailabilityPredicate availabilityPredicate = new AvailabilityPredicate(this, clientConfig); + compositePredicate = CompositePredicate.withPredicates(availabilityPredicate).build(); + } + + @Override + public AbstractServerPredicate getPredicate() { + return compositePredicate; + } + + @Override + public Server choose(Object key) { + List servers = getLoadBalancer().getReachableServers(); + if (CollectionUtils.isEmpty(servers)) { + return null; + } + + // filter circuit breaker servers by ribbon + if (compositePredicate != null) { + servers = compositePredicate.getEligibleServers(servers); + } + + ServiceInstances serviceInstances = LoadBalancerUtils.transferServersToServiceInstances(servers); + + ProcessLoadBalanceRequest request = new ProcessLoadBalanceRequest(); + request.setDstInstances(serviceInstances); + request.setLbPolicy(LoadBalanceConfig.LOAD_BALANCE_RING_HASH); + Criteria criteria = new Criteria(); + String hashKey = Optional.ofNullable(PolarisLoadBalancerRingHashKeyProvider.getHashKey()).orElse(""); + criteria.setHashKey(hashKey); + request.setCriteria(criteria); + + ProcessLoadBalanceResponse processLoadBalanceResponse = routerAPI.processLoadBalance(request); + + Instance targetInstance = processLoadBalanceResponse.getTargetInstance(); + + return new PolarisServer(serviceInstances, targetInstance); + } +} diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRule.java b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRandomRule.java similarity index 92% rename from spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRule.java rename to spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRandomRule.java index 8c38d3a56..d21dba6a4 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRule.java +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRandomRule.java @@ -41,12 +41,12 @@ import org.springframework.util.CollectionUtils; * * @author lepdou 2022-05-17 */ -public class PolarisWeightedRule extends PredicateBasedRule { +public class PolarisWeightedRandomRule extends PredicateBasedRule { private final RouterAPI routerAPI; private CompositePredicate compositePredicate; - public PolarisWeightedRule(RouterAPI routerAPI) { + public PolarisWeightedRandomRule(RouterAPI routerAPI) { this.routerAPI = routerAPI; } @@ -69,7 +69,9 @@ public class PolarisWeightedRule extends PredicateBasedRule { } // filter circuit breaker servers by ribbon - servers = compositePredicate.getEligibleServers(servers); + if (compositePredicate != null) { + servers = compositePredicate.getEligibleServers(servers); + } ServiceInstances serviceInstances = LoadBalancerUtils.transferServersToServiceInstances(servers); diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRibbonClientConfiguration.java b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRibbonClientConfiguration.java index a7f6364c3..c41d9a4a3 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRibbonClientConfiguration.java +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRibbonClientConfiguration.java @@ -22,11 +22,18 @@ import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.IPing; import com.netflix.loadbalancer.IRule; +import com.netflix.loadbalancer.RandomRule; +import com.netflix.loadbalancer.RoundRobinRule; import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.ServerList; import com.tencent.cloud.polaris.loadbalancer.PolarisLoadBalancer; +import com.tencent.cloud.polaris.loadbalancer.PolarisRingHashRule; +import com.tencent.cloud.polaris.loadbalancer.PolarisWeightedRandomRule; import com.tencent.polaris.api.core.ConsumerAPI; +import com.tencent.polaris.router.api.core.RouterAPI; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; /** @@ -43,4 +50,32 @@ public class PolarisRibbonClientConfiguration { return new PolarisLoadBalancer(iClientConfig, iRule, iPing, serverList, consumerAPI, polarisLoadBalancerProperties); } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.strategy", havingValue = "roundRobin", matchIfMissing = true) + public IRule roundRobinRule() { + return new RoundRobinRule(); + } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.strategy", havingValue = "random") + public IRule randomRule() { + return new RandomRule(); + } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.strategy", havingValue = "polarisWeightedRandom") + public IRule polarisWeightedRandomRule(RouterAPI routerAPI) { + return new PolarisWeightedRandomRule(routerAPI); + } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.strategy", havingValue = "polarisRingHash") + public IRule polarisRingHashRule(RouterAPI routerAPI) { + return new PolarisRingHashRule(routerAPI); + } } diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-tencent-polaris-loadbalancer/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 5ecb156bc..4cba0a8c6 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -15,8 +15,31 @@ { "name": "spring.cloud.polaris.loadbalancer.strategy", "type": "java.lang.String", - "defaultValue": "random", - "description": "retry,best_available,availability_filtering,round_robin,weighted_response_time,zone_avoidance,random,consistent_hash,weighted_random." + "defaultValue": "roundRobin", + "description": "loadbalancer strategy." + } + ], + "hints": [ + { + "name": "spring.cloud.polaris.loadbalancer.strategy", + "values": [ + { + "value": "roundRobin", + "description": "round robin load balancer." + }, + { + "value": "random", + "description": "random load balancer." + }, + { + "value": "polarisWeightedRandom", + "description": "polaris weighted random load balancer." + }, + { + "value": "polarisRingHash", + "description": "polaris ring hash load balancer." + } + ] } ] } diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancerTest.java b/spring-cloud-tencent-polaris-loadbalancer/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancerTest.java index 4f1cfd20c..e633f553c 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancerTest.java +++ b/spring-cloud-tencent-polaris-loadbalancer/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancerTest.java @@ -79,7 +79,7 @@ public class PolarisLoadBalancerTest { //mock routerAPI for rule when(routerAPI.processLoadBalance(any())).thenReturn(assembleProcessLoadBalanceResp()); - PolarisWeightedRule rule = new PolarisWeightedRule(routerAPI); + PolarisWeightedRandomRule rule = new PolarisWeightedRandomRule(routerAPI); rule.initWithNiwsConfig(new DefaultClientConfigImpl()); // clientConfig @@ -111,7 +111,7 @@ public class PolarisLoadBalancerTest { public void testExtendDiscoveryServiceInstance() { //mock routerAPI for rule when(routerAPI.processLoadBalance(any())).thenReturn(assembleProcessLoadBalanceResp()); - PolarisWeightedRule rule = new PolarisWeightedRule(routerAPI); + PolarisWeightedRandomRule rule = new PolarisWeightedRandomRule(routerAPI); rule.initWithNiwsConfig(new DefaultClientConfigImpl()); // clientConfig