SpringCloud(二) 客户端负载均衡Ribbon使用


一、Ribbon是什么?

Ribbon是Netflix发布的负载均衡器,它有助于控制HTTP和TCP的客户端的行为。为Ribbon配置服务提供者地址后,Ribbon就可基于某种负载均衡算法,自动地帮助服务消费者去请求。Ribbon默认为我们提供了很多负载均衡算法,例如轮询、随机等。当然,我们也可为Ribbon实现自定义的负载均衡算法。
在Spring Cloud中,当Ribbon与Eureka配合使用时,Ribbon可自动从Eureka Server获取服务提供者地址列表,并基于负载均衡算法,请求其中一个服务提供者实例。展示了Ribbon与Eureka配合使用时的架构。
在这里插入图片描述

二、使用Ribbon

1.概念

我们在配置Eureka注册中心的时候,创建了两个服务提供者和一个消费者两个注册中心,现在需要用到这五个服务,因为Ribbon被集成在了 Eureka中,所以我们也不需要使用 maven坐标引入依赖。
配置注册中心的时候,其实有用到Ribbon这个东西。只是当时没有说。还记得我们配置的RestTemplate吗?

@Configuration
public class AppConfig {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

没错就是这个,我们使用 @LoadBalanced 注解之后,

    public static final String PAYMENT_URL = "http://SGG-PAYMENT-SERVICE/payment/";

这个时候,才可以通过服务名称访问到对应的服务实例。在配置服务中心的时候,我们就知道了Ribbon 是默认使用的轮询机制实现负载均衡的。 当然 Ribbon 默认给我们提供了很多其他的选择方式。
在这里插入图片描述

这个这个图可以看到。Ribbon 为我们提供了很多负载均衡的策略来提供给我们使用,默认使用的就是轮训机制, 就是上面的那个RoundRobinRule ,

2. 如何修改默认的负载均衡机制

我们将默认的轮询机制的负载均衡修改为 随机的。创建一个配置类

@Configuration
public class CustomRandomRule {
    @Bean
    public RandomRule randomRule() {
        return new RandomRule();
    }
}

注意: 这里这个类不能配置到SpringBoot启动类的同级别目录下以及子目录下,为什么呢?因为Ribbon的配置必须用@Configuration注解标识,并且不能被@Component注解或者@SpringBootApplication(因为里面包含了@Component)扫描到。因为如果被@ComponetScan扫描到会导致所有的RibbonClient都去共享这个配置。
所以我们这个类要配置在外一层里面才可以。 现在再去启动类上添加注解。

@SpringBootApplication
@EnableEurekaClient
@RibbonClient(value = "SGG-PAYMENT-SERVICE", configuration = LoadBlbanceConfig.class)
public class OrderApp {
    public static void main(String[] args) {
        SpringApplication.run(OrderApp.class, args);
    }
}

可以看到我们的添加了 RibbonClient 注解, 当然了如果你有多个服务需要配置,你也可以通过使用 @RibbonClients 这个注解, 这个注解可以添加多个 RibbonClient
接下来我们启动昨天的服务 7001, 7002, 8001 ,8002, 80 访问我们的接口试试看 , 还是不是默认的轮询机制了。
在这里插入图片描述
可以看到,我们的这个接口已经成为随机的了,现在是已经成功了。 有时候是 8001 有时候是8002, 而且找不到规律。

3. 自定义负载均衡策略。

我们前面说了,负载均衡策略主要是接口是 IRule 这个接口中的 choose 方法,作用就是用来决定这次的请求发送到哪一个实例上面。

public interface IRule{
    /*
     * choose one alive server from lb.allServers or
     * lb.upServers according to key
     * 
     * @return choosen Server object. NULL is returned if none
     *  server is available 
     */
    public Server choose(Object key);
    
    public void setLoadBalancer(ILoadBalancer lb);
    
    public ILoadBalancer getLoadBalancer();    
}

但是我们不准备实现该接口,我打算实现一个抽象类AbstractLoadBalancerRule,该抽象类也是继承自 IRule 接口

public abstract class AbstractLoadBalancerRule implements IRule, IClientConfigAware {

    private ILoadBalancer lb;
        
    @Override
    public void setLoadBalancer(ILoadBalancer lb){
        this.lb = lb;
    }
    
    @Override
    public ILoadBalancer getLoadBalancer(){
        return lb;
    }      
}

CustomMyRule.java

/**
 * @author gssznb
 * @Date 2020/9/6
 * @Descript: 如何自定义访问规则。, 通过集成 AbstractLoadBalancerRule 重写 choose 方法 。
 */
@Slf4j
public class CustomMyRule extends AbstractLoadBalancerRule {

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {

    }

    @Override
    public Server choose(Object key) {
        // 获取到 lb 对象
        ILoadBalancer lb = super.getLoadBalancer();
        // 获取到所有的实例对象
        List<Server> allServers = lb.getAllServers();
        AtomicReference<Server> s = new AtomicReference<>();;
        // 遍历一下我们的这个所有的实例
        allServers.forEach(server -> {
            String host = server.getHost();
            int port = server.getPort();
            String scheme = server.getScheme();
            Server.MetaInfo metaInfo = server.getMetaInfo();
            String zone = server.getZone();
            log.info("host: [ {} ], port: [ {} ], scheme: [ {} ]", host, port, scheme);
            log.info("metaInfo: [ {} ], zone: [ {} ]", metaInfo, zone);
            if (port == 8001) {
                s.set(server);
            }
        });
        // 我们这边实现的策略就是,不管怎么样,我们都始终使用 端口号为 8001 的实例
        return s.get();
    }
}

修改LoadBlbanceConfig.java

    @Bean
    public CustomMyRule randomRule() {
        return new CustomMyRule();
    }

修改启动类OrderApp.java

@SpringBootApplication
@EnableEurekaClient
@RibbonClient(value = "SGG-PAYMENT-SERVICE", configuration = LoadBlbanceConfig.class)
public class OrderApp {

    public static void main(String[] args) {
        SpringApplication.run(OrderApp.class, args);
    }
}

启动,访问接口!!可以看到不管我们访问多少次,他永远都是 8001 端口的实例。 这边将 allServer 中的实例信息打印出来

2020-09-08 20:29:02.621  INFO 10100 --- [p-nio-80-exec-6] cn.fllday.config.lb.CustomMyRule         : host: [ 192.168.101.2 ], port: [ 8001 ], scheme: [ null ]
2020-09-08 20:29:02.621  INFO 10100 --- [p-nio-80-exec-6] cn.fllday.config.lb.CustomMyRule         : metaInfo: [ com.netflix.niws.loadbalancer.DiscoveryEnabledServer$1@3b5d72b1 ], zone: [ defaultZone ]
2020-09-08 20:29:02.621  INFO 10100 --- [p-nio-80-exec-6] cn.fllday.config.lb.CustomMyRule         : host: [ 192.168.101.2 ], port: [ 8002 ], scheme: [ null ]

感谢尚硅谷老师!!! 在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值