1、SpringCloud Ribbon概述
Spring Cloud Ribbon是一个进行客户端的LoadBalance负载均衡组件,基于HTTP和TCP客户端。它虽然只是一个工具类库,并不需要像eureka注册中心、网关服务那样单独部署,但它却是每一个微服务的基础设施。因为实际上,对于服务间调用、API网关请求转发都需要经过Ribbon负载均衡来实现,比如我们熟悉的Feign发送请求也得经过它。负载均衡是互联网开发避不开的核心概念之一,它是HA高可用的最有效手段。而在微服务日益流行的今天,对Ribbon的理解和使用,对于我们构建微服务非常重要。
Ribbon是一个内置LoadBalance平衡器的进程间通信(远程过程调用)库。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,Ribbon是一个客户端负载均衡器,我们可以在配置文件中Load Balancer后面的所有机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器,我们也很容易使用Ribbon实现自定义的负载均衡算法。
Spring cloud有两种服务调用方式,一种是ribbon+restTemplate,另一种是feign。
2、Ribbon 负载均衡
当前微服务分布式架构下,下游服务通常会创建多个副本实例,每个副本都在另一台计算机上运行。此时,出现 Load Balancer(负载均衡器),根据负载策略将上有服务请求映射到每一个副本上,它有助于在服务器之间平均分配传入流量。
2.1 客户端负载均衡和服务端负载均衡
客户端负载均衡和服务端负载均衡最大的不同在于服务清单所在的位置。客户端负载均衡中,客户端中都维护着自己要访问的服务段清单,而这些清单都来源于服务注册中心,但是服务端负载均衡的服务清单是无法自己来维护的。
(1) 服务端负载均衡器
传统上,Load Balancers(例如Nginx、F5)是放置在服务器端的组件。当请求来自 客户端 时,它们将转到负载均衡器,负载均衡器将为请求指定 服务器。负载均衡器使用的最简单的算法是随机指定。在这种情况下,大多数负载平衡器是用于控制负载平衡的硬件集成软件。
特点:
- 服务端地址对客户端透明,客户端不知道服务器端的服务列表,甚至不知道自己发送请求的目标地址存在负载均衡器。
- 服务器端维护负载均衡服务器,控制负载均衡策略和算法。
(2)客户端负载均衡器
当负载均衡器位于 客户端 时,客户端得到可用的服务器列表然后按照特定的负载均衡策略,分发请求到不同的 服务器 。

特点:
- 客户端需要知道服务器端的服务列表(可能通过配置、可能让其自己去注册中心拉取),需要自行决定请求要发送的目标地址。
- 客户端维护负载均衡服务器,控制负载均衡策略和算法。
2.2 负载均衡器分类
-
BaseLoadBalancer
BaseLoadBalancer类时Ribbon服务均衡器的基础实现类,在该类中定义了很多关于负载均衡器光宇的基础内容。
-
DynamicServiceListLoadBalancer
DynamicServiceListLoadBalancer负载均衡器时对BaseLoadBalancer的扩展。
-
ZoneAwareLoadBalancer
ZoneAwareLoadBalancer负载均衡器时对DynamicServiceListLoadBalancer的扩展。
springcloud — 微服务负载均衡组件之Ribbon
2.3、负载均衡策略
IRule时负载均衡策略的接口,AbstractLoadBalancerRule是负载均衡策略的抽象类。下面我们看一下几个具体的实现类:
- RandomRule: 实现了从服务实例清单中随机选择一个服务实例的功能
- RoundRobinRule:实现了按照线性轮询的方式一次选择每个服务实例的功能
- RetryTule:实现了一个具备重试机制的实例选择功能
- WeightedRespinseTimeRule:该策略是对RoundRobinRule的扩展,增加了根据实例的运行情况来计算权重,并根据权重来挑选实例,已达到更优的分配效果。
- ClientConfigEnabledRoundRobinRule:该策略较为特殊,我们一般不直接使用它。因为它本身并没有实现什么特殊的处理逻辑,真如代码中所示,在他的内部定义了一个RoundRobinRule策略,而choose函数的实现也正是使用了RoundRobinRule的线性轮询机制,所以它实现的功能实际上RoundeRobinRule相同。虽然不能直接使用该策略,但是可以通过继承该策略,默认的choose就实现了线性轮询机制,可以在子类中实现更高级的策略;
- BestAvailableRule:该策略通过遍历负载均衡器中维护的所有实例,会过滤调故障的实例,并找出并发请求数最小的一个,所以该策略的特征是选择出最空闲的实例;
- PredicateBaseRule:先通过子类中实现的Predicate逻辑来过滤一部分服务实例,然后再以线性轮询的方式从过滤后的实例清单中选出一个。至于如何过滤,需要我们在AbstractServerPredicate的子类中实现apply方法来确定具体的实现策略。
-
ZoneAvoidanceRule:它是PredicateBaseRule的具体实现类,从它的源码中可以看到它是通过CompositePredicate来进行服务实例清单过滤的。这是一个组合过滤条件,在其构造函数中,ZoneAvoidancePredicate为主过滤条件,AvailabilityPredicate为次过滤条件初始化了组合过滤条件的实例。
ZoneAvoidanceRule在实现的时候并没有像AvailabilityFilteringRule那样重写choose函数来优化,它遵循:“先过滤清单,再轮询选择”。其中过滤清单的条件就是我们上面提到的以ZoneAvoidancepredicate为主过滤条件,AvailabilityPredicate为次过滤条件的组合过滤条件。从CompositePredicate的代码片段中,我们可以看到它定义的一个主过滤条件AbstraServicePredicate Delegate以及一组次过滤条件列表listfallbacks,所以它的此过滤列表是可以拥有多个的,并且由于它采用了List存储所以次过滤条件是按顺序执行的。
3、Ribbon实践
基础环境:
SpringCloud 版本 Finchley.RC1
SpringBoot 版本 2.0.1.RELEASE
添加Ribbon依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
application.yml配置:
server:
port: 8381
spring:
application:
name: spring-demo-service-ribbon
spring-demo-service:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
启动类:
@SpringBootApplication
@EnableDiscoveryClient
public class ServiceRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceRibbonApplication.class, args);
}
/**
* 向容器中注入 restTemplate,同时通过 @LoadBalanced 开启 restTemplate 负载均衡功能
* @return
*/
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
在启动类中,通过@EnableDiscoveryClient 向 consul 注册,并向容器中注入 restTemplate,同时通过 @LoadBalanced 开启 restTemplate 负载均衡功能。
测试service类:
@Service
public class SpringDemoRibbonService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "portFallback")
public String port() {
return restTemplate.getForObject("http://SPRING-DEMO-SERVICE/port", String.class);
}
public String portFallback() {
return "sorry ribbon, it's error!";
}
}
这里我们启动了两个spring-demo-service服务,实现一个简单的port接口进行远程调用,然后在浏览器中多次访问 localhost:8381/hello,效果如下:
此时说明基本使用 Ribbon 实现了客户端负载均衡的功能,当用 restTemplate 调用服务接口时,访问了不同端口的服务实例。
4、Ribbon模块说明
ribbon五大组件:
- ServerList:可以响应客户端的特定服务的服务器列表
- ServerListFilter:可以动态获得的具有所需特征的候选服务器列表的过滤器
- ServerListUpdater:用于执行动态服务器列表更新
- IRule:负载均衡策略,用于确定从服务器列表返回哪个服务器
- IPing:客户端用于快速检查服务器当时是否处于活动状态(心跳检测)
- ILoadBalancer:负载均衡器,负责负载均衡调度的管理
说明,以上核心组件所在的Jar其实是ribbon-loadbalancer,它包含ribbon-core,更面向于应用层面,所以一般都会使用它。
Ribbon 依赖包中Modules模块:
- ribbon-core:客户端配置api和其他共享api
- ribbon-loadbalancer:可以独立使用或与其他模块一起使用的负载均衡器api
- ribbon:集成了负载平衡、容错、缓存/批处理等功能的api
- ribbon-eureka:使用Eureka客户端为云提供动态服务器列表的api
- ribbon-httpclient:REST客户端构建在Apache HttpClient之上,与负载平衡器集成(不支持并被ribbon模块取代)
- ribbon-transport:使用具有负载平衡功能的RxNetty传输支持HTTP、TCP和UDP协议的客户端
引用: https://www.springcloud.cc/spring-cloud-greenwich.html#spring-cloud-ribbon https://blog.csdn.net/f641385712/article/details/104761814