SpringCloud实践系列:Ribbon负载均衡

一、概述

1.1、什么是Ribbon

Ribbon是负载均衡器,用于解决服务集群的负载均衡

1.2、常见负载均衡

  • 集中式LB 即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5, 也可以是软件,如nginx), 由该设施负责把访问请求通过某种策略转发至服务的提供方;

  • 进程内LB 将LB逻辑到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。

  • Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。

1.3、Ribbon工作流程


二、快速使用

  • 导入依赖

    springcloud alibaba对Ribbon做了兼容,无需单独引用



``` <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> ```
  • 启动类加注解

    // 启动类上开启服务注册与发现功能 @EnableDiscoveryClient 
  • 配置文件

    可以不写,直接使用默认的

    ribbon: 
        eager-load: 
            enabled: true # 是否立即加载(项目启动是,是否拉取实例列表),默认是false(项目启动不拉取,第一次请求时拉取). clients: # 指定哪些服务需要立即加载,数组形式 - cloud-goods
                - cloud-goods2
  • 使用

    在RestTemplate配置文件中,加@LoadBalanced注解

    import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; @Configuration public class ApiConfig { @Bean @LoadBalanced public RestTemplate restTemplate(ClientHttpRequestFactory factory) { return new RestTemplate(factory);
        } @Bean public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
            SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
            factory.setReadTimeout(5000);
            factory.setConnectTimeout(5000); return factory;
        }
    }

三、源码简单追踪

3.1、源码简单追踪

LoadBalancerAutoConfiguration类中有个ribbonInterceptor方法,该方法调了LoadBalancerInterceptor类

public class LoadBalancerAutoConfiguration {
    ...... static class LoadBalancerInterceptorConfig {
        ...... @Bean public LoadBalancerInterceptor ribbonInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) { return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
        }
        ......
    }    
}

LoadBalancerInterceptor类中有个关键的方法intercept,调用RibbonLoadBalancerClient的execute方法,获取实例列表

public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
    ...... public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException { // 获得url URI originalUri = request.getURI(); // 拿到serviceName String serviceName = originalUri.getHost();
        Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri); // 获取实例列表,实现负载均衡 return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
    }
}

RibbonLoadBalancerClient类的execute方法中,获取实例列表,实现负载均衡

public class RibbonLoadBalancerClient implements LoadBalancerClient { public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException { // 获取实例列表(先从本地缓存取,没有则从注册中心取) ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId); // 实现负载均衡(选取负载均衡策略) Server server = this.getServer(loadBalancer, hint); if (server == null) { throw new IllegalStateException("No instances available for " + serviceId);
        } else {
            RibbonLoadBalancerClient.RibbonServer ribbonServer = new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server)); return this.execute(serviceId, (ServiceInstance)ribbonServer, (LoadBalancerRequest)request);
        }
    }
}

3.2、Ribbon核心组件

接口 作用 默认值
IClientConfig 读取配置 DefaultClientConfigImpl
IRule 负载均衡规则,选择实例 ZoneAvoidanceRule
IPing 筛选掉ping不通的实例 DummyPing
ServerList 交给Ribbon的实例列表 Ribbon:ConfigurationBasedServerList Spring Cloud Alibaba:NacosServerList
ServerListFilter 过滤掉不符合条件的实例 ZonePreferenceServerListFilter
ILoadBalance Ribbon的入口 ZoneAwareLoadBalance
ServerListUpdater 更新交给Ribbon的List的策略 PollingServerListUpdater

四、负载均衡策略

4.1、内置的负载均衡策略

Ribbon核心组件IRule: 根据特定算法从服务列表中选取一个需要访问的服务

IRule是一个接口,有7个自带的实现类,可以实现不同的负载均衡算法规则

规则名称 特点
AvailabilityFilteringRule 过滤掉一直连接失败的被标记为circuit tripped的后端Server,并 过滤掉那些高并发的后端Server或者使用一个AvailabilityPredicate 来包含过滤server的逻辑,其实就是检查status里记录的各个server 的运行状态
BestAvailableRule 选择一个最小的并发请求的server,逐个考察server, 如果Server被tripped了,则跳过
RandomRule 随机选择一个Server
ResponseTimeWeightedRule 已废弃,作用同WeightedResponseTimeRule
WeightedResponseTimeRule 根据响应时间加权,响应时间越长,权重越小,被选中的可能性越低
RetryRule 对选定的负载均衡策略加上重试机制,在一个配置时间段内当 选择Server不成功,则一直尝试使用subRule的方式选择一个 可用的Server
RoundRobinRule 轮询选择,轮询index,选择index对应位置的Server
ZoneAvoidanceRule(默认) 默认的负载均衡策略,即复合判断Server所在区域的性能和Server的可用性 选择Server,在没有区域的环境下,类似于轮询(RandomRule)【优中选优,再轮询】

4.2、切换ribbon负载均衡策略

  • 编写配置

    在客户端配置

    注意:不能在启动类的同级/子集下配置

    import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RoundRobinRule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
    
    @Configuration public class MyRibbonRule {
        @Bean public IRule getRule() { return new RoundRobinRule();
        }
    }
  • 配置启动类

    // 启动类上加该注解即可 @RibbonClient(name = "cloud-goods", configuration = {MyRibbonRule.class})

4.3、自定义策略(使用Nacos权重)

直接在页面上修改权重,是无效的。因为负载均衡中引入了ribbon,没有改ribbon配置,还是使用的ribbon的默认负载均衡策略。

使用nacos的权重,需要自定义负载均衡策略

  • 配置权重

    • 在页面上配置

*   在代码中配置 ```
    spring:
      application:
        name: cloud-goods # 服务名
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848 # 指定nacos-server的地址
            username: nacos
            password: nacos
            weight: 10
    server:
      port: 9001
    
    ``` 
  • 自定义负载均衡策略

    拿到nacos的配置,进行自定义的负载均衡策略

    注意:不能在启动类的同级/子集下配置

    import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.ribbon.NacosServer; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.pojo.Instance; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.AbstractLoadBalancerRule; import com.netflix.loadbalancer.BaseLoadBalancer; import com.netflix.loadbalancer.Server; import org.springframework.beans.factory.annotation.Autowired; public class NacosWeightedRule extends AbstractLoadBalancerRule { /**
         * NacosDiscoveryProperties内置了基于权重的负载均衡算法
         */ @Autowired private NacosDiscoveryProperties nacosDiscoveryProperties; /**
         * 读取配置文件并初始化NacosWeightedRule
         * @param iClientConfig
         */ @Override public void initWithNiwsConfig(IClientConfig iClientConfig) {
    
        } /**
         * 实现基于权重的负载均衡算法
         * @param o
         */ @Override public Server choose(Object o) { try {
                BaseLoadBalancer loadBalancer = (BaseLoadBalancer)this.getLoadBalancer(); //想要请求的微服务名称 String name = loadBalancer.getName(); //拿到服务发现新的相关的api NamingService namingService = nacosDiscoveryProperties.namingServiceInstance(); //Nacos client自动通过基于权重的负载均衡算法,给我们选择一个实例 Instance instance = namingService.selectOneHealthyInstance(name); return new NacosServer(instance);
            } catch (NacosException e) { return null;
            }
        }
    }
  • 引用自定义的负载均衡策略

    • 引用配置类

      import com.netflix.loadbalancer.IRule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
      
      @Configuration public class MyRibbonRule {
          @Bean public IRule getRule() { return new NacosWeightedRule();
          }
      }
    • 启动类

      // 启动类上加该注解即可 @RibbonClient(name = "cloud-goods", configuration = {MyRibbonRule.class
#Java##Spring##程序员#
全部评论

相关推荐

12-15 12:50
河北工程大学
sta666:我也是这个国际商业化的,三天,一天一面,就通过了,不过我是后端实习生,好好面感觉能过。
点赞 评论 收藏
分享
不知道怎么取名字_:两个方向 1.简历针对性准备下 2.面试前也需要准备的 主要还是要看各个公司需求,看公司行业和岗位描述,那里面已经写了对技术的需求,一份简历,不可能和所有嵌入式岗位都匹配的
投递北京经纬恒润科技股份有限公司等公司6个岗位
点赞 评论 收藏
分享
评论
点赞
2
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务