Ribbon 网关自定义负载策略失效问题处理

自定义负载策略:这里以ip_hash为例子

项目依赖

我个人不推荐继承这个AbstractLoadBalancerRule方式去做 

       <!--nacos+ribbon-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            <version>2.2.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>

  第一种方式:

  @Bean
  public IRule getRule(){
        return new IpHashRule();
  }
@Slf4j
public class IpHashRule extends AbstractLoadBalancerRule {

    public IpHashRule() {}

    public IpHashRule(ILoadBalancer lb) {
        this.setLoadBalancer(lb);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {}

    @Override
    public Server choose(Object o) {
        return this.choose(this.getLoadBalancer(), o);
    }

    public Server choose(ILoadBalancer lb, Object o) {
        if (lb == null) {
            log.warn("No load balancer!");
            return null;
        }
        Server server = null;
        int count = 0;
        while (server == null && count++ < 10) {
            List<Server> reachableServers = lb.getReachableServers();
            List<Server> allServers = lb.getAllServers();
            int upCount = reachableServers.size();
            int serverCount = allServers.size();

            if (upCount != 0 && serverCount != 0) {
                server = allServers.get(this.ipHashIndex(serverCount));
                log.info(">>> IP_Hash 策略预选[{}]!", server);
                if (server == null)
                    Thread.yield();
                    // 这里除了判断服务是否存活以及是否可用外,我还额外判断了当前服务是否存在于可用服务列表中
                else if (server.isAlive() && server.isReadyToServe() && reachableServers.contains(server)) {
                    log.info("IP_Hash 策略选择[{}]服务!<<<", server);
                    return server;
                } else
                    server = null;

                continue;
            }
            log.warn("No up servers available from load balancer: {}", lb);
            return null;
        }
        if (count >= 10) {
            log.warn("No available alive servers after 10 tries from load balancer: {}", lb);
        }
        return server;
    }

    private int ipHashIndex(int serverCount){
        String userIp = getRemoteAddr();
        int hashCode = Math.abs(userIp.hashCode());
        return hashCode % serverCount;
    }

    private String getRemoteAddr() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        // 两种获取Request的方式,这里容易出现 null的情况,第二步是关键
        // HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
        String remoteAddr = request.getRemoteAddr();
        if (request.getHeader("X-FORWARDED-FOR") != null) {
            remoteAddr = request.getHeader("X-FORWARDED-FOR");
        }
        log.debug("RemoteAddr: {}", remoteAddr);
        return remoteAddr;
    }
}

   这个自定义的策略规则之后:访问服务器A,在访问B之后,只会拿到A服务接口,访问出错。

解决办法:

  第二种方式:

继承:LoadBalancerClientFilter

通过NacosDiscoveryProperties 获取注册中心服务实例化出服务出来做负载策略处理

在choose方法中new DefaultServiceInstance

    @Bean
    public BalancerFilter getBalancerFilter(LoadBalancerClient loadBalancer, LoadBalancerProperties properties) {
        return new BalancerFilter(loadBalancer, properties);
    }
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.Instance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.gateway.config.LoadBalancerProperties;
import org.springframework.cloud.gateway.filter.LoadBalancerClientFilter;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient;
import org.springframework.web.server.ServerWebExchange;

import java.net.URI;
import java.util.List;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;

public class BalancerFilter extends LoadBalancerClientFilter {

    @Autowired
    private NacosDiscoveryProperties properties;

    public BalancerFilter(LoadBalancerClient loadBalancer, LoadBalancerProperties properties) {
        super(loadBalancer, properties);
    }

    @Override
    protected ServiceInstance choose(ServerWebExchange exchange) {
        if (this.loadBalancer instanceof RibbonLoadBalancerClient) {
            URI uri = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
            try {
                //获取nacos所有实例
                List<Instance> allInstances = properties.namingServiceInstance().getAllInstances(uri.getHost());
                //自己实现负载---通过获取实例
                Instance instance = allInstances.get(0);
                DefaultServiceInstance defaultServiceInstance = new DefaultServiceInstance();
                defaultServiceInstance.setInstanceId(instance.getInstanceId());
                defaultServiceInstance.setHost(instance.getIp());
                defaultServiceInstance.setPort(instance.getPort());
                return defaultServiceInstance;

            } catch (NacosException e) {
                e.printStackTrace();
            }
        }

        return super.choose(exchange);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我来秋风扫落叶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值