feature: add polaris ring hash load balancer.

pull/1080/head
Shanyou Yu (Sean Yu) 2 years ago committed by Haotian Zhang
parent 2e8074b163
commit b10ef1bf70

@ -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) - [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) - [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) - [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.]()

@ -39,7 +39,8 @@ import com.tencent.cloud.common.pojo.PolarisServer;
import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.polaris.loadbalancer.LoadBalancerUtils; import com.tencent.cloud.polaris.loadbalancer.LoadBalancerUtils;
import com.tencent.cloud.polaris.loadbalancer.PolarisLoadBalancer; 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.loadbalancer.config.PolarisLoadBalancerProperties;
import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor; import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor;
import com.tencent.cloud.polaris.router.spi.RouterResponseInterceptor; 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_RANDOM = "random";
final static String STRATEGY_ROUND_ROBIN = "roundRobin"; 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_RETRY = "retry";
final static String STRATEGY_RESPONSE_TIME_WEIGHTED = "responseTimeWeighted"; final static String STRATEGY_RESPONSE_TIME_WEIGHTED = "responseTimeWeighted";
final static String STRATEGY_BEST_AVAILABLE = "bestAvailable"; final static String STRATEGY_BEST_AVAILABLE = "bestAvailable";
@ -228,7 +230,9 @@ public class PolarisLoadBalancerCompositeRule extends AbstractLoadBalancerRule {
case STRATEGY_RANDOM: case STRATEGY_RANDOM:
return new RandomRule(); return new RandomRule();
case STRATEGY_WEIGHT: case STRATEGY_WEIGHT:
return new PolarisWeightedRule(routerAPI); return new PolarisWeightedRandomRule(routerAPI);
case STRATEGY_HASH_RING:
return new PolarisRingHashRule(routerAPI);
case STRATEGY_RETRY: case STRATEGY_RETRY:
return new RetryRule(); return new RetryRule();
case STRATEGY_RESPONSE_TIME_WEIGHTED: case STRATEGY_RESPONSE_TIME_WEIGHTED:

@ -41,7 +41,7 @@ import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.pojo.PolarisServer; import com.tencent.cloud.common.pojo.PolarisServer;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils; 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.loadbalancer.config.PolarisLoadBalancerProperties;
import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterProperties;
import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties;
@ -140,7 +140,7 @@ public class PolarisLoadBalancerCompositeRuleTest {
AbstractLoadBalancerRule lbRule = compositeRule.getRule(); AbstractLoadBalancerRule lbRule = compositeRule.getRule();
assertThat(lbRule).isInstanceOf(PolarisWeightedRule.class); assertThat(lbRule).isInstanceOf(PolarisWeightedRandomRule.class);
} }
@Test @Test

@ -51,6 +51,10 @@ public class PolarisServiceInstance implements ServiceInstance {
} }
} }
public Instance getPolarisInstance() {
return instance;
}
@Override @Override
public String getInstanceId() { public String getInstanceId() {
return instance.getId(); return instance.getId();

@ -18,6 +18,8 @@ spring:
stat: stat:
enabled: true enabled: true
port: 28081 port: 28081
loadbalancer:
strategy: polarisWeightedRandom
tencent: tencent:
rpc-enhancement: rpc-enhancement:
reporter: reporter:

@ -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);
}
}

@ -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<Server> 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);
}
}

@ -41,12 +41,12 @@ import org.springframework.util.CollectionUtils;
* *
* @author lepdou 2022-05-17 * @author lepdou 2022-05-17
*/ */
public class PolarisWeightedRule extends PredicateBasedRule { public class PolarisWeightedRandomRule extends PredicateBasedRule {
private final RouterAPI routerAPI; private final RouterAPI routerAPI;
private CompositePredicate compositePredicate; private CompositePredicate compositePredicate;
public PolarisWeightedRule(RouterAPI routerAPI) { public PolarisWeightedRandomRule(RouterAPI routerAPI) {
this.routerAPI = routerAPI; this.routerAPI = routerAPI;
} }
@ -69,7 +69,9 @@ public class PolarisWeightedRule extends PredicateBasedRule {
} }
// filter circuit breaker servers by ribbon // filter circuit breaker servers by ribbon
if (compositePredicate != null) {
servers = compositePredicate.getEligibleServers(servers); servers = compositePredicate.getEligibleServers(servers);
}
ServiceInstances serviceInstances = LoadBalancerUtils.transferServersToServiceInstances(servers); ServiceInstances serviceInstances = LoadBalancerUtils.transferServersToServiceInstances(servers);

@ -22,11 +22,18 @@ import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.IPing; import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.RoundRobinRule;
import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerList; import com.netflix.loadbalancer.ServerList;
import com.tencent.cloud.polaris.loadbalancer.PolarisLoadBalancer; 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.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; import org.springframework.context.annotation.Bean;
/** /**
@ -43,4 +50,32 @@ public class PolarisRibbonClientConfiguration {
return new PolarisLoadBalancer(iClientConfig, iRule, iPing, serverList, return new PolarisLoadBalancer(iClientConfig, iRule, iPing, serverList,
consumerAPI, polarisLoadBalancerProperties); 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);
}
} }

@ -15,8 +15,31 @@
{ {
"name": "spring.cloud.polaris.loadbalancer.strategy", "name": "spring.cloud.polaris.loadbalancer.strategy",
"type": "java.lang.String", "type": "java.lang.String",
"defaultValue": "random", "defaultValue": "roundRobin",
"description": "retry,best_available,availability_filtering,round_robin,weighted_response_time,zone_avoidance,random,consistent_hash,weighted_random." "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."
}
]
} }
] ]
} }

@ -79,7 +79,7 @@ public class PolarisLoadBalancerTest {
//mock routerAPI for rule //mock routerAPI for rule
when(routerAPI.processLoadBalance(any())).thenReturn(assembleProcessLoadBalanceResp()); when(routerAPI.processLoadBalance(any())).thenReturn(assembleProcessLoadBalanceResp());
PolarisWeightedRule rule = new PolarisWeightedRule(routerAPI); PolarisWeightedRandomRule rule = new PolarisWeightedRandomRule(routerAPI);
rule.initWithNiwsConfig(new DefaultClientConfigImpl()); rule.initWithNiwsConfig(new DefaultClientConfigImpl());
// clientConfig // clientConfig
@ -111,7 +111,7 @@ public class PolarisLoadBalancerTest {
public void testExtendDiscoveryServiceInstance() { public void testExtendDiscoveryServiceInstance() {
//mock routerAPI for rule //mock routerAPI for rule
when(routerAPI.processLoadBalance(any())).thenReturn(assembleProcessLoadBalanceResp()); when(routerAPI.processLoadBalance(any())).thenReturn(assembleProcessLoadBalanceResp());
PolarisWeightedRule rule = new PolarisWeightedRule(routerAPI); PolarisWeightedRandomRule rule = new PolarisWeightedRandomRule(routerAPI);
rule.initWithNiwsConfig(new DefaultClientConfigImpl()); rule.initWithNiwsConfig(new DefaultClientConfigImpl());
// clientConfig // clientConfig

Loading…
Cancel
Save