Ribbon实现负载均衡—SpringCloud(H版)微服务学习教程(20)

Java技术 潘老师 3年前 (2021-03-26) 1533 ℃ (0) 扫码查看

一、环境准备

为了实现Ribbon负载均衡的演示,我们首先将项目恢复到我们第12小节的状态,即:我们有

  • 1个服务消费者:cloud-consumer-order80
  • 2个服务提供者:cloud-provider-payment8001cloud-provider-payment8002
  • 3个服务注册中心:cloud-eureka-server7001、cloud-eureka-server7002cloud-eureka-server7003

二、架构说明

Ribbon在工作时分成两步:
1)第一步先选择Eureka Server ,它优先选择在同一个区域内负载较少的server。
2)第二步再根据用户指定的策略,在从server取到的服务注册列表中选择一个地址 。
其中Ribbon提供了多种策略:比如轮询、随机和根据响应时间加权。

Ribbon实现负载均衡—SpringCloud(H版)微服务学习教程(20)
总结: Ribbon其实就是一个软负载均衡的客户端组件,他可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例。

三、Ribbon配置

我们在之前的项目中,就已经可以实现负载均衡了,但是我们在pom里确并没有发现导入Ribbon的相关依赖,这是为什么?原因就在于在我们导入的Eureka Client依赖中已经包含了Ribbon相关依赖,如图:
Ribbon实现负载均衡—SpringCloud(H版)微服务学习教程(20)
如果是没有整合Ribbon依赖的需要单独引入Ribbon,其GAV坐标为:

<dependency>
    <groupId>com.netflix.ribbon</groupId>
    <artifactId>ribbon</artifactId>
    <version>2.2.2</version>
</dependency>

四、RestTemplate

我们之前在Order80OrderController中都是使用的RestTemplategetForObject/postForObject方法,现在我们再新增两个方法,使用下getForEntity/postForEntity方法。

@GetMapping("/consumer/payment/getForEntity/{id}")
    public CommonResult<Payment> getPayment2(@PathVariable("id") Long id){
        ResponseEntity<CommonResult> entity = restTemplate.getForEntity(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
        log.info(entity.getStatusCode()+"\t"+entity.getHeaders());
        if(entity.getStatusCode().is2xxSuccessful()){
            return entity.getBody();
        }else{
            return new CommonResult(444,"查询失败");
        }
    }

    @GetMapping("/consumer/payment/postForEntity")
    public CommonResult<Payment> create2(Payment payment){
        ResponseEntity<CommonResult> entity = restTemplate.postForEntity(PAYMENT_URL+"/payment/create",payment,CommonResult.class);
        if(entity.getStatusCode().is2xxSuccessful()){
            return entity.getBody();
        }else{
            return new CommonResult(444,"新增失败");
        }
    }
区别:
getForObjectpostForObject 返回对象为响应体中数据转化成的对象,基本上可以理解为Json
getForEntitypostForEntity 返回对象为ResponseEntity对象, 包含了响应中的- -些重要信息,比如响应头、响应状态码、响应体等

接下来测试get和create发现正常使用,在此不再赘述

五、Ribbon负载均衡策略

Ribbon作为后端负载均衡器,比Nginx更注重的是承担并发而不是请求分发,可以直接感知后台动态变化来指定分发策略。它一共提供了7种负载均衡策略,均是IRule接口的实现类,IRule的继承实现图如下:
Ribbon实现负载均衡—SpringCloud(H版)微服务学习教程(20)
其提供的7中负载均衡实现类及说明如下:
Ribbon实现负载均衡—SpringCloud(H版)微服务学习教程(20)

六、如何替换Ribbon负载均衡策略

这里我们以将原来默认的轮询策略替换为随机策略为例:

第1步:新建自定义规则包

修改cloud-consumer-order80代码,新建com.panziye.myrule

官方文档明确给出了警告:
这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,达不到特殊化定制的目的了。
而我们的主启动类上的@SpringBootApplication注解源码上就带有@ComponentScan注解,因此我们自定义的规则包,不能与主启动类在同一个包下。

Ribbon实现负载均衡—SpringCloud(H版)微服务学习教程(20)

第2步:自定义规则类

我们在myrule包下新建名为MyRibbonRule规则类(这里我们使用注解配置的方式实现):

package com.panziye.myrule;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyRibbonRule {
    @Bean
    public IRule MyRibbonRule(){
        // 使用随机策略
        return new RandomRule();
    }
}

目前项目结构如下:
Ribbon实现负载均衡—SpringCloud(H版)微服务学习教程(20)

第3步:修改主启动类

我们需要在主启动类OrderMain80上新增@RibbonClient注解:

@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MyRibbonRule.class)
提示:name指定服务应用名,configuration 指定自定义规则类

第4步:测试

启动着5个模块(注意先后顺序),测试查看访问策略确实变成了随机,在此不再演示。

七、Ribbon轮询策略原理

1)Ribbon轮询策略原理:

rest接口第几次请求数%服务器集群总数量=实际调用服务器位置下标,每次服务 重启动后rest接口计数从1开始

Ribbon实现负载均衡—SpringCloud(H版)微服务学习教程(20)
2)源码
我们可以通过ctrl+n搜索IRule,查看IRule相关源码,再ctrl+h查看其实现类,我们这里查看RoundRobinRule,这里面涉及到自旋锁、CAS算法等知识(JUC),有兴趣的可自行探究。
3)手写负载均衡算法,有兴趣可自行学习


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/java/2778.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】