• SpringCloud之Ribbon负载均衡解读


    目录

    基本介绍

    概述

    @LoadBalanced理解

    简单源码解读

    1)LoadBalancerIntercepor

    2)LoadBalancerClient

    3)负载均衡策略IRule

    4)总结

    负载均衡策略

    负载均衡策略

    自定义负载均衡策略


    基本介绍

    概述

    Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们很容易使用Ribbon实现自定义的负载均衡算法。

    Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。(负载均衡+RestTemplate调用)

    @LoadBalanced理解

    RestTemplate是Spring提供的一个简单的Rest模板客户端,用来进行API的调用。

    如果我们向要在微服务应用中使用RestTemplate,并达到负载均衡的效果应该怎么做呢 ?大家都知道在微服务中,一般同一个服务实例不只一个,那么就涉及到请求过程中服务实例的选择问题。答案是使用@LoadBalanced注解,将该注解加在RestTemplate的Bean上,就可以实现负载均衡。

    示例代码如下:

    1. @Configuration
    2. public class AppConfiguration {
    3. @Bean
    4. @LoadBalanced // 开启负载均衡能力
    5. public RestTemplate restTemplate() {
    6. return new RestTemplate();
    7. }
    8. }

    此时当我们使用RestTemplate就会变成这个样子,url变为了http://provider/test,不会直接使用http://ip:port/test的形式,而是使用服务名称,根据服务名称去注册中心获取实际的服务信息,最终再转换为要请求的地址。 

    简单源码解读

    以发出的请求明明是http://userservice/user/1,变成了http://localhost:8081为例

    为什么我们只输入了service名称就可以访问了呢?之前还要获取ip和端口。显然有人帮我们根据service名称,获取到了服务实例的ip和端口。它就是LoadBalancerInterceptor,这个类会在对RestTemplate的请求进行拦截,然后从Eureka根据服务id获取服务列表,随后利用负载均衡算法得到真实的服务地址信息,替换服务id。

    我们进行源码跟踪:

    1)LoadBalancerIntercepor

    可以看到这里的intercept方法,拦截了用户的HttpRequest请求,然后做了几件事:

    • request.getURI():获取请求uri,本例中就是 http://user-service/user/8

    • originalUri.getHost():获取uri路径的主机名,其实就是服务id,user-service

    • this.loadBalancer.execute():处理服务id,和用户请求。

    这里的this.loadBalancerLoadBalancerClient类型,我们继续跟入。

    2)LoadBalancerClient

    继续跟入execute方法:

    代码是这样的:

    • getLoadBalancer(serviceId):根据服务id获取ILoadBalancer,而ILoadBalancer会拿着服务id去eureka中获取服务列表并保存起来。

    • getServer(loadBalancer):利用内置的负载均衡算法,从服务列表中选择一个。本例中,可以看到获取了8082端口的服务

    放行后,再次访问并跟踪,发现获取的是8081:

    3)负载均衡策略IRule

    在刚才的代码中,可以看到获取服务使通过一个getServer方法来做负载均衡, 我们继续跟入:

    继续跟踪源码chooseServer方法,发现这么一段代码:

      我们看看这个rule是谁:

    这里的rule默认值是一个RoundRobinRule,看类的介绍:

    可以知道就是轮询  

    4)总结

    1、在创建RestTemplate的bean时添加@LoadBalanced注解
    2、LoadBalancerAutoConfiguration自动配置筛选出添加@LoadBalanced注解的RestTemplate
    3、为RestTemplate设置LoadBalancerInterceptor,目的是使用LoadBalancerClient来发起请求
    4、请求过程中,根据负载均衡策略,调用LoadBalancerClient.choose()方法获取最终ServiceInstance
    5、根据ServiceInstance获取真实host、port,发起最后请求

    负载均衡策略

    负载均衡策略

    负载均衡的规则都定义在IRule接口中,而IRule有很多不同的实现类:

    不同规则的含义如下:

    内置负载均衡规则类规则描述
    RoundRobinRule简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。
    AvailabilityFilteringRule对以下两种服务器进行忽略: (1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。 (2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上限,可以由客户端的..ActiveConnectionsLimit属性进行配置。
    WeightedResponseTimeRule为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。
    ZoneAvoidanceRule以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做轮询。
    BestAvailableRule忽略那些短路的服务器,并选择并发数较低的服务器。
    RandomRule随机选择一个可用的服务器。
    RetryRule重试机制的选择逻辑

    默认的实现就是ZoneAvoidanceRule,是一种轮询方案  

    自定义负载均衡策略

    通过定义IRule实现可以修改负载均衡规则,有两种方式:

    代码方式:在启动类中,定义一个新的IRule:

    官方文档明确给出了警告:这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,达不到特殊化定制的目的了。 

    1. @Bean
    2. public IRule randomRule(){
    3.    return new RandomRule();
    4. }

    配置文件方式:在order-service的application.yml文件中,添加新的配置也可以修改规则:

    1. userservice: # 给某个微服务配置负载均衡规则,这里是userservice服务
    2. ribbon:
    3.   NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则

    注意,一般用默认的负载均衡规则,不做修改。

  • 相关阅读:
    Mysql学习(一)之Mysql的介绍和安装
    python3 中调用 C 语言的函数
    Play Beyond:Sui让优秀的游戏变得更好
    并发容器线程安全应对之道-ConcurrentHashMap
    java计算机毕业设计小王防疫副食品配送商城源程序+mysql+系统+lw文档+远程调试
    Node.js阶段学习(一)
    Java RSA密钥从RSAPrivateKey和RSAPublicKey对象中,分别提取模和指数
    计算机系统概论
    Java方法调用动态绑定(多态性)详解
    C //例 8.22 用函数求整数a和b中的大者。
  • 原文地址:https://blog.csdn.net/m0_62436868/article/details/133838130