sync hoxton version:

1. support get service list from polaris
2. optimize health check
3. support multi registry center
4. upgrade spring boot/spring cloud version
pull/55/head
lepdou 4 years ago
parent d6cbb7f96e
commit 69d47d5517

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-build</artifactId>
<version>3.0.1</version>
<version>3.0.4</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -74,7 +74,7 @@
<revision>1.0.0.2020-SNAPSHOT</revision>
<!-- Spring Cloud -->
<spring.cloud.version>2020.0.1</spring.cloud.version>
<spring.cloud.version>2020.0.5</spring.cloud.version>
<!-- Maven Plugin Versions -->
<jacoco.version>0.8.3</jacoco.version>

@ -64,7 +64,7 @@
<properties>
<revision>1.0.0.2020-SNAPSHOT</revision>
<guava.version>23.0</guava.version>
<polaris.version>1.2.0</polaris.version>
<polaris.version>1.3.0-SNAPSHOT</polaris.version>
<tomcat.version>10.0.0-M6</tomcat.version>
<powermock.version>2.0.0</powermock.version>

@ -24,15 +24,6 @@
<groupId>com.tencent.cloud</groupId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-consul-discovery</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!-- </dependency>-->
</dependencies>
<build>
<plugins>

@ -6,20 +6,3 @@ spring:
cloud:
polaris:
address: grpc://127.0.0.1:8091
consul:
port: 8500
host: 127.0.0.1
enabled: true
discovery:
register: true
health-check-path: /actuator/health
health-check-interval: 10s
instance-id: ${spring.application.name}:${server.port}
enabled: true
service-name: ${spring.application.name}
ip-address: localhost
prefer-ip-address: true
eureka:
client:
serviceUrl:
defaultZone: http://127.0.0.1:7654/eureka/

@ -28,16 +28,6 @@
<groupId>com.tencent.cloud</groupId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-consul-discovery</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-router</artifactId>

@ -8,20 +8,3 @@ spring:
configurations: default
polaris:
address: grpc://127.0.0.1:8091
consul:
port: 8500
host: 127.0.0.1
enabled: true
discovery:
register: true
health-check-path: /actuator/health
health-check-interval: 10s
instance-id: ${spring.application.name}:${server.port}
enabled: true
service-name: ${spring.application.name}
ip-address: localhost
prefer-ip-address: true
eureka:
client:
serviceUrl:
defaultZone: http://127.0.0.1:7654/eureka/

@ -15,18 +15,19 @@
<dependencies>
<dependency>
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-polaris-gateway</artifactId>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 3.0之后如果网关需要开启 lb: 模式,需要额外引入 spring-cloud-loadbalancer -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
</dependencies>
</project>

@ -17,6 +17,7 @@
package com.tencent.cloud.polaris.circuitbreaker;
import com.tencent.cloud.constant.ContextConstant;
import com.tencent.cloud.polaris.circuitbreaker.feign.PolarisFeignBeanPostProcessor;
import com.tencent.cloud.polaris.context.PolarisConfigModifier;
import com.tencent.cloud.polaris.context.PolarisContextConfiguration;
@ -71,5 +72,10 @@ public class PolarisFeignClientAutoConfiguration {
//开启熔断配置
configuration.getConsumer().getCircuitBreaker().setEnable(true);
}
@Override
public int getOrder() {
return ContextConstant.ModifierOrder.CIRCUIT_BREAKER_ORDER;
}
}
}

@ -96,6 +96,12 @@ public class PolarisProperties {
@Value("${spring.cloud.polaris.discovery.heartbeat.enabled:#{false}}")
private Boolean heartbeatEnabled = true;
/**
* Custom health check url to override default
*/
@Value("${spring.cloud.polaris.discovery.health-check-url:}")
private String healthCheckUrl;
@Autowired
private Environment environment;
@ -210,6 +216,14 @@ public class PolarisProperties {
this.port = port;
}
public String getHealthCheckUrl() {
return healthCheckUrl;
}
public void setHealthCheckUrl(String healthCheckUrl) {
this.healthCheckUrl = healthCheckUrl;
}
@Override
@SuppressWarnings("checkstyle:all")
public String toString() {
@ -225,6 +239,7 @@ public class PolarisProperties {
", policy='" + policy + '\'' +
", registerEnabled=" + registerEnabled +
", heartbeatEnabled=" + heartbeatEnabled +
", healthCheckUrl=" + healthCheckUrl +
", environment=" + environment +
'}';
}

@ -25,7 +25,10 @@ import com.tencent.polaris.api.core.ProviderAPI;
import com.tencent.polaris.api.pojo.ServiceInfo;
import com.tencent.polaris.api.rpc.GetAllInstancesRequest;
import com.tencent.polaris.api.rpc.GetInstancesRequest;
import com.tencent.polaris.api.rpc.GetServicesRequest;
import com.tencent.polaris.api.rpc.InstancesResponse;
import com.tencent.polaris.api.rpc.ServicesResponse;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -93,4 +96,15 @@ public class PolarisDiscoveryHandler {
return providerAPI;
}
/**
* Return all service for given namespace
*
* @return service list
*/
public ServicesResponse getServices() {
String namespace = polarisProperties.getNamespace();
GetServicesRequest request = new GetServicesRequest();
request.setNamespace(namespace);
return polarisConsumer.getServices(request);
}
}

@ -20,12 +20,14 @@ package com.tencent.cloud.polaris.discovery;
import com.tencent.cloud.polaris.pojo.PolarisServiceInstance;
import com.tencent.polaris.api.exception.PolarisException;
import com.tencent.polaris.api.pojo.Instance;
import com.tencent.polaris.api.pojo.ServiceInfo;
import com.tencent.polaris.api.pojo.ServiceInstances;
import com.tencent.polaris.api.rpc.InstancesResponse;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.cloud.client.ServiceInstance;
/**
@ -63,7 +65,12 @@ public class PolarisServiceDiscovery {
* @throws PolarisException polarisException
*/
public List<String> getServices() throws PolarisException {
return Collections.emptyList();
return polarisDiscoveryHandler.
getServices().
getServices().
stream().
map(ServiceInfo::getService).
collect(Collectors.toList());
}
}

@ -21,6 +21,7 @@ import static org.springframework.util.ReflectionUtils.rethrowRuntimeException;
import com.tencent.cloud.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.polaris.PolarisProperties;
import com.tencent.cloud.polaris.util.OkHttpUtil;
import com.tencent.polaris.api.core.ProviderAPI;
import com.tencent.polaris.api.exception.PolarisException;
import com.tencent.polaris.api.pojo.Instance;
@ -33,6 +34,8 @@ import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
@ -177,6 +180,21 @@ public class PolarisServiceRegistry implements ServiceRegistry<Registration> {
public void heartbeat(InstanceHeartbeatRequest heartbeatRequest) {
heartbeatExecutor.scheduleWithFixedDelay(() -> {
try {
String healthCheckEndpoint = polarisProperties.getHealthCheckUrl();
//先判断是否配置了health-check-url如果配置了需要先进行服务实例健康检查如果健康检查通过则进行心跳上报如果不通过则不上报心跳
if (Strings.isNotEmpty(healthCheckEndpoint)) {
if (!healthCheckEndpoint.startsWith("/")) {
healthCheckEndpoint = "/" + healthCheckEndpoint;
}
String healthCheckUrl = String.format("http://%s:%s%s", heartbeatRequest.getHost(), heartbeatRequest.getPort(), healthCheckEndpoint);
if (!OkHttpUtil.get(healthCheckUrl, null)){
log.error("backend service health check failed. health check endpoint = {}", healthCheckEndpoint);
return;
}
}
polarisDiscoveryHandler.getProviderAPI().heartbeat(heartbeatRequest);
} catch (PolarisException e) {
log.error("polaris heartbeat[{}]", e.getCode(), e);

@ -0,0 +1,83 @@
/*
* 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.util;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.OkHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.Objects;
/**
* okhttp util.
*
* @author kan peng
*/
public class OkHttpUtil {
public final static Logger logger = LoggerFactory.getLogger(OkHttpUtil.class);
/**
* JSON format
*/
public static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8");
/**
* client
*/
private final static OkHttpClient HTTP_CLIENT = new OkHttpClient();
/**
* get request.
*
* @param url url
* @param headers headers
* @return response
*/
public static boolean get(String url, Map<String, String> headers) {
try {
Request.Builder builder = new Request.Builder();
buildHeader(builder, headers);
Request request = builder.url(url).build();
Response response = HTTP_CLIENT.newCall(request).execute();
if (response.isSuccessful() && Objects.nonNull(response.body())) {
String result = response.body().string();
logger.debug("exec get request, url: {} successresponse data: {}", url, result);
return true;
}
} catch (Exception e) {
logger.error("exec get requesturl: {} failed!", url, e);
}
return false;
}
/**
* build header.
*
* @param builder builder
* @param headers headers
*/
private static void buildHeader(Request.Builder builder, Map<String, String> headers) {
if (Objects.nonNull(headers) && headers.size() > 0) {
headers.forEach((k, v) -> {
if (Objects.nonNull(k) && Objects.nonNull(v)) {
builder.addHeader(k, v);
}
});
}
}
}

@ -18,6 +18,12 @@
"defaultValue": true,
"description": "If instance is enabled to accept request. The default value is true."
},
{
"name": "spring.cloud.polaris.discovery.health-check-url",
"type": "java.lang.String",
"defaultValue": "",
"description": "backend service health check endpoint."
},
{
"name": "spring.cloud.polaris.discovery.token",
"type": "java.lang.String",
@ -41,6 +47,12 @@
"type": "java.lang.String",
"defaultValue": 100,
"description": "the weight of polaris instance , use to loadbalance."
},
{
"name": "spring.cloud.loadbalancer.polaris.enabled",
"type": "java.lang.String",
"defaultValue": 100,
"description": "polaris loadbalancer enable."
}
]
}

@ -95,7 +95,7 @@ public class PolarisServiceDiscoveryTest {
PolarisServiceDiscovery polarisServiceDiscovery = context.getBean(PolarisServiceDiscovery.class);
List<String> services = polarisServiceDiscovery.getServices();
assertThat(services.size()).isEqualTo(0);
assertThat(services.size()).isEqualTo(1);
});
}

@ -0,0 +1,47 @@
/*
* 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.constant;
/**
* Constant for Context.
*
* @author skyehtzhang
*/
public interface ContextConstant {
/**
* Order of configuration modifier.
*/
interface ModifierOrder {
/**
* First modifier order.
*/
Integer FIRST = Integer.MIN_VALUE;
/**
* Last modifier order.
*/
Integer LAST = Integer.MAX_VALUE;
/**
* Order of circuit breaker configuration modifier.
*/
Integer CIRCUIT_BREAKER_ORDER = 1;
}
}

@ -32,15 +32,22 @@
<artifactId>polaris-plugin-api</artifactId>
</dependency>
<!-- 支持多注册中心 -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>connector-composite</artifactId>
</dependency>
<!-- 北极星注册中心 -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>connector-polaris-grpc</artifactId>
</dependency>
<!--依赖resCache插件-->
<!-- Consul 注册中心 -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>resource-cache-memory</artifactId>
<artifactId>connector-consul</artifactId>
</dependency>
<!--依赖flowCache插件-->

@ -20,14 +20,25 @@ package com.tencent.cloud.polaris.context;
import com.tencent.polaris.factory.config.ConfigurationImpl;
/**
* Modifier interface for polaris configuration.
*
* @author Haotian Zhang
*/
public interface PolarisConfigModifier {
/**
*
* Modify configuration.
*
* @param configuration
* @param configuration
*/
void modify(ConfigurationImpl configuration);
/**
* Get modifier order for sorting.
*
* @return order
*/
int getOrder();
}

@ -17,6 +17,8 @@
package com.tencent.cloud.polaris.context;
import com.tencent.cloud.constant.ContextConstant;
import com.tencent.cloud.polaris.context.extend.consul.ConsulContextProperties;
import com.tencent.polaris.api.exception.PolarisException;
import com.tencent.polaris.client.api.SDKContext;
import com.tencent.polaris.factory.config.ConfigurationImpl;
@ -34,9 +36,11 @@ import org.springframework.context.annotation.Bean;
*
* @author Haotian Zhang
*/
@EnableConfigurationProperties(PolarisContextProperties.class)
@EnableConfigurationProperties({PolarisContextProperties.class, ConsulContextProperties.class})
public class PolarisContextConfiguration {
private static final String ADDRESS_SEPARATOR = ",";
@Bean(name = "polarisContext", initMethod = "init", destroyMethod = "destroy")
@ConditionalOnMissingBean
public SDKContext polarisContext(PolarisContextProperties properties) throws PolarisException {
@ -57,12 +61,23 @@ public class PolarisContextConfiguration {
@Override
public void modify(ConfigurationImpl configuration) {
if (!StringUtils.isBlank(properties.getAddress())) {
URI uri = URI.create(properties.getAddress());
List<String> addresses = new ArrayList<>();
addresses.add(uri.getAuthority());
configuration.getGlobal().getServerConnector().setAddresses(addresses);
configuration.getGlobal().getServerConnector().setAddresses(getAddressList(properties.getAddress()));
}
}
}
@Override
public int getOrder() {
return ContextConstant.ModifierOrder.FIRST;
}
private List<String> getAddressList(String addressInfo) {
List<String> addressList = new ArrayList<>();
String[] addresses = addressInfo.split(ADDRESS_SEPARATOR);
for (String address : addresses) {
URI uri = URI.create(address.trim());
addressList.add(uri.getAuthority());
}
return addressList;
}
}
}

@ -22,7 +22,10 @@ import com.tencent.polaris.api.config.Configuration;
import com.tencent.polaris.factory.ConfigAPIFactory;
import com.tencent.polaris.factory.config.ConfigurationImpl;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ -67,6 +70,8 @@ public class PolarisContextProperties {
String defaultHost = getHost();
configuration.getGlobal().getAPI().setBindIP(defaultHost);
Collection<PolarisConfigModifier> modifiers = modifierList;
modifiers = modifiers.stream().sorted(Comparator.comparingInt(PolarisConfigModifier::getOrder))
.collect(Collectors.toList());
if (!CollectionUtils.isEmpty(modifiers)) {
for (PolarisConfigModifier modifier : modifiers) {
modifier.modify(configuration);

@ -0,0 +1,126 @@
/*
* 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.context.extend.consul;
import com.tencent.cloud.constant.ContextConstant;
import com.tencent.cloud.polaris.context.PolarisConfigModifier;
import com.tencent.polaris.api.config.plugin.DefaultPlugins;
import com.tencent.polaris.factory.config.ConfigurationImpl;
import com.tencent.polaris.factory.config.global.ServerConnectorConfigImpl;
import com.tencent.polaris.plugins.connector.common.constant.ConsulConstant.MetadataMapKey;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.util.CollectionUtils;
/**
* Discovery configuration of Consul.
*
* @author Haotian Zhang
*/
@ConditionalOnExpression("'true'.equals('${spring.cloud.consul.enabled:true}')"
+ " && 'true'.equals('${spring.cloud.consul.discovery.enabled:true}')")
@ConfigurationProperties("spring.cloud.consul")
public class ConsulContextProperties {
/**
* Host of consul(or consul agent)
*/
private String host;
private int port;
private boolean enabled;
@Value("${spring.cloud.consul.discovery.register:#{'true'}}")
private boolean register;
@Value("${spring.cloud.consul.discovery.enabled:#{'true'}}")
private boolean discoveryEnabled;
@Value("${spring.cloud.consul.discovery.instance-id:}")
private String instanceId;
@Value("${spring.cloud.consul.discovery.service-name:${spring.application.name:}}")
private String serviceName;
@Value("${spring.cloud.consul.discovery.ip-address:}")
private String ipAddress;
@Value("${spring.cloud.consul.discovery.prefer-ip-address:#{'false'}}")
private boolean preferIpAddress;
public void setHost(String host) {
this.host = host;
}
public void setPort(int port) {
this.port = port;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@Bean
@ConditionalOnMissingBean
public ConsulConfigModifier consulConfigModifier() {
return new ConsulConfigModifier();
}
private static class ConsulConfigModifier implements PolarisConfigModifier {
@Autowired(required = false)
private ConsulContextProperties consulContextProperties;
@Override
public void modify(ConfigurationImpl configuration) {
if (consulContextProperties != null && consulContextProperties.enabled
&& consulContextProperties.discoveryEnabled && consulContextProperties.register) {
if (CollectionUtils.isEmpty(configuration.getGlobal().getServerConnectors())) {
configuration.getGlobal().setServerConnectors(new ArrayList<>());
}
configuration.getGlobal().getServerConnectors().add(configuration.getGlobal().getServerConnector());
ServerConnectorConfigImpl serverConnectorConfig = new ServerConnectorConfigImpl();
serverConnectorConfig.setAddresses(
Collections.singletonList(consulContextProperties.host + ":" + consulContextProperties.port));
serverConnectorConfig.setProtocol(DefaultPlugins.SERVER_CONNECTOR_CONSUL);
Map<String, String> metadata = serverConnectorConfig.getMetadata();
if (StringUtils.isNotBlank(consulContextProperties.serviceName)) {
metadata.put(MetadataMapKey.SERVICE_NAME_KEY, consulContextProperties.serviceName);
}
if (StringUtils.isNotBlank(consulContextProperties.instanceId)) {
metadata.put(MetadataMapKey.INSTANCE_ID_KEY, consulContextProperties.instanceId);
}
if (consulContextProperties.preferIpAddress && StringUtils.isNotBlank(
consulContextProperties.ipAddress)) {
metadata.put(MetadataMapKey.PREFER_IP_ADDRESS_KEY,
String.valueOf(consulContextProperties.preferIpAddress));
metadata.put(MetadataMapKey.IP_ADDRESS_KEY, consulContextProperties.ipAddress);
}
configuration.getGlobal().getServerConnectors().add(serverConnectorConfig);
}
}
@Override
public int getOrder() {
return ContextConstant.ModifierOrder.LAST;
}
}
}
Loading…
Cancel
Save