spring cloud gateway自定义负载均衡, 优先转发到指定IP

示例为优先将请求分配到指定IP, 如果指定IP没有服务, 则随机分配.

GatewayLoadBalancerConfiguration.java

挂载配置类, 可以通过@org.springframework.boot.autoconfigure.condition.ConditionalOnXXX或者@Profile注解或者@ComponentScan过滤等方式来配置是否启用

在任意一个@Configuration注解的类上配置均可

import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.context.annotation.Configuration;

@Configuration
@LoadBalancerClients(defaultConfiguration = {LyLoadBalancerClientConfiguration.class})
public class GatewayLoadBalancerConfiguration {
}

LyLoadBalancerClientConfiguration.java

配置类, 用于配置自定义负载均衡策略

import kim.nzxy.gateway.loadbalance.IpPriorityLoadBalancer;
import org.springframework.cloud.client.ServiceInstance;
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.env.Environment;

/**
 * @author ly-chn
 */
public class LyLoadBalancerClientConfiguration {
    @Bean
    public ReactorLoadBalancer<ServiceInstance> customLoadBalancer(Environment environment,
                                                                   LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new IpPriorityLoadBalancer(name,
            loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class));
    }
}

IpPriorityLoadBalancer.java

自定义负载均衡实现方式, 如果请求头中包含client-ip, 并且某个服务注册地址匹配, 则转到此服务, 否则转发到随机一个服务, 参考: org.springframework.cloud.loadbalancer.core.RandomLoadBalancer

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
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.SelectedInstanceCallback;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 优先匹配指定系统IP
 *
 * @author ly-chn
 */
@Slf4j
@AllArgsConstructor
public class IpPriorityLoadBalancer implements ReactorServiceInstanceLoadBalancer {

    private final String serviceId;
    private final ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;


    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        // 建议将"client-ip"设定为常量
        List<String> clientIpList = ((RequestDataContext) request.getContext()).getClientRequest().getHeaders().get("client-ip");
        String clientIp = CollectionUtils.isNotEmpty(clientIpList) ? clientIpList.get(0) : null;
        ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
        return supplier.get(request).next().map(serviceInstances -> processInstanceResponse(supplier, serviceInstances, clientIp));
    }

    private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier,
                                                              List<ServiceInstance> serviceInstances, String clientIp) {
        Response<ServiceInstance> serviceInstanceResponse = getInstanceResponse(serviceInstances, clientIp);
        if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
            ((SelectedInstanceCallback) supplier).selectedServiceInstance(serviceInstanceResponse.getServer());
        }
        return serviceInstanceResponse;
    }

    private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances, String clientIp) {
        if (instances.isEmpty()) {
            if (log.isWarnEnabled()) {
                log.warn("No servers available for service: " + serviceId);
            }
            return new EmptyResponse();
        }
        if (StringUtils.isEmpty(clientIp)) {
            return new DefaultResponse(instances.get(ThreadLocalRandom.current().nextInt(instances.size())));
        }
        for (ServiceInstance instance : instances) {
            if (Objects.equals(clientIp, instance.getHost())) {
                return new DefaultResponse(instance);
            }
        }
        return new DefaultResponse(instances.get(ThreadLocalRandom.current().nextInt(instances.size())));
    }

}

前端使用时:

GET http://网关IP:网关端口/目标资源
client-ip: 192.168.1.168

此时请求将优先转发到192.168.1.168上

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
Spring Cloud Gateway支持多种负载均衡策略,例如随机、轮询、权重等。如果现有的负载均衡策略不能满足你的需求,你可以自定义负载均衡策略。 首先,你需要实现`org.springframework.cloud.client.loadbalancer.reactive.LoadBalancer`接口来定义你的负载均衡策略。然后,你需要创建一个`org.springframework.cloud.gateway.filter.factory.rewrite.RewriteFunction`实例,用于将服务的URI重写为负载均衡的服务实例地址。最后,你需要将这个自定义负载均衡策略应用到Spring Cloud Gateway的路由规则中。 以下是一个示例,展示了如何定义一个基于特定请求头的自定义负载均衡策略: ```java public class CustomLoadBalancer implements LoadBalancer<ServiceInstance> { private final String headerName; public CustomLoadBalancer(String headerName) { this.headerName = headerName; } @Override public Mono<Response<ServiceInstance>> choose(Request request) { Object headerValue = request.headers().getFirst(headerName); String serviceName = "my-service"; // 根据请求头的值选择服务实例 ServiceInstance serviceInstance = ...; return Mono.just(new DefaultResponse(serviceInstance)); } } public class CustomLoadBalancerGatewayFilterFactory extends AbstractGatewayFilterFactory<CustomLoadBalancerGatewayFilterFactory.Config> { public CustomLoadBalancerGatewayFilterFactory() { super(Config.class); } @Override public GatewayFilter apply(Config config) { LoadBalancer<ServiceInstance> loadBalancer = new CustomLoadBalancer(config.getHeaderName()); RewriteFunction<String, String> rewriteFunction = uri -> { // 将URI重写为负载均衡的服务实例地址 ServiceInstance serviceInstance = loadBalancer.choose(Request.create("", new HttpHeaders())).block().getServer(); return "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + uri; }; return new RewritePathGatewayFilterFactory().apply(new RewritePathGatewayFilterFactory.Config().setRewriteFunction(rewriteFunction)); } public static class Config { private String headerName; public String getHeaderName() { return headerName; } public void setHeaderName(String headerName) { this.headerName = headerName; } } } ``` 在上面的示例中,`CustomLoadBalancer`实现了`LoadBalancer`接口,并基于特定的请求头选择服务实例。`CustomLoadBalancerGatewayFilterFactory`则将`CustomLoadBalancer`应用到Spring Cloud Gateway的路由规则中,并将服务的URI重写为负载均衡的服务实例地址。最后,你可以在路由规则中使用`CustomLoadBalancerGatewayFilterFactory`来定义自定义负载均衡策略。 ```yaml spring: cloud: gateway: routes: - id: my-route uri: http://my-service filters: - CustomLoadBalancer=my-header ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值