feat: support to 2020.0.1

pull/12/head
chuntaojun 4 years ago
parent d6d663f07e
commit 085ae91f77

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-build</artifactId>
<version>2.3.4.RELEASE</version>
<version>3.0.1</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -71,10 +71,10 @@
<properties>
<!-- Project revision -->
<revision>1.1.4.Hoxton.SR9-SNAPSHOT</revision>
<revision>2020.0.1-SNAPSHOT</revision>
<!-- Spring Cloud -->
<spring.cloud.version>Hoxton.SR9</spring.cloud.version>
<spring.cloud.version>2020.0.1</spring.cloud.version>
<!-- Maven Plugin Versions -->
<jacoco.version>0.8.3</jacoco.version>

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies-parent</artifactId>
<version>2.3.1.RELEASE</version>
<version>3.0.1</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -62,7 +62,8 @@
</developers>
<properties>
<revision>1.1.4.Hoxton.SR9-SNAPSHOT</revision>
<revision>2020.0.1-SNAPSHOT</revision>
<guava.version>23.0</guava.version>
<polaris.version>1.2.0</polaris.version>
<tomcat.version>10.0.0-M6</tomcat.version>
<powermock.version>2.0.0</powermock.version>

@ -20,7 +20,7 @@
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
<version>1.2.6</version>
<scope>compile</scope>
</dependency>
<dependency>
@ -53,12 +53,6 @@
<artifactId>feign-okhttp</artifactId>
</dependency>
<!-- 负载均衡依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<!-- 熔断超时后,重试机制依赖-->
<dependency>
<groupId>org.springframework.retry</groupId>

@ -20,7 +20,7 @@
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
<version>1.2.6</version>
<scope>compile</scope>
</dependency>
<dependency>
@ -51,12 +51,6 @@
<artifactId>feign-okhttp</artifactId>
</dependency>
<!-- 负载均衡依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<!-- 熔断超时后,重试机制依赖-->
<dependency>
<groupId>org.springframework.retry</groupId>

@ -42,18 +42,6 @@
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 熔断依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!-- 负载均衡依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<!-- 熔断超时后,重试机制依赖-->
<dependency>
<groupId>org.springframework.retry</groupId>

@ -43,18 +43,6 @@
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 熔断依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!-- 负载均衡依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<!-- 熔断超时后,重试机制依赖-->
<dependency>
<groupId>org.springframework.retry</groupId>

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>polaris-gateway-example</artifactId>
<groupId>com.tencent.cloud</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>gateway-zuul-service</artifactId>
<name>Spring Cloud Starter Tencent Polaris Gateway Zuul Example</name>
<dependencies>
<dependency>
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
<groupId>com.tencent.cloud</groupId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-polaris-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>

@ -1,20 +0,0 @@
server:
session-timeout: 1800
port: 48082
spring:
application:
name: GatewayZuulService
cloud:
polaris:
address: grpc://127.0.0.1:8091
tencent:
metadata:
content:
a: 1
transitive:
- a
zuul:
routes:
GatewayCalleeService:
serviceId: GatewayCalleeService
path: /GatewayCalleeService/**

@ -15,7 +15,6 @@
<name>Spring Cloud Starter Tencent Polaris Gateway Example</name>
<modules>
<module>gateway-zuul-service</module>
<module>gateway-scg-service</module>
<module>gateway-callee-service</module>
</modules>
@ -32,19 +31,6 @@
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 熔断依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!-- 负载均衡依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<!-- 熔断超时后,重试机制依赖-->
<dependency>
<groupId>org.springframework.retry</groupId>

@ -52,11 +52,5 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

@ -50,11 +50,6 @@
</dependency>
<!-- Polaris dependencies end -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
@ -67,6 +62,12 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
@ -90,5 +91,11 @@
<artifactId>powermock-api-mockito2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
<version>3.0.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

@ -0,0 +1,34 @@
/*
* 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.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
/**
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.polaris.enabled", havingValue = "true")
public @interface ConditionalOnLoadBalancerPolaris {
}

@ -15,23 +15,21 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.ribbon;
package com.tencent.cloud.polaris.loadbalancer;
import com.tencent.cloud.polaris.discovery.ConditionalOnPolarisDiscoveryEnabled;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.context.annotation.Configuration;
/**
* @author Haotian Zhang, Andrew Shan, Jie Cheng
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ConditionalOnLoadBalancerPolaris
@ConditionalOnPolarisDiscoveryEnabled
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@RibbonClients(defaultConfiguration = PolarisRibbonServerListConfiguration.class)
public class PolarisDiscoveryRibbonAutoConfiguration {
@LoadBalancerClients(defaultConfiguration = PolarisLoadBalancerClientConfiguration.class)
public class LoadBalancerPolarisAutoConfiguration {
}

@ -15,21 +15,16 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.gateway.example.zuul;
package com.tencent.cloud.polaris.loadbalancer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
import org.springframework.context.annotation.Configuration;
/**
* @author Haotian Zhang
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
*/
@SpringBootApplication
@EnableZuulProxy
public class GatewayZuulApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayZuulApplication.class, args);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
public class PolarisLoadBalancerClientConfiguration {
}

@ -0,0 +1,80 @@
/*
* 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.polaris.PolarisProperties;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import reactor.core.publisher.Mono;
/**
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
*/
public class PolarisLoadbalancer implements ReactorServiceInstanceLoadBalancer {
private static final Logger log = LoggerFactory.getLogger(PolarisLoadbalancer.class);
private final String serviceId;
private ObjectProvider<ServiceInstanceListSupplier> supplierObjectProvider;
private final PolarisProperties discoveryProperties;
public PolarisLoadbalancer(String serviceId,
ObjectProvider<ServiceInstanceListSupplier> supplierObjectProvider,
PolarisProperties discoveryProperties) {
this.serviceId = serviceId;
this.supplierObjectProvider = supplierObjectProvider;
this.discoveryProperties = discoveryProperties;
}
@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
ServiceInstanceListSupplier supplier = supplierObjectProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
return supplier.get().next().map(this::getInstanceResponse);
}
private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> serviceInstances) {
if (serviceInstances.isEmpty()) {
log.warn("No servers available for service: " + this.serviceId);
return new EmptyResponse();
}
try {
ServiceInstance instance = NacosBalancer.getHostByRandomWeight3(serviceInstances);
return new DefaultResponse(instance);
}
catch (Exception e) {
log.warn("NacosLoadBalancer error", e);
return new EmptyResponse();
}
}
}

@ -1,74 +0,0 @@
/*
* 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.ribbon;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractServerList;
import com.netflix.loadbalancer.Server;
import com.tencent.cloud.polaris.pojo.PolarisServer;
import com.tencent.polaris.api.pojo.Instance;
import com.tencent.polaris.api.pojo.ServiceInstances;
import com.tencent.polaris.api.rpc.InstancesResponse;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler;
import java.util.ArrayList;
import java.util.List;
/**
* @author Haotian Zhang, Andrew Shan, Jie Cheng
*/
public class PolarisServerList extends AbstractServerList<Server> {
private String serviceId;
private PolarisDiscoveryHandler polarisDiscoveryHandler;
public PolarisServerList(PolarisDiscoveryHandler polarisDiscoveryHandler) {
this.polarisDiscoveryHandler = polarisDiscoveryHandler;
}
@Override
public List<Server> getInitialListOfServers() {
return getServers();
}
@Override
public List<Server> getUpdatedListOfServers() {
return getServers();
}
private List<Server> getServers() {
InstancesResponse filteredInstances = polarisDiscoveryHandler.getInstances(serviceId);
ServiceInstances serviceInstances = filteredInstances.toServiceInstances();
List<Server> polarisServers = new ArrayList<>();
for (Instance instance : serviceInstances.getInstances()) {
polarisServers.add(new PolarisServer(serviceInstances, instance));
}
return polarisServers;
}
public String getServiceId() {
return serviceId;
}
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
this.serviceId = iClientConfig.getClientName();
}
}

@ -67,12 +67,6 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>

@ -31,6 +31,12 @@
</dependency>
<!-- Spring Cloud Tencent dependencies end -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
<optional>true</optional>
</dependency>
<!-- Polaris dependencies start -->
<dependency>
<groupId>com.tencent.polaris</groupId>
@ -43,12 +49,6 @@
<scope>test</scope>
</dependency>
<!-- Polaris dependencies end -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

@ -17,16 +17,9 @@
package com.tencent.cloud.polaris.router;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.PollingServerListUpdater;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerList;
import com.tencent.cloud.metadata.constant.MetadataConstant.SystemMetadataKey;
import com.tencent.cloud.metadata.context.MetadataContextHolder;
import com.tencent.cloud.polaris.pojo.PolarisServer;
import com.tencent.cloud.polaris.pojo.PolarisServiceInstance;
import com.tencent.polaris.api.pojo.DefaultInstance;
import com.tencent.polaris.api.pojo.DefaultServiceInstances;
import com.tencent.polaris.api.pojo.Instance;
@ -36,64 +29,48 @@ import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.router.api.core.RouterAPI;
import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest;
import com.tencent.polaris.router.api.rpc.ProcessRoutersResponse;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.util.CollectionUtils;
/**
* @author Haotian Zhang
*/
public class PolarisRoutingLoadBalancer extends DynamicServerListLoadBalancer<Server> {
public class PolarisRoutingLoadBalancer {
private final RouterAPI routerAPI;
public PolarisRoutingLoadBalancer(IClientConfig config, IRule rule, IPing ping,
ServerList<Server> serverList, RouterAPI routerAPI) {
super(config, rule, ping, serverList, null, new PollingServerListUpdater());
public PolarisRoutingLoadBalancer(RouterAPI routerAPI) {
this.routerAPI = routerAPI;
}
@Override
public List<Server> getReachableServers() {
List<Server> allServers = super.getAllServers();
public List<ServiceInstance> chooseInstances(List<ServiceInstance> allServers) {
if (CollectionUtils.isEmpty(allServers)) {
return allServers;
}
ServiceInstances serviceInstances = null;
if (allServers.get(0) instanceof PolarisServer) {
serviceInstances = ((PolarisServer) allServers.get(0)).getServiceInstances();
} else {
String serviceName;
// notice the difference between different service registries
if (StringUtils.isNotBlank(allServers.get(0).getMetaInfo().getServiceIdForDiscovery())) {
serviceName = allServers.get(0).getMetaInfo().getServiceIdForDiscovery();
} else {
serviceName = allServers.get(0).getMetaInfo().getAppName();
}
if (StringUtils.isBlank(serviceName)) {
throw new IllegalStateException(
"PolarisRoutingLoadBalancer only Server with AppName or ServiceIdForDiscovery attribute");
}
ServiceKey serviceKey = new ServiceKey(MetadataContextHolder.LOCAL_NAMESPACE, serviceName);
List<Instance> instances = new ArrayList<>(8);
for (Server server : allServers) {
DefaultInstance instance = new DefaultInstance();
instance.setNamespace(MetadataContextHolder.LOCAL_NAMESPACE);
instance.setService(serviceName);
instance.setHealthy(server.isAlive());
instance.setProtocol(server.getScheme());
instance.setId(server.getId());
instance.setHost(server.getHost());
instance.setPort(server.getPort());
instance.setZone(server.getZone());
instance.setWeight(100);
instances.add(instance);
}
serviceInstances = new DefaultServiceInstances(serviceKey, instances);
String serviceName = allServers.get(0).getServiceId();
if (StringUtils.isBlank(serviceName)) {
throw new IllegalStateException(
"PolarisRoutingLoadBalancer only Server with AppName or ServiceIdForDiscovery attribute");
}
ServiceKey serviceKey = new ServiceKey(MetadataContextHolder.LOCAL_NAMESPACE, serviceName);
List<Instance> instances = new ArrayList<>(8);
for (ServiceInstance server : allServers) {
DefaultInstance instance = new DefaultInstance();
instance.setNamespace(MetadataContextHolder.LOCAL_NAMESPACE);
instance.setService(serviceName);
instance.setProtocol(server.getScheme());
instance.setId(server.getInstanceId());
instance.setHost(server.getHost());
instance.setPort(server.getPort());
instance.setWeight(100);
instances.add(instance);
}
serviceInstances = new DefaultServiceInstances(serviceKey, instances);
ProcessRoutersRequest processRoutersRequest = new ProcessRoutersRequest();
processRoutersRequest.setDstInstances(serviceInstances);
String srcNamespace = MetadataContextHolder.get().getSystemMetadata(SystemMetadataKey.LOCAL_NAMESPACE);
@ -110,15 +87,11 @@ public class PolarisRoutingLoadBalancer extends DynamicServerListLoadBalancer<Se
}
ProcessRoutersResponse processRoutersResponse = routerAPI.processRouters(processRoutersRequest);
ServiceInstances filteredServiceInstances = processRoutersResponse.getServiceInstances();
List<Server> filteredInstances = new ArrayList<>();
List<ServiceInstance> filteredInstances = new ArrayList<>();
for (Instance instance : filteredServiceInstances.getInstances()) {
filteredInstances.add(new PolarisServer(serviceInstances, instance));
filteredInstances.add(new PolarisServiceInstance(instance));
}
return filteredInstances;
}
@Override
public List<Server> getAllServers() {
return getReachableServers();
}
}

@ -1,56 +0,0 @@
/*
* 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.router.config;
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.Server;
import com.netflix.loadbalancer.ServerList;
import com.tencent.cloud.polaris.router.PolarisRoutingLoadBalancer;
import com.tencent.cloud.polaris.router.rule.PolarisLoadBalanceRule;
import com.tencent.cloud.polaris.router.rule.PolarisWeightedRandomRule;
import com.tencent.polaris.router.api.core.RouterAPI;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author Haotian Zhang
*/
@Configuration
public class PolarisRibbonClientConfiguration {
@Bean
@ConditionalOnMissingBean
public IRule polarisRibbonRule(PolarisRibbonProperties polarisRibbonProperties) {
switch (PolarisLoadBalanceRule.fromStrategy(polarisRibbonProperties.getPolicy())) {
case WEIGHTED_RANDOM_RULE:
default:
return new PolarisWeightedRandomRule();
}
}
@Bean
@ConditionalOnMissingBean
public ILoadBalancer polarisRoutingLoadBalancer(IClientConfig iClientConfig, IRule iRule, IPing iPing,
ServerList<Server> serverList, RouterAPI polarisRouter) {
return new PolarisRoutingLoadBalancer(iClientConfig, iRule, iPing, serverList, polarisRouter);
}
}

@ -21,12 +21,9 @@ import com.tencent.polaris.api.exception.PolarisException;
import com.tencent.polaris.client.api.SDKContext;
import com.tencent.polaris.factory.api.RouterAPIFactory;
import com.tencent.polaris.router.api.core.RouterAPI;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -35,17 +32,15 @@ import org.springframework.context.annotation.Configuration;
*
* @author Haotian Zhang
*/
@Configuration(proxyBeanMethods = false)
@Configuration()
@EnableConfigurationProperties
@ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.enabled", matchIfMissing = true)
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@RibbonClients(defaultConfiguration = PolarisRibbonClientConfiguration.class)
public class PolarisRibbonAutoConfiguration {
public class PolarisRouterAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public PolarisRibbonProperties polarisRibbonProperties() {
return new PolarisRibbonProperties();
public PolarisRouterProperties polarisRibbonProperties() {
return new PolarisRouterProperties();
}
@Bean(name = "polarisRoute")

@ -15,28 +15,19 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.ribbon;
package com.tencent.cloud.polaris.router.config;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerList;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler;
import com.tencent.cloud.polaris.router.PolarisRoutingLoadBalancer;
import com.tencent.cloud.polaris.router.rule.PolarisLoadBalanceRule;
import com.tencent.polaris.router.api.core.RouterAPI;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author Haotian Zhang, Andrew Shan, Jie Cheng
* @author Haotian Zhang
*/
@Configuration
public class PolarisRibbonServerListConfiguration {
public class PolarisRouterClientConfiguration {
@Bean
@ConditionalOnMissingBean
public ServerList<Server> ribbonServerList(PolarisDiscoveryHandler polarisDiscoveryHandler,
IClientConfig iClientConfig) {
PolarisServerList serverList = new PolarisServerList(polarisDiscoveryHandler);
serverList.initWithNiwsConfig(iClientConfig);
return serverList;
}
}

@ -24,7 +24,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
* @author Haotian Zhang
*/
@ConfigurationProperties("spring.cloud.polaris.ribbon")
public class PolarisRibbonProperties {
public class PolarisRouterProperties {
/**
*

@ -1,67 +0,0 @@
/*
* 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.router.rule;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.Server;
import com.tencent.cloud.polaris.pojo.PolarisServer;
import com.tencent.polaris.api.config.consumer.LoadBalanceConfig;
import com.tencent.polaris.api.pojo.Instance;
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.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import java.util.List;
/**
* @author Haotian Zhang
*/
public class PolarisWeightedRandomRule extends AbstractLoadBalancerRule {
private static final String POLICY = LoadBalanceConfig.LOAD_BALANCE_WEIGHTED_RANDOM;
@Autowired
private RouterAPI polarisRouter;
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
@Override
public Server choose(Object key) {
List<Server> allServers = getLoadBalancer().getReachableServers();
if (CollectionUtils.isEmpty(allServers)) {
return null;
}
Server server = allServers.get(0);
if (!(server instanceof PolarisServer)) {
throw new IllegalStateException("PolarisDiscoveryRule only support PolarisServer instances");
}
PolarisServer polarisServer = (PolarisServer) server;
ProcessLoadBalanceRequest request = new ProcessLoadBalanceRequest();
request.setDstInstances(polarisServer.getServiceInstances());
request.setLbPolicy(POLICY);
ProcessLoadBalanceResponse processLoadBalanceResponse = polarisRouter.processLoadBalance(request);
Instance targetInstance = processLoadBalanceResponse.getTargetInstance();
return new PolarisServer(polarisServer.getServiceInstances(), targetInstance);
}
}

@ -1,2 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tencent.cloud.polaris.router.config.PolarisRibbonAutoConfiguration
com.tencent.cloud.polaris.router.config.PolarisRouterAutoConfiguration

@ -36,7 +36,7 @@ public class PolarisRibbonAutoConfigurationTest {
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(
PolarisRibbonTest.class,
PolarisRibbonAutoConfiguration.class))
PolarisRouterAutoConfiguration.class))
.withPropertyValues("spring.application.name=" + SERVICE_PROVIDER)
.withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081");
@ -45,7 +45,7 @@ public class PolarisRibbonAutoConfigurationTest {
public void testDefaultInitialization() {
this.contextRunner.run(context -> {
assertThat(context).hasSingleBean(RouterAPI.class);
assertThat(context).hasSingleBean(PolarisRibbonProperties.class);
assertThat(context).hasSingleBean(PolarisRouterProperties.class);
});
}

@ -42,15 +42,11 @@
<artifactId>spring-cloud-commons</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.google.guava</groupId>-->
<!-- <artifactId>guava</artifactId>-->
<!-- <version>${guava.version}</version>-->
<!-- </dependency>-->
<dependency>
<groupId>commons-collections</groupId>

@ -1,109 +0,0 @@
/*
* 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.pojo;
import com.google.common.base.Objects;
import com.netflix.loadbalancer.Server;
import com.tencent.polaris.api.pojo.Instance;
import com.tencent.polaris.api.pojo.ServiceInstances;
import org.apache.commons.lang.StringUtils;
import java.util.Map;
/**
* Polaris implementation of {@link Server}
*
* @author Haotian Zhang
*/
public class PolarisServer extends Server {
private final ServiceInstances serviceInstances;
private final Instance instance;
private final MetaInfo metaInfo;
public PolarisServer(ServiceInstances serviceInstances, Instance instance) {
super(instance.getHost(), instance.getPort());
if (StringUtils.equalsIgnoreCase(instance.getProtocol(), "https")) {
setSchemea("https");
} else {
setSchemea("http");
}
this.serviceInstances = serviceInstances;
this.instance = instance;
this.metaInfo = new MetaInfo() {
@Override
public String getAppName() {
return instance.getService();
}
@Override
public String getServerGroup() {
return null;
}
@Override
public String getServiceIdForDiscovery() {
return instance.getService();
}
@Override
public String getInstanceId() {
return instance.getId();
}
};
}
public Instance getInstance() {
return instance;
}
@Override
public MetaInfo getMetaInfo() {
return metaInfo;
}
public Map<String, String> getMetadata() {
return instance.getMetadata();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
PolarisServer that = (PolarisServer) o;
return Objects.equal(instance, that.instance);
}
@Override
public int hashCode() {
return Objects.hashCode(super.hashCode(), instance);
}
public ServiceInstances getServiceInstances() {
return serviceInstances;
}
}

@ -44,12 +44,6 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<scope>test</scope>
</dependency>
<!-- powermock-module-junit4 -->
<dependency>
<groupId>org.powermock</groupId>

@ -30,13 +30,6 @@
<artifactId>spring-cloud-starter-tencent-polaris-ratelimit</artifactId>
</dependency>
<!-- Spring Cloud Tencent dependencies end -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>

@ -17,14 +17,9 @@
package com.tencent.cloud.polaris.gateway.config;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.http.ZuulServlet;
import com.tencent.cloud.polaris.gateway.core.scg.filter.Metadata2HeaderScgFilter;
import com.tencent.cloud.polaris.gateway.core.scg.filter.MetadataFirstScgFilter;
import com.tencent.cloud.polaris.gateway.core.scg.filter.RateLimitScgFilter;
import com.tencent.cloud.polaris.gateway.core.zuul.filter.Metadata2HeaderZuulFilter;
import com.tencent.cloud.polaris.gateway.core.zuul.filter.MetadataFirstZuulFilter;
import com.tencent.cloud.polaris.gateway.core.zuul.filter.RateLimitZuulFilter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
@ -38,25 +33,7 @@ import org.springframework.context.annotation.Configuration;
@Configuration
public class PolarisGatewayAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ZuulServlet.class)
static class PolarisGatewayZuulAutoConfiguration {
@Bean
public ZuulFilter metadataFirstZuulFilter() {
return new MetadataFirstZuulFilter();
}
@Bean
public ZuulFilter rateLimitZuulFilter() {
return new RateLimitZuulFilter();
}
@Bean
public ZuulFilter metadata2HeaderZuulFilter() {
return new Metadata2HeaderZuulFilter();
}
}
@Configuration(proxyBeanMethods = false)
@Configuration()
@ConditionalOnClass(GlobalFilter.class)
static class PolarisGatewayScgAutoConfiguration {
@Bean

@ -1,79 +0,0 @@
/*
* 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.gateway.core.zuul.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.tencent.cloud.metadata.constant.MetadataConstant;
import com.tencent.cloud.metadata.context.MetadataContext;
import com.tencent.cloud.metadata.context.MetadataContextHolder;
import com.tencent.cloud.metadata.util.JacksonUtils;
import org.springframework.util.CollectionUtils;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.RIBBON_ROUTING_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.ROUTE_TYPE;
/**
* Zuul filter used for writing metadata in HTTP request header.
*
* @author skyehtzhang
*/
public class Metadata2HeaderZuulFilter extends ZuulFilter {
@Override
public String filterType() {
return ROUTE_TYPE;
}
@Override
public int filterOrder() {
return RIBBON_ROUTING_FILTER_ORDER - 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
// get request context
RequestContext requestContext = RequestContext.getCurrentContext();
// get metadata of current thread
MetadataContext metadataContext = MetadataContextHolder.get();
// add new metadata and cover old
Map<String, String> customMetadata = metadataContext.getAllTransitiveCustomMetadata();
if (!CollectionUtils.isEmpty(customMetadata)) {
String metadataStr = JacksonUtils.serialize2Json(customMetadata);
try {
requestContext.addZuulRequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA,
URLEncoder.encode(metadataStr, "UTF-8"));
} catch (UnsupportedEncodingException e) {
requestContext.addZuulRequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA, metadataStr);
}
}
return null;
}
}

@ -1,64 +0,0 @@
/*
* 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.gateway.core.zuul.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.tencent.cloud.metadata.constant.MetadataConstant;
import com.tencent.cloud.metadata.context.MetadataContextHolder;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.REQUEST_URI_KEY;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SERVICE_ID_KEY;
/**
* Zuul filter used for setting peer info in context.
*
* @author Haotian Zhang
*/
public class MetadataFirstZuulFilter extends ZuulFilter {
@Override
public String filterType() {
return PRE_TYPE;
}
@Override
public int filterOrder() {
return PRE_DECORATION_FILTER_ORDER + 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
// get request context
RequestContext requestContext = RequestContext.getCurrentContext();
// TODO 对端命名空间暂时与本地命名空间相同
MetadataContextHolder.get().putSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_NAMESPACE,
MetadataContextHolder.get().getSystemMetadata(MetadataConstant.SystemMetadataKey.LOCAL_NAMESPACE));
MetadataContextHolder.get().putSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_SERVICE,
(String) requestContext.get(SERVICE_ID_KEY));
MetadataContextHolder.get().putSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_PATH,
(String) requestContext.get(REQUEST_URI_KEY));
return null;
}
}

@ -1,99 +0,0 @@
/*
* 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.gateway.core.zuul.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.tencent.cloud.metadata.constant.MetadataConstant;
import com.tencent.cloud.metadata.context.MetadataContextHolder;
import com.tencent.cloud.polaris.ratelimit.utils.Consts;
import com.tencent.cloud.polaris.ratelimit.utils.QuotaCheckUtils;
import com.tencent.polaris.ratelimit.api.core.LimitAPI;
import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse;
import com.tencent.polaris.ratelimit.api.rpc.QuotaResultCode;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashMap;
import java.util.Map;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.RIBBON_ROUTING_FILTER_ORDER;
import static org.springframework.http.HttpStatus.TOO_MANY_REQUESTS;
/**
* Zuul filter used for rate limit.
*
* @author Haotian Zhang
*/
public class RateLimitZuulFilter extends ZuulFilter {
private static final Logger LOG = LoggerFactory.getLogger(RateLimitZuulFilter.class);
@Autowired(required = false)
private LimitAPI limitAPI;
@Override
public String filterType() {
return PRE_TYPE;
}
@Override
public int filterOrder() {
return RIBBON_ROUTING_FILTER_ORDER - 1;
}
@Override
public boolean shouldFilter() {
return limitAPI != null;
}
@Override
public Object run() {
// get request context
RequestContext requestContext = RequestContext.getCurrentContext();
String peerNamespace =
MetadataContextHolder.get().getSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_NAMESPACE);
String peerService =
MetadataContextHolder.get().getSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_SERVICE);
String peerPath = MetadataContextHolder.get().getSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_PATH);
Map<String, String> labels = null;
if (StringUtils.isNotBlank(peerPath)) {
labels = new HashMap<>();
labels.put("method", peerPath);
}
try {
QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, peerNamespace, peerService, 1, labels,
null);
if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) {
requestContext.setSendZuulResponse(false);
requestContext.setResponseStatusCode(TOO_MANY_REQUESTS.value());
requestContext.getResponse().getWriter().write(Consts.QUOTA_LIMITED_INFO + quotaResponse.getInfo());
}
} catch (Throwable throwable) {
//限流API调用出现异常不应该影响业务流程的调用
LOG.error("fail to rate limit with QuotaRequest[{}-{}-{}].", peerNamespace, peerService, peerPath,
throwable);
}
return null;
}
}
Loading…
Cancel
Save