spring cloud gateway自定义负载均衡实现路由策略,获取的总是同一个服务

背景

根据业务需求,我需要自定义负载均衡策略,并根据一定的规则智能路由匹配到相应的服务并返回。代码如下:

			DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
            String  name = loadBalancer.getName();
            NamingService namingService = this.nacosDiscoveryProperties.namingServiceInstance();
            // 获取指定服务名所有健康实例列表
            List<Instance> instances = namingService.selectInstances(name, true);
            if (CollectionUtils.isEmpty(instances)) {
                return null;
            }
            //取请求头的值
            String headValue = (String) ThreadAttributes.getThreadAttribute(REQUEST_HEADER_NAME);
            //没有标识 走默认路由规则
            if(StringUtils.isBlank(headValue)){
                return new NacosServer(getBenchMarkInstance(instances));
            }
            List<Instance> metadataMatchInstances = instances.stream()
                    .filter(instance -> Objects.equals(headValue,instance.getMetadata().get(REQUEST_HEADER_NAME)))
                    .collect(Collectors.toList());

当调用getLoadBalancer()时,返回的总是匹配到上一次正确的服务,简单来说:假如现在有A、B、C三个服务,当第一次请求A服务的时候可以正常返回对应的A服务,第二次请求B服务的时候,getLoadBalancer()返回的服务实例还是A服务的实例,而且重启之后又会一直返回B服务,此时大家都反馈路由错了的问题。我当时感觉就是当出现线程安全问题的时候才可能出现这种情况。

原因

网关的路由策略出现线程安全问题,因为Iloadbalance是成员变量,而Spring bean实例默认是singleton的,所以有线程安全问题,改为prototype之后,每次都是新的bean,新的对象,新创建的成员变量,所以解决了线程安全问题。

解决办法

加上@Scope(value=“prototype”)即可。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
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 ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值