Spirng Cloud学习笔记(2)-Ribbon负载均衡

ps:这是我的个人笔记地址:TinkerBell学习笔记

1.0 Ribbon 概述

Spring Cloud Ribbon: 是一个基于 HTTP 和 TCP 的客户端负载均衡工具

公司Netfix

作用可以让我们轻松地将面向服务的 REST 模版请求 自动转换成客户端负载均衡的服务调用。Ribbon 客户端组件提供了一套完善的配置项,比如连接超时,重试等。

负载均衡策略轮询(Ribbon默认) hash 权重 ….

使用方法在 Spring Cloud 构建的微服务系统中, Ribbon 作为服务消费者的负载均衡器,有两种使用方式:

1.Ribbon+RestTemplate

2.Ribbon+OpenFeign(OpenFeign默认集成了 Ribbon)


2.0 Ribbon 快速入门

在这里插入图片描述

2.1 使用自定义负载均衡

思路:用Random随机数实现负载均衡 图中一个消费者 两个提供者

消费者调用提供者 实现负载均衡 , 所以三个依赖都是eureka-client

2.2 创建Eureka-server注册中心

(这里不会的可以翻看第一章节)

2.3 创建 provider-1 和 provider-2

新建SpringBoot项目 勾选Spring Web+ eureka client

将provider-1和-2 拟用相同的应用名称provider(Id),分别修改端口8081和 8082
分别在启动类上开启@EnableEurekaClient

server:
  port: 8081    #provider-1 用8081 provider-2用8082
spring:
  application:
    name: provider  #相同不用改 
eureka:
  client:
    service-url: #eureka 服务端和客户端的交互地址,集群用,隔开
      defaltZone: http://localhost:8761/eureka

    fetch-registry: true   #是否拉取服务列表
    register-with-eureka: true #是否注册自己(单机 eureka 一般关闭注册自己,集群注意打开)
    registry-fetch-interval-seconds: 5 # 表示 eureka-client 间隔多久去拉取服务注册信息
  instance:
    hostname: localhost
    instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}
    prefer-ip-address: true  # 服务列表以 ip 的形式展示
    lease-renewal-interval-in-seconds: 10 # #表示 eureka server 发送心跳给 server 端的频率
    lease-expiration-duration-in-seconds: 20 #至上一次收到 client 的心跳之后,等待
    #下一次心跳的超时时间,在这个时间内若没收到下一次心跳,则将移除该实例

2.4 provider提供接口"/info"

在这里插入图片描述

2.5 创建 consumer

新建SpringBoot项目 勾选Spring Web -eureka client 确认

在consumer项目中添加 Ribbon依赖

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            <version>2.2.9.RELEASE</version>
        </dependency>

2.6 编写 consumer 的启动类

@SpringBootApplication
@EnableEurekaClient   
public class ConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
    //RestTemplate:在java中发起远程调用的一个工具;将它标记为Bean 注入IOC容器,就不用每次都new一个
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

2.7 编写 consumer 的 TestController

package com.tinkerbell.Controller;
import com.netflix.loadbalancer.ILoadBalancer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
import java.util.Random;
/**
 * @Author: 小叮当
 * @Description: 消费者访问提供者 使用自定义Random做负载均衡
 * @Date Created in 2022/9/3  下午 9:05
 * @Web www.tinkerbell9433.top/ ----TinkerBell学习笔记
 */

@RestController
public class TestController {
//通过服务发现客户端去做服务发现(通过应用名称访问另一个服务)
    @Autowired   
    private DiscoveryClient discoveryClient;
//java的一个远程调用工具(即一个服务到另一个服务,暂时这么理解吧)
    @Autowired
    RestTemplate restTemplate;
//采用随机策略做负载均衡
    static Random random = new Random();

    @GetMapping("testBalance")
    public String testBalance(String serverId){
//通过传入的应用名称做服务发现 得到该服务的实例信息(ip 端口 ...)
        List<ServiceInstance> instances = discoveryClient.getInstances(serverId);
        //情况1 传参错误 或者服务列表为空
        if (ObjectUtils.isEmpty(instances)){
            return "服务列表为空";
        }
        //情况2 服务列表不为空 先自己做一个负载均衡
        ServiceInstance serviceInstance = loadBalance(instances);
        String host = serviceInstance.getHost();
        int port = serviceInstance.getPort();
        String url ="http://"+host+":"+port+"/info";
        System.out.println("本次我调用的是:"+url);
        String forObject = restTemplate.getForObject(url, String.class);
        System.out.println(forObject);
        return forObject;
    }
    private   ServiceInstance loadBalance(List<ServiceInstance> instances){
        //拼接 url 去调用 ip:port 先自己实现不用 ribbon
        ServiceInstance serviceInstance = instances.get(random.nextInt(instances.size()));
        return serviceInstance;
    }
}

2.8 搭建完的项目结构

简单介绍:消费者通过discoveryClient做服务发现,参数为serverId(也就是应用名称provider),此时两个“提供者”的形式是:一个名称,两台实例,就相当于传入provider做服务发现可以找到8081,8082两台,并通过自定义负载均衡做来回调用,从而达到效果。

在这里插入图片描述

2.9 测试访问

先启动注册中心 eureka-server 再陆续启动provider-1和2,consumer(有条件的等一会儿在进行测试,Eureka拉去服务列表需要时间)

consumer:localhost:8080 ,Provider-1和2分别是8081和8082

访问:http://localhost:8080/testBalance?serverId=provider在这里插入图片描述

3.1 使用Ribbon做负载均衡

只需要对 consumer 改造即可,改造启动类 改造 controller,

谁想实现负载均衡效果,就谁来

3.2 修改RestTemplate

@SpringBootApplication
@EnableEurekaClient
public class ConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
    //RestTemplate:在java中发起远程调用的一个工具;将它标记为Bean 注入IOC容器,就不用每次都new一个
    @Bean
    @LoadBalanced //ribbon 的负载均衡注解
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

3.2修改RibbonController

package com.tinkerbell.Controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
 * @Author: 小叮当
 * @Description: Ribbon负载均衡
 * @Date Created in 2022/9/3  下午 9:05
 * @Web www.tinkerbell9433.top/ ----TinkerBell学习笔记
 */

@RestController
public class RibbonController {
	//此时的RestTemplate已经集成了Ribbon的负载均衡策略 直接调用就可以出现效果
    @Autowired
    RestTemplate restTemplate;

    @GetMapping("testBalance")
    public String testBalance(String serverId){

        String url ="http://"+serverId+"/info";
        System.out.println("本次我调用的是:"+url);
        String forObject = restTemplate.getForObject(url, String.class);
        System.out.println(forObject);
        return forObject;
    }
}

3.3 测试成功-Ribbon负载均衡

访问http://localhost:8080/testBalance?serverId=provider
在这里插入图片描述

4.1 Ribbon 原理分析

4.2 Ribbon 要做什么事情?

**先通过 “http://” + serviceId + “/info” 我们思考 ribbon 在真正调用之前需要做什么? **

restTemplate.getForObject(“http://provider/info”, String.class);

想要把上面这个请求执行成功,我们需要以下几步

  1. 拦截该请求;
  2. 获取该请求的 URL 地址:http://provider/info
  3. 截取 URL 地址中的 provider
  4. 从服务列表中找到 key 为 provider 的服务实例的集合(服务发现)
  5. 根据负载均衡算法选出一个符合的实例
  6. 拿到该实例的 host 和 port,重构原来 URL 中的 provider
  7. 真正的发送 restTemplate.getForObject(“http://ip:port/info”,String.class)

简而言之:Ribbon拦截到provider后做服务发现拿到该应用名称的集合,并拿到这些实例的ip和端口,重构url。

4.3 负载均衡之前的服务列表是从何而来呢?

Ribbon 里面有没有服务列表?

Ribbon 只做负载均衡和远程调用 服务列表从哪来?

从 eureka 来 ,Ribbon 没有服务发现的功能,但是 eureka 有,所以 ribbon 和 eureka 完美结合

Ribbon 有一个核心接口 ILoadBalance(承上(eureka)启下(Rule))

我们发现在负载均衡之前,服务列表已经有数据了

4.4 Ribbon 把 服务列表缓存起来,脏读怎么处理?

Ribbon 中使用了一个 PING 机制 (心跳监测)
从 eureka 中拿到服务列表,缓存到本地,ribbon 搞了个定时任务,隔一段时间就去循环 ping 一下每个服务节点是否存活

4.5 Ribbon 负载均衡的实现和几种算法

1.RoundRobinRule–轮询 请求次数 % 机器数量

2.RandomRule–随机

3.权重

  1. iphash 3.AvailabilityFilteringRule --会先过滤掉由于多次访问故障处于断路器跳闸状态的服 务,还有并发的连接数量超过阈值的服务,然后对于剩余的服务列表按照轮询的策略进行访问

5.WeightedResponseTimeRule–根据平均响应时间计算所有服务的权重,响应时间越快服 务权重越大被选中的概率越大。刚启动时如果同统计信息不足,则使用轮询的策略,等统计信 息足够会切换到自身规则

6.RetryRule-- 先按照轮询的策略获取服务,如果获取服务失败则在指定的时间内会进行重 试,获取可用的服务

7.BestAvailableRule --会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后 选择一个并发量小的服务

8.ZoneAvoidanceRule – 默认规则,复合判断 Server 所在区域的性能和 Server 的可用 行选择服务器。 Ribbon 默认使用哪一个负载均衡算法: ZoneAvoidanceRule :区间内亲和轮询的算法!通过一个 key 来区分

5.1 如何修改默认的负载均衡算法

5.2 通过配置文件修改(指定某一个服务使用什么算法)

provider: #提供者的服务名称,那么访问该服务的时候就会按照自定义的负载均衡算法 
  ribbon: 
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #几种算法的全限定类名

5.3 配置消费者调用任何服务都用某种算法(全局)

@Bean 
public IRule myRule() { //指定调用所有的服务都用此算法
return new RandomRule();
}

6.1 Ribbon的常用配置

ribbon: #全局的设置
  eager-load:
    enabled: false # ribbon 一启动不会主动去拉取服务列表,当实际使用时才 去拉取 是否立即加载
  http:
    client:
      enabled: false # 在 ribbon 最后要发起 Http 的调用调用,我们认为是 RestTemplate 完成的,其实最后是 HttpURLConnection 来完成的,这里面设置为 true , 可以把 HttpUrlConnection->HttpClient
  okhttp:
    enabled: false #HttpUrlConnection 来完成的,这里面设置为 true ,可以 把 HttpUrlConnection->OkHttpClient(也是发 http 请求的,它在移动端的开发用的多)
provider: #提供者的服务名称,那么访问该服务的时候就会按照自定义的负载均衡算法
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #修改默认负载均衡算法,几种算法的全限定类名
    #修改默认负载均衡算法,几种算法的全限定类名
    # NFLoadBalancerClassName: #loadBalance 策略
    # NFLoadBalancerPingClassName: #ping 机制策略
    # NIWSServerListClassName: #服务列表策略
    # NIWSServerListFilterClassName: #服务列表过滤策略
#ZonePreferenceServerListFilter 默认是优先过滤非一个区的服务列表

7.1 .Ribbon 总结(后面的代码中 不会出现 ribbon)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值