6 changed files with 159 additions and 20 deletions
@ -0,0 +1,79 @@ |
|||||
|
package com.zdxt.gateway.webserver.config; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
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; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* 优先级负载均衡器 - 首选优先策略 |
||||
|
* <p> |
||||
|
* 根据配置文件中实例的声明顺序确定优先级, |
||||
|
* 始终选择优先级最高的健康实例。 |
||||
|
* <p> |
||||
|
* 健康检查并发执行后返回结果顺序不确定, |
||||
|
* 因此通过 preferredOrder 显式匹配配置中的优先级顺序。 |
||||
|
* |
||||
|
* @author zdxt |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
public class PreferredFirstLoadBalancer implements ReactorServiceInstanceLoadBalancer { |
||||
|
|
||||
|
private final String serviceId; |
||||
|
private final ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider; |
||||
|
/** 配置中声明的实例顺序(host:port),索引越小优先级越高 */ |
||||
|
private final List<String> preferredOrder; |
||||
|
|
||||
|
public PreferredFirstLoadBalancer( |
||||
|
ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, |
||||
|
String serviceId, |
||||
|
List<String> preferredOrder) { |
||||
|
this.serviceId = serviceId; |
||||
|
this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider; |
||||
|
this.preferredOrder = preferredOrder; |
||||
|
log.info("[{}] 优先级顺序: {}", serviceId, preferredOrder); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Mono<Response<ServiceInstance>> choose(Request request) { |
||||
|
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider |
||||
|
.getIfAvailable(NoopServiceInstanceListSupplier::new); |
||||
|
return supplier.get(request) |
||||
|
.next() |
||||
|
.map(this::selectInstance); |
||||
|
} |
||||
|
|
||||
|
private Response<ServiceInstance> selectInstance(List<ServiceInstance> instances) { |
||||
|
if (instances.isEmpty()) { |
||||
|
log.warn("[{}] 无可用服务实例", serviceId); |
||||
|
return new EmptyResponse(); |
||||
|
} |
||||
|
|
||||
|
// 按配置优先级顺序遍历,找到第一个在健康列表中的实例
|
||||
|
for (String preferred : preferredOrder) { |
||||
|
for (ServiceInstance instance : instances) { |
||||
|
String key = instance.getHost() + ":" + instance.getPort(); |
||||
|
if (preferred.equals(key)) { |
||||
|
log.debug("[{}] 选择优先实例: {}, 健康实例数: {}", |
||||
|
serviceId, key, instances.size()); |
||||
|
return new DefaultResponse(instance); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 如果配置顺序中的实例都不在健康列表中(不应发生),取健康列表第一个
|
||||
|
ServiceInstance fallback = instances.get(0); |
||||
|
log.warn("[{}] 未匹配到配置优先级实例,回退使用: {}:{}", |
||||
|
serviceId, fallback.getHost(), fallback.getPort()); |
||||
|
return new DefaultResponse(fallback); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue