03.Ribbon负载均衡
# 01.负载均衡介绍
# 1.1 服务端负载均衡
客户端发送请求被服务端负载均衡拦截,根据负载均衡算法分发请求到具体服务器上处理请求
# 1.2 Ribbon客户端负载均衡
- 第一:通过微服务域名从注册中获取要访问的服务列表
- 第二:使用负载均算法,从服务列表中获取到合适的 ip服务
# 02.Ribbon介绍
- Ribbon是Spring Cloud核心组件之一,它提供的最重要的功能就是负载均衡,和硬件负载均衡F5不同,它的负载均衡是基于客户端的
- Zuul网关和Feign可以通过Ribbon轻松的实现服务的负载均衡,同时避免了与业务无关的冗余代码。
# 2.1 @LoadBalanced原理
在Ribbon示例中可以看到,Ribbon通过一个@LoadBalanced注解就实现了RestTemplate请求的负载均衡
RestTemplate在发送请求的时候会被ClientHttpRequestInterceptor拦截,LoadBalancerInterceptor是ClientHttpRequestInterceptor的实现类
它的作用就是用于RestTemplate的负载均衡,LoadBalancerInterceptor将负载均衡的核心逻辑交给了loadBalancer
# 2.2 获取服务实例列表
Ribbon使用ServerList接口抽象服务实例列表,Ribbon获取服务实例有如下两种方法,可以使用参数{service-name}.ribbon.NIWSServerListClassName进行选择。
Ribbon通过ConfigurationBasedServerList类实现配置服务列表,多个服务实例用逗号隔开
spring.application.name=shop-order
shop-product.ribbon.listOfServers=http://localhost:8001,http://localhost:8002
2
- 利用注册中心获取
- 利用配置文件获取服务实例列表扩展性很差,因为在服务实例上线或者下线的情况下,需要手动修改配置文件,扩展性很低
- 一个健壮的微服务系统会采用注册中心的方式维护服务的上下线。
- Ribbon可以使用DiscoveryEnabledNIWSServerList维护和Eureka之间的服务上下线
# 2.3 动态更新服务实例列表
服务实例上下线在微服务系统中是一个非常常见的场景,Ribbon也实现了该功能,Ribbon定时更新的接口抽象为ServerListUpdater。
当Ribbon从注册中心获取了服务实例列表之后,Ribbon需要动态更新服务实例列表,抽象接口为ServerListUpdater
更新的方式有两种,一种是通过定时任务定时拉取服务实例列表,另一种是通过Eureka服务事件通知的方式。
Ribbon可以通过配置项{service-name}.ribbon.ServerListUpdaterClassName进行选择更新方
方法1:定时拉取
- Ribbon会使用一个定时任务线程池定时拉取更新数据。
方法2:事件通知
- 和PollingServerListUpdater不同的是,如果注册中心是Eureka,可以采用事件通知的方式
- 即当Eureka注册中心发生注册信息变更的时候,那么就将消息发送到事件监听者
- Ribbon使用EurekaNotificationServerListUpdater实现类进行更新,首先会创建一个Eureka监听器
- 当接口接受到通知事件之后,会将更新逻辑提交到线程池中执行
# 2.4 对服务进行心跳检测
- 服务列表中的服务实例未必一直都处于可用的状态,Ribbon会对服务实例进行检测
- PingerStrategy接口抽象检测的策略,Ribbon默认采用了串行的方式进行检测,如果有必要,我们可以通过该接口实现并行的检测方式。
- Pinger会定时通过PingerStrategy获取更新的服务实例,并调用监听者。
# 2.5 负载均衡调度器
从ServerListFilter获取到一个微服务实例集合后,ILoadBalancer需要使用某个策略从集合中选择一个服务实例, 而策略的抽象接口为IRule
选择服务实例之后,ILoadBalancer在调用过程中,会记录请求的执行结果,比如请求的失败成功情况,调用耗时等,IRule接口也可以根据这些信息决定是否使用某个Server。
名称 | 解释 |
---|---|
RoundRobinRule | 轮训策略 |
RandomRule | 随机策略 |
BestAvailableRule | 过滤出故障服务器后,选择一个并发量最小的 |
WeightedResponseTimeRule | 针对响应时间加权轮询 |
AvailabilityFilteringRule | 可用过滤策略,先过滤出故障的或并发请求大于阈值的一部分服务实例,然后再以线性轮询的方式从过滤后的实例清单中选出一个; |
ZoneAvoidanceRule | 从最佳区域实例集合中选择一个最优性能的服务实例 |
RetryRule | 选择一个Server,如果失败,重新选择一个Server重试 |