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 60f9359a0..96545d621 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 @@ -41,6 +41,7 @@ import com.tencent.cloud.polaris.loadbalancer.LoadBalancerUtils; import com.tencent.cloud.polaris.loadbalancer.PolarisLoadBalancer; import com.tencent.cloud.polaris.loadbalancer.PolarisRingHashRule; import com.tencent.cloud.polaris.loadbalancer.PolarisWeightedRandomRule; +import com.tencent.cloud.polaris.loadbalancer.PolarisWeightedRoundRobinRule; import com.tencent.cloud.polaris.loadbalancer.config.PolarisLoadBalancerProperties; import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor; import com.tencent.cloud.polaris.router.spi.RouterResponseInterceptor; @@ -74,6 +75,7 @@ public class PolarisLoadBalancerCompositeRule extends AbstractLoadBalancerRule { final static String STRATEGY_RANDOM = "random"; final static String STRATEGY_ROUND_ROBIN = "roundRobin"; final static String STRATEGY_WEIGHT = "polarisWeightedRandom"; + final static String STRATEGY_WEIGHT_ROUND_ROBIN = "polarisWeightedRoundRobin"; final static String STRATEGY_HASH_RING = "polarisRingHash"; final static String STRATEGY_RETRY = "retry"; final static String STRATEGY_RESPONSE_TIME_WEIGHTED = "responseTimeWeighted"; @@ -231,6 +233,8 @@ public class PolarisLoadBalancerCompositeRule extends AbstractLoadBalancerRule { return new RandomRule(); case STRATEGY_WEIGHT: return new PolarisWeightedRandomRule(routerAPI); + case STRATEGY_WEIGHT_ROUND_ROBIN: + return new PolarisWeightedRoundRobinRule(routerAPI); case STRATEGY_HASH_RING: return new PolarisRingHashRule(routerAPI); case STRATEGY_RETRY: 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 66c53c52a..a48840ace 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 @@ -42,6 +42,7 @@ 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.PolarisWeightedRandomRule; +import com.tencent.cloud.polaris.loadbalancer.PolarisWeightedRoundRobinRule; 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; @@ -143,6 +144,17 @@ public class PolarisLoadBalancerCompositeRuleTest { assertThat(lbRule).isInstanceOf(PolarisWeightedRandomRule.class); } + @Test + public void testWeightRRLB() { + when(polarisLoadBalancerProperties.getStrategy()).thenReturn(PolarisLoadBalancerCompositeRule.STRATEGY_WEIGHT_ROUND_ROBIN); + PolarisLoadBalancerCompositeRule compositeRule = new PolarisLoadBalancerCompositeRule(routerAPI, + polarisLoadBalancerProperties, config, requestInterceptors, null, null); + + AbstractLoadBalancerRule lbRule = compositeRule.getRule(); + + assertThat(lbRule).isInstanceOf(PolarisWeightedRoundRobinRule.class); + } + @Test public void testRetryLB() { when(polarisLoadBalancerProperties.getStrategy()).thenReturn(PolarisLoadBalancerCompositeRule.STRATEGY_RETRY); diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/AbstractPolarisRule.java b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/AbstractPolarisRule.java new file mode 100644 index 000000000..8a02dffed --- /dev/null +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/AbstractPolarisRule.java @@ -0,0 +1,84 @@ +/* + * 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 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.pojo.Instance; +import com.tencent.polaris.api.pojo.ServiceInstances; +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; + +/** + * Abstract polaris load balancer rule. + * + * @author veteranchen + */ +public abstract class AbstractPolarisRule extends PredicateBasedRule { + private final RouterAPI routerAPI; + private CompositePredicate compositePredicate; + + public AbstractPolarisRule(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 = setProcessLoadBalanceRequest(request); + ProcessLoadBalanceResponse processLoadBalanceResponse = routerAPI.processLoadBalance(request); + Instance targetInstance = processLoadBalanceResponse.getTargetInstance(); + return new PolarisServer(serviceInstances, targetInstance); + } + + protected abstract ProcessLoadBalanceRequest setProcessLoadBalanceRequest(ProcessLoadBalanceRequest request); +} 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 index deba08ce5..a9d240024 100644 --- 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 @@ -18,77 +18,31 @@ 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 class PolarisRingHashRule extends AbstractPolarisRule { 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; + super(routerAPI); } @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); + protected ProcessLoadBalanceRequest setProcessLoadBalanceRequest(ProcessLoadBalanceRequest request) { 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); + return request; } } diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRandomRule.java b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRandomRule.java index d21dba6a4..00b14fc1c 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRandomRule.java +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRandomRule.java @@ -18,71 +18,24 @@ package com.tencent.cloud.polaris.loadbalancer; -import java.util.List; - -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.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 PolarisWeightedRandomRule extends PredicateBasedRule { - - private final RouterAPI routerAPI; - private CompositePredicate compositePredicate; +public class PolarisWeightedRandomRule extends AbstractPolarisRule { public PolarisWeightedRandomRule(RouterAPI routerAPI) { - this.routerAPI = routerAPI; - } - - @Override - public void initWithNiwsConfig(IClientConfig clientConfig) { - AvailabilityPredicate availabilityPredicate = new AvailabilityPredicate(this, clientConfig); - compositePredicate = CompositePredicate.withPredicates(availabilityPredicate).build(); + super(routerAPI); } @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); + protected ProcessLoadBalanceRequest setProcessLoadBalanceRequest(ProcessLoadBalanceRequest request) { request.setLbPolicy(LoadBalanceConfig.LOAD_BALANCE_WEIGHTED_RANDOM); - - ProcessLoadBalanceResponse processLoadBalanceResponse = routerAPI.processLoadBalance(request); - - Instance targetInstance = processLoadBalanceResponse.getTargetInstance(); - - return new PolarisServer(serviceInstances, targetInstance); + return request; } } diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRoundRobinRule.java b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRoundRobinRule.java new file mode 100644 index 000000000..089d99264 --- /dev/null +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRoundRobinRule.java @@ -0,0 +1,41 @@ +/* + * 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.polaris.api.config.consumer.LoadBalanceConfig; +import com.tencent.polaris.router.api.core.RouterAPI; +import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceRequest; + +/** + * Polaris weighted load balancer. + * + * @author veteranchen + */ +public class PolarisWeightedRoundRobinRule extends AbstractPolarisRule { + + public PolarisWeightedRoundRobinRule(RouterAPI routerAPI) { + super(routerAPI); + } + + @Override + protected ProcessLoadBalanceRequest setProcessLoadBalanceRequest(ProcessLoadBalanceRequest request) { + request.setLbPolicy(LoadBalanceConfig.LOAD_BALANCE_WEIGHTED_ROUND_ROBIN); + return request; + } +} 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 ac2643b24..8156b6c73 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 @@ -30,6 +30,7 @@ import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.cloud.polaris.loadbalancer.PolarisLoadBalancer; import com.tencent.cloud.polaris.loadbalancer.PolarisRingHashRule; import com.tencent.cloud.polaris.loadbalancer.PolarisWeightedRandomRule; +import com.tencent.cloud.polaris.loadbalancer.PolarisWeightedRoundRobinRule; import com.tencent.cloud.polaris.loadbalancer.transformer.InstanceTransformer; import org.springframework.beans.factory.annotation.Autowired; @@ -74,6 +75,13 @@ public class PolarisRibbonClientConfiguration { return new PolarisWeightedRandomRule(polarisSDKContextManager.getRouterAPI()); } + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.strategy", havingValue = "polarisWeightedRoundRobin") + public IRule polarisWeightedRoundRobinRule(PolarisSDKContextManager polarisSDKContextManager) { + return new PolarisWeightedRoundRobinRule(polarisSDKContextManager.getRouterAPI()); + } + @Bean @ConditionalOnMissingBean @ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.strategy", havingValue = "polarisRingHash") 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 4cba0a8c6..9235e861d 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 @@ -35,6 +35,10 @@ "value": "polarisWeightedRandom", "description": "polaris weighted random load balancer." }, + { + "value": "polarisWeightedRoundRobin", + "description": "polaris weighted round robin 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 4bbf896a0..c89ff97ef 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 @@ -26,6 +26,8 @@ import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.DummyPing; import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.ServerList; +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.cloud.polaris.loadbalancer.config.PolarisLoadBalancerProperties; import com.tencent.polaris.api.core.ConsumerAPI; @@ -82,6 +84,12 @@ public class PolarisLoadBalancerTest { PolarisWeightedRandomRule rule = new PolarisWeightedRandomRule(routerAPI); rule.initWithNiwsConfig(new DefaultClientConfigImpl()); + PolarisWeightedRoundRobinRule rrRule = new PolarisWeightedRoundRobinRule(routerAPI); + rule.initWithNiwsConfig(new DefaultClientConfigImpl()); + + PolarisRingHashRule hashRule = new PolarisRingHashRule(routerAPI); + hashRule.initWithNiwsConfig(new DefaultClientConfigImpl()); + // clientConfig IClientConfig config = new DefaultClientConfigImpl(); config.loadProperties(CLIENT_NAME); @@ -104,6 +112,21 @@ public class PolarisLoadBalancerTest { Assertions.assertThat(host).isNotNull(); Assertions.assertThat(host).isEqualTo("127.0.0.1:8080"); + + balancer = new PolarisLoadBalancer(config, rrRule, new DummyPing(), emptyServerList, + consumerAPI, properties, null); + host = balancer.choose(null); + Assertions.assertThat(host).isNotNull(); + Assertions.assertThat(host).isEqualTo("127.0.0.1:8080"); + + balancer = new PolarisLoadBalancer(config, hashRule, new DummyPing(), emptyServerList, + consumerAPI, properties, null); + MetadataContext context = new MetadataContext(); + context.setLoadbalancer("LOAD_BALANCER_HASH_KEY", "hash_key_1"); + MetadataContextHolder.set(context); + host = balancer.choose(null); + Assertions.assertThat(host).isNotNull(); + Assertions.assertThat(host).isEqualTo("127.0.0.1:8080"); } }