王富贵

Stay hungry,Stay foolish

若你自认理性且正确,那更应该心平气和,言之有据地与人交流,即使不能立刻说服对方,但也至少埋下了一颗种子,冷嘲热讽或居高临下的态度,总会加大人与人之间的隔阂,最终只是在自己的小圈子中制造回声。愿我们最终都能成为乐观且包容的人,愿意耐心听取他人的苦衷和心声。
  menu
69 文章
0 浏览
3 当前访客
ღゝ◡╹)ノ❤️

RabbitMQ消息队列

1、负载均衡器Ribbon

1.1、什么是ribbon

什么是负载均衡:负载均衡就是当一项服务部署到了多台机器的时候,请求合理均衡的分配到所有的机器上处理,就是负载均衡

主流的负载方案有两种:

  1. 服务端负载均衡,在消费者和服务提供方中间使用独立的代理方式实现负载均衡,也就是使用中间件。有硬件的(f5),也有软件的(nginx)
  2. 客户端根据自己的请求情况做负载均衡,ribbon就是属于客户端自己做负载均衡。也就是说,nacos将所有的服务地址给我们,我们自己均衡的去选择访问哪一项

spring-cloud-ribbon是基于netflix ribbon实现的一套客户端负载均衡工具,ribbon客户端组件提供了一系列的完善的配置,比如超时,重试等等。通过load Balancer获取到服务提供的所有机器实例,ribbon会基于某种规则(轮询,随机,权重)去调用服务。我们也可以自定义实现我们自己的负载均衡策略

1.1.1.客户端负载均衡

客户端根据自己的请求情况做负载均衡,ribbon就是属于客户端自己做负载均衡。也就是说,nacos将所有的服务地址给我们,我们自己均衡的去选择访问哪一项

10

1.1.2.服务端负载均衡

服务端负载均衡,在消费者和服务提供方中间使用独立的代理方式实现负载均衡,也就是使用中间件。有硬件的(f5),也有软件的(nginx)

响应的时候先经过中间件,中间件选一个发送给调用者

11

1.1.3.常见负载均衡算法

  1. 随机,通过随机选择服务执行
  2. 轮询,负载均衡默认的实现方法,请求一个一个轮流处理
  3. 加权轮询,通过对服务器性能分析,给高配低负载的服务器更高的权重也就是给他处理更多的请求,均衡压力
  4. 地址Hash,通过客户端请求的地址的hash值取模进行服务器调度
  5. 最小链路数,及时请求均衡了,压力也不一定均衡,最小连接数法就是根据服务器的情况,比如请求积压数等参数,将请求分配到当前压力最小的服务器上,最小活跃数

1.2、nacos使用ribbon

由于nacos-discover已经有ribbon的依赖,我们不需要添加任何依赖

在SpringCloud第一代中使用Ribbon、SpringCloud第二代中直接采用自研发loadbalance即可,默认使用的Ribbon

1.2.1.使用LoadBalancerClient

1.注入LoadBalancerClient

@Autowired
private LoadBalancerClient loadBalancerClient;

2.调用loadBalancerClient

@GetMapping("/ribbon")
public URI ribbon(){
    // 通过地址自动负载均衡
    ServiceInstance choose = loadBalancerClient.choose("provider");
    return choose.getUri();
}

1.2.2.使用@LoadBalanced注解配合restTemplate实现

1.配置bean

@Bean
@LoadBalanced
RestTemplate restTemplate() {
    return new RestTemplate();
}

2.url使用服务名替换路径调用

我们这里服务名叫provider,所以为http://provider/hello,我们访问hello接口

@Autowired
private RestTemplate restTemplate;

@GetMapping("/hello")
public String hello(){
    //进行了拼接地址加
    String forObject = restTemplate.getForObject("http://provider/hello/", String.class);
    return "我是消费者拿生产者:"+forObject;
}

1.3、ribbon配置

1.3.1.ribbon的负载均衡策略

12

IRule

这是所有负载均衡策略的父接口,里面的核心方法是choose方法,用来选择一个服务实例

AbstractLoadBalancerRule

AbstractLoadBalancerRule是一个抽象类,里面主要定义了一个ILoadBalancer,就是我们上文所说的负载均衡器,这里定义他主要是为了辅助负责均衡策略选取核实的服务端实例

  1. RandomRule,该策略就是随机选择一个服务实例。在RandomRule的无参构造中初始化了一个Random对象,然后他重写的choose方法调用了choose(ILoadBalancer ib, Object key)这个重载的choose方法,在这个重载的choose方法中,每次利用random对象生成一个不大于服务实例总数的随机数,并将该随机数作为下标索引获取一个服务实例
  2. RoundRobinRule,该策略叫做线性轮询策略。这个类的choose(ILoadBalancer lb, Object key)函数整体逻辑是这样的︰开启一个计数器count,在while循环中遍历服务清单,获取清单之前先通过incrementAndGetModulo方法获取一个下标,这个下标是一个不断自增长的数先加1然后和服务清单总数取模之后获取到的(所以这个下标从来不会越界),拿着下标再去服务清单列表中取服务,每次循环计数器都会加1,如果连续10次都没有取到服务,则会报一个警告No available alive servers after 10 tries from load balancer: XXXX
  3. **RetryRule(轮询基础上进行重试)**看名字就知道这种负载均衡策略带有重试功能。首先RetryRule中又定义了一个subRule,它的实现类是RoundRobinRule,然后在RetryRule的choose(LoadBalancerlb,Object key)方法中,每次还是采用RoundRobinRule中的choose规则来选择一个服务实例,如果选到的实例正常就返回,如果选择的服务实例为nul或者已经失效,则在失效时间deadine之前不断的进行重试(重试时获取服务的策略还是RoundRobinRule中定义的策略),如果超过了deadline还是没取到则会返回一个null
  4. **WeightedResponseTimeRule(权重-nacos的nacosRule,Nacos还拓展了一个自己的基于配置的权重拓展)**他对RoundRobinRule的功能进行了拓展,他会根据每一个实例的运行情况来给计算出该实例的一个权重,然后再挑选实例的时候根据权重进行挑选,这样能够实现更优的实例调用。他里面有一个叫DynamicServerWeightTask的定时任务,默认情况下每三十秒会计算一次各个服务实例的权重,权重的计算规则也很简单,如果一个服务的平均响应时间越短则权重越大,那么该服务实例被选中执行任务的概率也就越大
  5. **BestAvailableRule(过滤失效的服务实例,找出并发请求最小的实例来使用)**他继承ClientConfigEnabledRoundRobinRule,在他的基础上主要增加loadBalancerStats中保存的服务实例的状态信息来过滤失效的服务实例,找出并发请求最小的实例来使用。然而loadBalancerStats有可能为null,则BestAvaliableRule将采用他的父类ClientConfigEnabledRoundRobinRule的服务选取策略(线性轮询)
  6. **ZoneAvoidanceRule(默认规则,符合判断server所在区域的性能和server的可用性选择服务器)**他是PredicateBasedRule的一个实现类,只不过这里多一个过滤条件,他的过滤ZoneAvoidancePredicate为主过滤条件和以AvailabilityPredicate为次过滤条件组成的一个叫做CompositePredicate的组合过滤条件,过滤成功后,继续采用线性轮询(RoundRobinRule)的方式从过滤结果中选择一个出来
  7. **AvailabilityFilteringRule(先过滤故障实例,再选择并发较小的实例)**过滤掉一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的后端server或者使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就是检查status里记录的各个server的运行状态

1.3.2.修改默认负载均衡策略

修改默认负载均衡策略有两种方式,一种是通过配置bean的方式配置,一种是通过yaml配置文件的方式,这里我们更推荐使用yaml配置文件的方式

1.3.2.1.配置bean

注意:再配置bean之前我们需要注意一个问题,如果我们的配置类被自动扫描进spring容器中,那么全局的负载均衡都会使用这么一个策略,这不适合我们对不同的生产者使用不同的负载均衡策略。所以,我们的配置类必须不能被主类扫描到

13

1.我们要将这个类的实现装配到全局中

注意位置,不能被扫描到

@Configuration
public class RibbonConfig {

    /**
     * 全局配置
     * 指定负载均衡策略,可以指定我们之前学习的所有策略
     * @return
     */
  
    @Bean
    public IRule iRule(){
        // 指定使用nacos提供的负载均衡策略(优先调用统一集群的实例,基于随机权重)
        return new NacosRule();
    }
}

2.利用@RibbonClient在主加载类指定微服务及其负载均衡策略

//name:服务提供者名称
//configuration:他的配置类的类文件
@RibbonClient(name = "provider",configuration = RibbonRandomRuleConfig.class)
@SpringBootApplication
@EnableDiscoveryClient
@RibbonClients(value ={
        // 指定负载均衡的服务提供者,以及负载均衡策略配置类的类对象
        @RibbonClient(name = "provider",configuration = RibbonRandomRuleConfig.class)
})
public class Ribbon {

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

1.3.2.2.配置文件

我们现在演示配置文件的方式配置负载均衡策略

我们只需要修改配置文件即可,注意,这里我们是没有提示的,也就是说源码直接来读键值对,注意需要直接丢根下而不能空格

# properties配置文件

服务提供名.ribbon.NFLoadBalancerRuleClassName = 负载均衡策略全类名
例如:
provider.ribbon.NFLoadBalancerRuleClassName = com.alibaba.cloud.nacos.ribbon.NacosRule

--------------------------------

# yaml配置文件
服务提供名: 
	ribbon: 
		NFLoadBalancerRuleClassName : 负载均衡策略全类名
例如:
provider:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule

这里我们的NacosRule是基于nacos的权重来实现的负载均衡

14

1.3.3.自定义负载均衡策略

我们自定义负载均衡策略非常简单,我们只需要实现父类接口(IRule)或者基类(AbstractLoadBalancerRule·)就行,使用方法同上

1.编写配置类

public class MyRibbonRule extends AbstractLoadBalancerRule {

    @Override
    public Server choose(Object key) {
        //获取当前请求的服务实例
        ILoadBalancer loadBalancer = this.getLoadBalancer();
        //获取到实例列表
        List<Server> servers = loadBalancer.getReachableServers();
        //线程安全的随机获取一个下标
        int i = ThreadLocalRandom.current().nextInt(servers.size());
        return servers.get(i);
    }

    //初始化配置的,我们不学那么深
    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {}
}

2.我们使用配置的方式注入进去

# 权重配置
provider:
  ribbon:
    NFLoadBalancerRuleClassName: com.hy.ribbon.MyRibbonRule

1.3.4.小问题

这里有个小问题,就是我们负载均衡策略是懒加载的,在消费端调用的时候,才会去请求nacos拿到列表并加载。那么我们第一次调用的时候可能会出现超时的情况。如果想要直接加载,我们需要做一定的配置

# 配置负载均衡策略直接加载
ribbon:
  eager-load:
    # 开启饥饿加载,即启动直接加载
    enabled: true
    # 配置需要直接加载的服务提供者名,多个使用英文逗号隔开
    clients: provider

1.4、LoadBalancer

LoadBalancer是spring cloud官方自己提供的客户端负载均衡器,用来替代Ribbon

spring官方提供了两种负载均衡客户端:

RestTemplate

RestTemplate是Spring提供的用于访问rest服务的客户端,RestTemplate提供了多种便捷访问远程http服务的方法,能够大大的提高客户端的编写效率。默认情况下,RestTemplate依赖jdk的http连接工具

WebClient

WebClient是从Spring WebFlux 5.0版本开始提供的一个非阻塞的基于响应式编程的进行http请求的客户端工具

1.4.1、使用LoadBalancer

1.引入LoadBalancer依赖

<!-- 引入LoadBalancer依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

2.排除ribbon

我们方才知道,虽然我们使用的是RestTemplate,但是他默认是使用ribbon的,我们要使用loadBalancer就需要移除ribbon

移除方式有两种,在pom依赖中排除,或者在配置文件yaml中声明不使用ribbon

  1. pom依赖排除,并引入LoadBalancer
<!--client发现依赖 排除ribbon依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </exclusion>
    </exclusions>
</dependency>
  1. yaml声明不使用ribbon
spring:
  application:
    # 服务名,如果nacos没有配置,则用他
    name: consumer-with-ribbon
  cloud:
    nacos:
      # 服务发现配置
      discovery:
        server-addr: 175.178.58.107:8848 # nacos发现地址
        username: nacos # nacos用户名
        password: LM647688lx # nacos密码
        namespace: a048578c-ec50-4db1-bfd7-f8f69eb96622 # 工作空间(不加为默认)
        group: my-group # # 配置分组(不加为默认)分在同一个组才能相互发现
        service: consumer-with-ribbon # 服务名称
      # nacos地址
      server-addr: 175.178.58.107:8848

    loadbalancer:
      ribbon:
        enabled: false

3.使用LoadBalancer

直接使用RestTemplate即可。原理就是原生使用的ribbon被排除了,并且LoadBalancer引入,所以我们使用他

@RestController
public class TestController {
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/hello")
    public String hello(){
        String forObject = restTemplate.getForObject("http://provider/hello/", String.class);
        return "我是消费者拿生产者:"+forObject;
    }
}

1.4.2、深入了解LoadBalancer

ribbon负载均衡提供了很多种均衡的方式,而LoadBalancer只提供了轮询的方式。spring官方提出他可能主要是为了提供一些接口,用来制造生态,就目前看来并没有什么好效果。所以等他火了再说吧。

当然LoadBalancer既然提供了接口,那么我们同样可以自定义负载均衡策略。这里我们就不深入了解了,提供一个官方文档看看

官方文档在spring-cloud-commons里面

LoadBalancer官方文档


标题:RabbitMQ消息队列
作者:1938857445
地址:https://www.lmlx66.top/articles/2022/04/25/1650865420859.html