Spring Cloud Ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡工具。可以将面向服务的 REST 模板请求自动转化成客户端负载均衡的服务调用。Spring Cloud Ribbon 虽然是一个工具类框架,但它不像服务注册中心、配置中心、API网关那样需要独立部署。但是它几乎存在于每一个 Spring Cloud 构建的微服务和基础设置中。因为微服务间的调用,API 网关的请求转发等内容,实际上都是通过 Ribbon 来实现的,包括 Feign 它也是基于 Ribbon 实现的工具。所以 Spring Cloud Ribbon 的理解和使用,对于我们使用 Spring Cloud 来构建微服务非常重要。

一、概述


【1】是什么:Spring Cloud Ribbon 是基于 Netflix Ribbon实现的一套客户端的负载均衡的工具。简单的说,Ribbon是 Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将 Netflix 的中间层服务连接在一起。Ribbon 客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说就是在配置文件中列出 Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮你基于某种规则(如单轮询,随机连接等)去连接这些机器。我们也很容易使用 Ribbon实现自定义的负载均衡算法。
【2】作用:LB,即负载平衡(Load Balance)在微服务或分布式集群中经常用的一种应用。负载平衡简单的说,就是将用户的请求平摊的分配到多个服务,而达到服务的HA(高可用)。常见的负载均衡软件Nginx,LVS,硬件F5等。相应的中间件,例如:Dubbo 和 SpringCloud 中均给我们提供了负载均衡,SpinrgCloud 的负载均衡算法可以自定义。
【3】主要分为两种:1)、集中式LB:偏硬件,即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件F5,也可以是软件Nginx),由该设置负责把访问请求通过某种策略转发至服务的提供方; 2)、进程内LB:将 LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。

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

二、Ribbon 初步配置


【1】修改客户端,例如:microservicecloud-consumer-dept-80 工程的 pom.xml 文件;

 1 <!-- Ribbon相关 -->
2 <dependency>
3 <groupId>org.springframework.cloud</groupId>
4 <artifactId>spring-cloud-starter-eureka</artifactId>
5 </dependency>
6 <dependency>
7 <groupId>org.springframework.cloud</groupId>
8 <artifactId>spring-cloud-starter-ribbon</artifactId>
9 </dependency>
10 <dependency>
11 <groupId>org.springframework.cloud</groupId>
12 <artifactId>spring-cloud-starter-config</artifactId>
13 </dependency>
14 <dependency>
15 <groupId>org.springframework.boot</groupId>
16 <artifactId>spring-boot-starter-web</artifactId>
17 </dependency>

【2】修改 application.yml,追加 eureka 的服务注册地址;

1 eureka:
2 client:
3 register-with-eureka: false
4 service-url:
5 defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

【3】对 ConfigBean 配置类,添加新注解 @LoadBalance 获得 RestTemplate 时,加入 Ribbon 的配置;

1 @LoadBalanced//Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端       负载均衡的工具。
2 public RestTemplate getRestTemplate()
3 {
4 return new RestTemplate();
5 }

【4】主启动类 DeptConsumer80_App 添加 @EnableEurekaClient

1 @EnableEurekaClient
2 public class DeptConsumer80_App
3 {

【5】修改 deptController_Consumer 客户端访问类;

1 //微服务的名称MICROSERVICECLOUD-DEPT
2 private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT";
3
4 @RequestMapping(value="/comsumer/dept/add")
5 public boolean add(Consumer comsumer){
6 return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",comsumer,Boolean.class);
7 }

【6】先启动3个 eureka 集群后,在启动 microservicecloud-provider-dept-8001 并注册进 eureka;
【7】启动 microservicecloud-consumer-dept-80;
【8】小结:Ribbon 和 Eureka 整合后 Consumer 可以直接调用服务而不用关心服务和端口号。

三、Ribbon 负载均衡


【1】Ribbon 在工作时分为两步:
   ①、先选择EurekaServer,它优先选择在同一个区域内负载较少的server
   ②、根据用户指定的策略,再从 server取到的服务注册列表中选择一个地址;
【2】实操:①、参考 microservicecloud-provide-dept-8001,创建 microservicecloud-provide-dept-8002 和 8003;
   ②、新建 8002/8003数据库,各微服务分别连各自的数据库;
   ③、修改 8002/8003 各自的 yml:修改端口和数据库连接,对外暴露的统一的服务实例名不能修改;
      ④、启动3个 eureka 集群配置区;
   ⑤、启动3个 Dept 微服务并各自测试通过;
   ⑥、启动 microservicecloud-consumer-dept-80;
   ⑦、客户端通过 Ribbo 完成负载均衡并访问上一步的 Dept微服务;
总结:Ribbo 其实是一个软负载均衡的客户端组件,它可以和其它请求的客户端结合使用,获取 Eureka 中一个实例;

四、Ribbon 核心组件 IRule


Irule:根据特定算法从服务中选取一个要访问的服务。
【1】RoundRobinRule:轮询;
【2】RandomRule:随机;
【3】AvaliabilityFilteringRule:会先过滤掉由于多次访问故障而处于熔断器跳闸状态的服务,还有并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问;
【4】WeightedResponseTimeRule:根据平均响应时间计算所有服务的权重,响应时间越快权重越大被选中的概率就越高,刚启动时统计信息不足时,则使用 RoundRobinRule 策略,等统计信息足够,则会切换到 WeightedResponseTimeRule;
【5】RetryRule:先按照 roundRobinRule 的策略获取服务,如果获取失败则会在指定时间内进行重试,获取可用服务;
【6】BestAvailableRule:会过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务;
【7】ZoneAvoidanceRule:默认规则,复合判断 server 所在区域的性能和 server 的可用性选择器;

以上算法要使用则需要在 customer 端得 configBean.java 配置文件中添加(重要):

@Bean
public IRule myRule()
{
//return new RoundRobinRule();
//return new RandomRule();//达到的目的,用我们重新选择的随机算法替代默认的轮询。
return new RetryRule();
}

五、Ribbon 自定义


【1】修改 microservicecloud-consumer-dept-80;
【2】主启动类添加注解 @RibbonClient:在启动该微服务的时候就能去加载我们的自定义 Ribbon 配置类,从而使配置生效,如:@RibbonClient(name = "MICROSERVICECLOUD-DEPT",configuration=MySelfRule.class)

1 @RibbonClient(name="MICROSERVICECLOUD-DEPT",configuration=MySelfRule.class)
2 public class DeptConsumer80_App
3 {

【3】警告:这个配置类不能放在 @ComponentScan(主启动Java文件的包下面)所扫描的当前包以及子包下,否则我们自定义的这个配置类就会被所有的 Ribbon 客户端共享,也就是说我们达不到特殊化定制的目的。自定义 myrule:(不能和主启动类同一个 package)。不同之处就在于这个类不会扫描到,而是通过 @RibbonClient 注解将其与固定的服务进行绑定。达到与其他微服务不一样的负载均衡算法的目的。

 1 @Configuration
2 public class MySelfRule
3 {
4 @Bean
5 public IRule myRule()
6 {
7 //return new RandomRule();// Ribbon默认是轮询,我自定义为随机
8 //return new RoundRobinRule();// Ribbon默认是轮询,我自定义为随机
9 return new RandomRule_ZY();// 我自定义为每台机器5次
10 }
11 }

【4】深度解析:问题:依旧是轮询策略,但是新需求,每个服务器要求被调用5次。即以前是每台机器一次,现在5次。对随机算法源码进行了修改。继承 AbstractLoadBalancerRule 实现负载均衡算法。详细学习,可以参考 GitHub 上 Ribbon 源码。

 1 public class RandomRule_ZY extends AbstractLoadBalancerRule {
2 // total = 0 // 当total==5以后,我们指针才能往下走,
3 // index = 0 // 当前对外提供服务的服务器地址,
4 // total需要重新置为零,但是已经达到过一个5次,我们的index = 1
5 // 分析:我们5次,但是微服务只有8001 8002 8003 三台,OK?
6 private int total = 0;// 总共被调用的次数,目前要求每台被调用5次
7 private int currentIndex = 0; // 当前提供服务的机器号
8
9 public Server choose(ILoadBalancer lb, Object key) {
10 if (lb == null) {
11 return null;
12 }
13 Server server = null;
14
15 while (server == null) {
16 if (Thread.interrupted()) {
17 return null;
18 }
19 List<Server> upList = lb.getReachableServers();
20 List<Server> allList = lb.getAllServers();
21
22 int serverCount = allList.size();
23 if (serverCount == 0) {
24 /*
25 * 没有服务器。结束而不管通过,因为后续的通过只会得到更多
26 * 限制性的。
27 */
28 return null;
29 }
30
31 // int index = rand.nextInt(serverCount);// java.util.Random().nextInt(3);
32 // server = upList.get(index);
33
34 // private int total = 0; // 总共被调用的次数,目前要求每台被调用5次
35 // private int currentIndex = 0; // 当前提供服务的机器号
36 if (total < 5) {
37 server = upList.get(currentIndex);
38 total++;
39 } else {
40 total = 0;
41 currentIndex++;
42 if (currentIndex >= upList.size()) {
43 currentIndex = 0;
44 }
45 }
46
47 if (server == null) {
48 /*
49 * 只有当服务器列表以某种方式被修剪时,才会发生这种情况。
50 * 这是暂时的情况。屈服后重试。
51 */
52 Thread.yield();
53 continue;
54 }
55
56 if (server.isAlive()) {
57 return (server);
58 }
59
60 // 不应该真的发生。。但必须是暂时的或是一个错误。
61 server = null;
62 Thread.yield();
63 }
64 return server;
65 }
66
67 public Server choose(Object key) {
68 return choose(getLoadBalancer(), key);
69 }
70
71 public void initWithNiwsConfig(IClientConfig clientConfig) {
72 // TODO Auto-generated method stub
73 }
74 }

SpringCloud Ribbon 负载均衡的更多相关文章

  1. SpringCloud Ribbon 负载均衡 通过服务器名无法连接的神坑一个

    一,问题 采取eureka集群.客户端通过Ribbon调用服务,Ribbon端报下列异常 java.net.UnknownHostException: SERVICE-HI java.lang.Ill ...

  2. SpringCloud系列——Ribbon 负载均衡

    前言 Ribbon是一个客户端负载均衡器,它提供了对HTTP和TCP客户端的行为的大量控制.我们在上篇(猛戳:SpringCloud系列——Feign 服务调用)已经实现了多个服务之间的Feign调用 ...

  3. SpringCloud系列五:Ribbon 负载均衡(Ribbon 基本使用、Ribbon 负载均衡、自定义 Ribbon 配置、禁用 Eureka 实现 Ribbon 调用)

    1.概念:Ribbon 负载均衡 2.具体内容 现在所有的服务已经通过了 Eureka 进行了注册,那么使用 Eureka 注册的目的是希望所有的服务都统一归属到 Eureka 之中进 行处理,但是现 ...

  4. SpringCloud无废话入门02:Ribbon负载均衡

    1.白话负载均衡 在上一篇的介绍中,我们创建了两个一模一样的服务提供者:Provider1和Provider2,然后它们提供的服务也一模一样,都叫Hello-Service.为什么一样的服务我们要部署 ...

  5. spring-cloud: eureka之:ribbon负载均衡自定义配置(二)

    spring-cloud: eureka之:ribbon负载均衡自定义配置(二) 有默认配置的话基本上就是轮询接口,现在我们改用自定义配置,同时支持:轮询,随机接口读取 准备工作: 1.eureka服 ...

  6. spring-cloud: eureka之:ribbon负载均衡配置(一)

    spring-cloud: eureka之:ribbon负载均衡配置(一) 比如我有: 一个eureka服务:8761 两个user用户服务: 7900/7901端口 一个movie服务:8010 1 ...

  7. SpringCloud学习(4)——Ribbon负载均衡

    Ribbon概述 SpringCloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具. 简单的说, Ribbon是Netflix发布的开源项目, 主要功能是提供客户端软 ...

  8. spring-cloud配置ribbon负载均衡

    spring-cloud配置ribbon负载均衡 ribbon提供的负载均衡就是开箱即用的,简单的不能再简单了 为了顺利演示此demo,你需要如下 需要提前配置eureka服务端,具体看 https: ...

  9. 浅谈SpringCloud (三) Ribbon负载均衡

    什么是负载均衡 当一台服务器的单位时间内的访问量越大时,服务器压力就越大,大到超过自身承受能力时,服务器就会崩溃.为了避免服务器崩溃,让用户有更好的体验,我们通过负载均衡的方式来分担服务器压力. 我们 ...

  10. SpringCloud学习笔记(2):使用Ribbon负载均衡

    简介 Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具,在注册中心对Ribbon客户端进行注册后,Ribbon可以基于某种负载均衡算法,如轮询(默认 ...

随机推荐

  1. eclipse中同步git代码报错checkout conflict with files

    1.Team--->Synchronize Workspace 2.在同步窗口找到冲突文件,把自己本地修改的复制出来 3.在文件上右键选择 Overwrite----->Yes , 4.再 ...

  2. Failed to apply plugin [id com.android.application]

    Failed to apply plugin [id com.android.application] 这种问题解决方法很简单,在BuildOutPut里面就能找到. 解决方法:在gradle.pro ...

  3. 目前为止最完善专业的微信小程序商城

    购买商业版(368元): http://market.zhenzikj.com/detail/82.html帮助文档:https://www.kancloud.cn/crmeb/crmeb/66242 ...

  4. 第一课 基本的DOS命令

    常见的DOS命令 1.#切换盘符 F: 2.#查看当前目录下所有文件 dir 3.#切换目录 cd change directory cd ..返回上一级 4.#清理屏幕 cls {clear scr ...

  5. redis - 常用方法封装总结

    package com.citydo.utils; import org.springframework.data.redis.connection.DataType; import org.spri ...

  6. C语言基础 DAY1

    程序的三种基本控制结构及其相关概念 1.C语言的三种基本结构 顺序结构:从头到尾一句接着一句的执行下来,直到执行完最后一句: 选择结构:到某个节点后,会根据一次判断的结果来决定之后向哪一个分支方向执行 ...

  7. SQL Server 错误:特殊符号“•”导致的sql查询问题

    问题描述: 对于一些标题或字符串,例如: 如果导入数据库,就会发现会自动变成?号了: 在进行SQL查询的时候,会出现一个同一条sql语句在mysql直接执行sql可以查询到,但是mssql进行查询的时 ...

  8. springboot 日志处理

    引言 springboot框架集成logback日志 logback是由log4j创始人设计的又一个开源日志组件.目前,logback分为三个模块:logback-core,logback-class ...

  9. 关于uniapp的事件监听,使用uni.$once和uni.$on导致的重复监听

    最近写项目的时候遇到个问题,就是在使用uniapp的事件监听器时出现重复监听问题.一开始我是用的uni.$on去监听事件,然后出现了重复的触发监听.百度了下,官方提示单次触发的建议使用uni.$onc ...

  10. C#和C++差异化对比

    这里只记录和C++面向对象的区别,也并无比较成分,只做差异化学习使用. 1. 访问修饰符区别:多了一个Internal:成员仅能被同一个项目中的代码访问. 2. 字段的访问:增加了Get,Set访问器 ...