Spring Cloud Ribbon负载均衡服务调用

概述

Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具。Ribbon客户端组件提供了一系列完善的配置项,如连接超时,重试等。简单地说,就是在配置文件中列出Load Balancer后面所有的机器,Ribbon会自动帮我们基于某种规则(如轮询,随机连接等)去连接这些机器,我们很容易使用Ribbon实现自定义的负载均衡算法。

Ribbon官网:https://github.com/Netflix/ribbon维护模式

负载均衡的表现就是,将用户的请求分摊到多个服务器上,从而达到高可用的目的。常见的负载均衡软件有:Nginx、LVS等。

Nginx是服务器端负载均衡,客户端的请求都发给Nginx,由Nginx实现分发,将请求发送到不同的服务器上。

Ribbon是客户端负载均衡,在调用微服务接口的时候,会在注册中心拿到注册信息服务列表缓存到本地JVM,在客户端通过某种规则,确定请求的链接,发送请求进行调用。

使用Ribbon负载均衡

其实在spring-cloud-starter-netflix-eureka-client坐标下,是引入了spring-cloud-starter-netflix-ribbon的,所以,只需要添加一个@LoadBalanced就可以实现负载均衡。

RestTemplate常见的方法有getForObject()、getForEntity()、postForObject()、postForEntity()方法。其中*ForObject()方法返回对象为响应体中数据转换成的对象,基本理解为JSON。*ForEntity()方法返回对象是ResponseEntity对象,包含了响应中的信息,比如响应头,响应状态码,响应体等。

新建两个模块(cloud-eureka-server7001、cloud-eureka-server7002),使用eureka实现服务注册,具体可看之前笔记,,将cloud-eureka-server7001、cloud-eureka-server7002的配置文件改成集群模式,让7001和7002互相注册,新建两个模块(cloud-provider-payment8001、cloud-provider-payment8002),也就是服务提供者,将cloud-provider-payment8001、cloud-provider-payment8002的配置文件改成集群模式,将cloud-consumer-order80的配置文件改成集群模式。新建一个服务消费者模块(cloud-consumer-order80),在cloud-consumer-order80模块中的OrderController里,添加两个方法,分别调用getForEntity()和postForEntity()方法。

注:新建模块过程省略,步骤可参考之前笔记

@GetMapping("/consumer/payment/getForEntity/{id}")
public CommonResult getPaymentById2(@PathVariable("id") Long id) {
    ResponseEntity<CommonResult> entity = restTemplate.getForEntity(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);
    System.out.println("status code=" + entity.getStatusCode());
    System.out.println("headers=" + entity.getHeaders());
    if (entity.getStatusCode().is2xxSuccessful()) {
        return entity.getBody();
    } else {
        return new CommonResult(404, "查找失败");
    }
}
@GetMapping("/consumer/payment/create2")
public CommonResult create2(Payment payment) {
    return restTemplate.postForEntity(PAYMENT_URL + "/payment/create", payment, CommonResult.class).getBody();
}

先启动Eureka注册中心,再启动两个生产者模块,最后启动消费者模块,浏览器发送请求来调用ForEntity()方法进行测试。在浏览器端,可以看到port的值,不断在8001和8002之前进行切换。

Ribbon负载均衡算法

负载均衡算法:REST接口第几次请求数字%服务器集群总数量=实际调用服务器位置下标,每次重启服务器REST接口计数从1开始。找一个IRule接口的实现类,下面是RoundRobinRule类对该接口的实现。

public Server choose(ILoadBalancer lb, Object key) {
    if (lb == null) {
        log.warn("no load balancer");
        return null;
    } else {
        Server server = null;
        int count = 0;
        while(true) {
            // 获取server,如果获取失败,进行重试,如果10次后,还没获取到server,就报错
            if (server == null && count++ < 10) {
                // 获取所有状态是up的server
                List<Server> reachableServers = lb.getReachableServers();
                // 获取所有server
                List<Server> allServers = lb.getAllServers();
                int upCount = reachableServers.size();
                int serverCount = allServers.size();
                if (upCount != 0 && serverCount != 0) {
                    // 计算出要访问的server下标
                    int nextServerIndex = this.incrementAndGetModulo(serverCount);
                    server = (Server)allServers.get(nextServerIndex);
                    if (server == null) {
                        Thread.yield();
                    } else {
                        if (server.isAlive() && server.isReadyToServe()) {
                            return server;
                        }
                        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 incrementAndGetModulo(int modulo) {
    int current;
    int next;
    // 利用cas和自旋锁,获取next的值
    do {
        current = this.nextServerCyclicCounter.get();
        next = (current + 1) % modulo;
    } while(!this.nextServerCyclicCounter.compareAndSet(current, next));
    return next;
}

从上面可以发现,Ribbon核心是IRule,IRule是一个接口,它有多个实现类,分别代表不同的负载均衡策略。

IRule的子类的关系图

注:

com.netflix.loadbalancer.RoundRobinRule:轮询机制

com.netflix.loadbalancer.RandomRule:随机机制

com.netflix.loadbalancer.RetryRule:首先按照RoundRobinRule策略来获取服务,如获取服务失败,在指定时间内尝试获取服务,获取可用服务

com.netflix.loadbalancer.WeigthResponseTimeRule:是对RoundRobinRule扩展,根据响应速度进行选择,响应速度越快,优先级越高

com.netflix.loadbalancer.BestAvailableRule:首先剔除掉多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务

com.netflix.loadbalancer.AvailabilityFilterRule:首先过滤掉故障实例,然后再选择并发最小的实例

com.netflix.loadbalancer.ZoneAvoidanceRule:默认规则,符合判断server所在区域的性能和server可用性选择服务器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值