fix bugs
This commit is contained in:
77
blade-starter-loadbalancer/pom.xml
Normal file
77
blade-starter-loadbalancer/pom.xml
Normal file
@@ -0,0 +1,77 @@
|
||||
<?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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>BladeX-Tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>blade-starter-loadbalancer</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<version>${project.parent.version}</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<!-- LoadBalancer -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
<!-- Feign -->
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-okhttp</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
<!-- Nacos -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-client</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-client</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-client</artifactId>
|
||||
</dependency>
|
||||
<!-- Web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- WebFlux -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webflux</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Auto -->
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-core-auto</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.loadbalancer.config;
|
||||
|
||||
import org.springblade.core.loadbalancer.props.BladeLoadBalancerProperties;
|
||||
import org.springblade.core.loadbalancer.rule.GrayscaleLoadBalancer;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientConfiguration;
|
||||
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientSpecification;
|
||||
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
|
||||
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
|
||||
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
* blade 负载均衡策略
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@AutoConfiguration(before = LoadBalancerClientConfiguration.class)
|
||||
@EnableConfigurationProperties(BladeLoadBalancerProperties.class)
|
||||
@ConditionalOnProperty(value = BladeLoadBalancerProperties.PROPERTIES_PREFIX + ".enabled", matchIfMissing = true)
|
||||
@Order(BladeLoadBalancerConfiguration.REACTIVE_SERVICE_INSTANCE_SUPPLIER_ORDER)
|
||||
public class BladeLoadBalancerConfiguration {
|
||||
public static final int REACTIVE_SERVICE_INSTANCE_SUPPLIER_ORDER = 193827465;
|
||||
|
||||
@Bean
|
||||
public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment,
|
||||
LoadBalancerClientFactory loadBalancerClientFactory,
|
||||
BladeLoadBalancerProperties bladeLoadBalancerProperties) {
|
||||
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
|
||||
return new GrayscaleLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), bladeLoadBalancerProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LoadBalancerClientSpecification loadBalancerClientSpecification() {
|
||||
return new LoadBalancerClientSpecification("default.bladeLoadBalancerConfiguration",
|
||||
new Class[]{BladeLoadBalancerConfiguration.class});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.loadbalancer.constant;
|
||||
|
||||
/**
|
||||
* LoadBalancer 常量
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public interface LoadBalancerConstant {
|
||||
|
||||
/**
|
||||
* 灰度服务的请求头参数
|
||||
*/
|
||||
String VERSION_NAME = "version";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.loadbalancer.props;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* LoadBalancer 配置
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@RefreshScope
|
||||
@ConfigurationProperties(BladeLoadBalancerProperties.PROPERTIES_PREFIX)
|
||||
public class BladeLoadBalancerProperties {
|
||||
public static final String PROPERTIES_PREFIX = "blade.loadbalancer";
|
||||
|
||||
/**
|
||||
* 是否开启自定义负载均衡
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
/**
|
||||
* 灰度服务版本
|
||||
*/
|
||||
private String version;
|
||||
/**
|
||||
* 优先的ip列表,支持通配符,例如:10.20.0.8*、10.20.0.*
|
||||
*/
|
||||
private List<String> priorIpPattern = new ArrayList<>();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.loadbalancer.rule;
|
||||
|
||||
import org.springblade.core.auto.annotation.AutoEnvPostProcessor;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.env.EnvironmentPostProcessor;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* 灰度版本 自动处理
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@AutoEnvPostProcessor
|
||||
public class GrayscaleEnvPostProcessor implements EnvironmentPostProcessor, Ordered {
|
||||
private static final String GREYSCALE_KEY = "blade.loadbalancer.version";
|
||||
private static final String ELK_KEY = "blade.log.elk.destination";
|
||||
|
||||
private static final String METADATA_KEY = "spring.cloud.nacos.discovery.metadata.version";
|
||||
|
||||
@Override
|
||||
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
|
||||
String version = environment.getProperty(GREYSCALE_KEY);
|
||||
if (StringUtils.hasText(version)) {
|
||||
environment.getSystemProperties().put(METADATA_KEY, version);
|
||||
}
|
||||
|
||||
String elk = environment.getProperty(ELK_KEY);
|
||||
if (StringUtils.hasText(elk)) {
|
||||
environment.getSystemProperties().put(ELK_KEY, elk);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.LOWEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.loadbalancer.rule;
|
||||
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.loadbalancer.props.BladeLoadBalancerProperties;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.*;
|
||||
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
|
||||
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
|
||||
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.springblade.core.loadbalancer.constant.LoadBalancerConstant.VERSION_NAME;
|
||||
|
||||
/**
|
||||
* LoadBalancer 负载规则
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class GrayscaleLoadBalancer implements ReactorServiceInstanceLoadBalancer {
|
||||
private final ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
|
||||
private final BladeLoadBalancerProperties bladeLoadBalancerProperties;
|
||||
|
||||
@Override
|
||||
public Mono<Response<ServiceInstance>> choose(Request request) {
|
||||
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
|
||||
.getIfAvailable(NoopServiceInstanceListSupplier::new);
|
||||
return supplier.get(request).next()
|
||||
.map(serviceInstances -> getInstanceResponse(serviceInstances, request));
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义节点规则返回目标节点
|
||||
*/
|
||||
private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances, Request request) {
|
||||
// 注册中心无可用实例 返回空
|
||||
if (CollectionUtils.isEmpty(instances)) {
|
||||
return new EmptyResponse();
|
||||
}
|
||||
// 指定ip则返回满足ip的服务
|
||||
List<String> priorIpPattern = bladeLoadBalancerProperties.getPriorIpPattern();
|
||||
if (!priorIpPattern.isEmpty()) {
|
||||
String[] priorIpPatterns = priorIpPattern.toArray(new String[0]);
|
||||
List<ServiceInstance> priorIpInstances = instances.stream().filter(
|
||||
(i -> PatternMatchUtils.simpleMatch(priorIpPatterns, i.getHost()))
|
||||
).collect(Collectors.toList());
|
||||
if (!priorIpInstances.isEmpty()) {
|
||||
instances = priorIpInstances;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取灰度版本号
|
||||
DefaultRequestContext context = (DefaultRequestContext) request.getContext();
|
||||
RequestData requestData = (RequestData) context.getClientRequest();
|
||||
HttpHeaders headers = requestData.getHeaders();
|
||||
String versionName = headers.getFirst(VERSION_NAME);
|
||||
|
||||
// 没有指定灰度版本则返回正式的服务
|
||||
if (StringUtils.isBlank(versionName)) {
|
||||
List<ServiceInstance> noneGrayscaleInstances = instances.stream().filter(
|
||||
i -> !i.getMetadata().containsKey(VERSION_NAME)
|
||||
).collect(Collectors.toList());
|
||||
return randomInstance(noneGrayscaleInstances);
|
||||
}
|
||||
|
||||
// 指定灰度版本则返回标记的服务
|
||||
List<ServiceInstance> grayscaleInstances = instances.stream().filter(i -> {
|
||||
String versionNameInMetadata = i.getMetadata().get(VERSION_NAME);
|
||||
return StringUtils.equalsIgnoreCase(versionNameInMetadata, versionName);
|
||||
}).collect(Collectors.toList());
|
||||
return randomInstance(grayscaleInstances);
|
||||
}
|
||||
|
||||
/**
|
||||
* 采用随机规则返回
|
||||
*/
|
||||
private Response<ServiceInstance> randomInstance(List<ServiceInstance> instances) {
|
||||
// 若没有可用节点则返回空
|
||||
if (instances.isEmpty()) {
|
||||
return new EmptyResponse();
|
||||
}
|
||||
|
||||
// 挑选随机节点返回
|
||||
int randomIndex = ThreadLocalRandom.current().nextInt(instances.size());
|
||||
ServiceInstance instance = instances.get(randomIndex % instances.size());
|
||||
return new DefaultResponse(instance);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user