Ribbon简介
需要解决的问题:
① 如何在配置Eureka Client注册中心时不去硬编码Eureka Server的地址?
② 在微服务不同模块间进行通信时,如何不去硬编码服务提供者的地址?
③ 当部署多个相同微服务时,如何实现请求时的负载均衡?
实现负载均衡方式1:通过服务器端实现负载均衡(nginx)
实现负载均衡方式2:通过客户端实现负载均衡。
Ribbon是什么?
Ribbon是Netflix发布的云中间层服务开源项目,其主要功能是提供客户端实现负载均衡算法。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,Ribbon是一个客户端负载均衡器,我们可以在配置文件中Load Balancer后面的所有机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器,我们也很容易使用Ribbon实现自定义的负载均衡算法。
下图展示了Eureka使用Ribbon时的大致架构:
Ribbon工作时分为两步:第一步选择Eureka Server,它优先选择在同一个Zone且负载较少的Server;第二步再根据用户指定的策略,再从Server取到的服务注册列表中选择一个地址。其中Ribbon提供了很多策略,例如轮询round robin、随机Random、根据响应时间加权等。
Ribbon的使用
集成Ribbon以及简单使用
如何集成Ribbon?
查看Spring cloud官方文档,搜索Ribbon。
① 首先引入Ribbon依赖
按照官方的意思是需要加入以下依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
但是其实是不需要的加入这个依赖的,在spring-cloud-starter-eureka依赖中就已经包含了Ribbon Starter (上节已知spring-cloud-starter-eureka-server 是为编写Eureka Server提供依赖,spring-cloud-starter-eureka是为编写Eureka Client提供依赖),因此只需要Eureka Client具有spring-cloud-starter-eureka依赖即可。即在POM中需要有
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-eureka</artifactId>
-
</dependency>
② 如何使用Ribbon
上节示例中是使用RestTemplate进行Eureka Client(包括服务提供者以及服务消费者,在这里其实是服务消费者使用RestTemplate)之间的通信,为RestTemplate配置类添加@LoadBalanced注解即可,如下所示:
-
@Bean
-
@LoadBalanced
-
public RestTemplate restTemplate() {
-
return new RestTemplate();
-
}
③ 如何解决硬编码
使用添加@LoadBalanced注解后的RestTemplate调用服务提供者的接口时,可以使用虚拟IP替代真实IP地址。所谓的虚拟IP就是服务提供者在application.properties或yml文件中配置的spring.application.name属性的值。示例如下:
-
@GetMapping("/movie/{id}")
-
public User findById(@PathVariable Long id) {
-
// VIP: Virtual IP http://microservice-provider-user/即虚拟IP 服务提供者的ServiceId (spring.application.name)
-
return this.restTemplate.getForObject("http://microservice-provider-user/simple/" + id, User.class);
-
}
运行测试:依次启动Eureka Server和Eureka Clients(服务提供者和服务消费者)
访问测试:
负载均衡测试:依次启动Eureka Servler 和 Eureka Client(一个服务消费者movie 两个不同端口号相同的服务提供者)
在服务提供者端访问4次
发现两个服务提供者user分别被调用了2次,说明Ribbon默认的负载均衡策略是轮询。
自定义RibbonClient
如何为服务消费者自定义Ribbon Client?
① 代码自定义RibbonClient
所谓的自定义Ribbon Client的主要作用就是使用自定义配置替代Ribbon默认的负载均衡策略,注意:自定义的Ribbon Client是有针对性的,一般一个自定义的Ribbon Client是对一个服务提供者(包括服务名相同的一系列副本)而言的。自定义了一个Ribbon Client 它所设定的负载均衡策略只对某一特定服务名的服务提供者有效,但不能影响服务消费者与别的服务提供者通信所使用的策略。根据官方文档的意思,推荐在 springboot主程序扫描的包范围之外进行自定义配置类。其实纯代码自定义RibbonClient的话有两种方式:
方式一:在springboot主程序扫描的包外定义配置类,然后为springboot主程序添加@RibbonClient注解引入配置类
-
@Configuration
-
public class TestConfiguration {
-
@Autowired
-
private IClientConfig config;
-
@Bean
-
public IRule ribbonRule(IClientConfig config) { // 自定义为随机规则
-
return new RandomRule();
-
}
-
}
注意:@RibbonClient注解中的name属性是指服务提供者的服务名(即当前消费者使用自定义配置与其通信的服务提供者的spring.application.name的属性)
@RibbonClient(name = "microservice-provider-user",configuration = TestConfiguration.class)
方式二:在与springboot主程序的同一级目录新建RibbonClient的配置类,但是必须在springboot扫描的包范围内排除掉,方法是自定义注解标识配置类,然后在springboot的添加@ComponentScan根据自定义注解类型过滤掉配置类
自定义注解
-
public @interface ExcludeFromComponentScan {
-
}
自定义配置类
-
@Configuration
-
@ExcludeFromComponentScan
-
public class TestConfiguration1 {
-
@Autowired
-
private IClientConfig config;
-
@Bean
-
public IRule ribbonRule(IClientConfig config) { // 自定义为随机规则
-
return new RandomRule();
-
}
-
}
在springboot主程序上添加注解
-
@RibbonClient(name = "microservice-provider-user",configuration = TestConfiguration1.class)
-
@ComponentScan(excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = ExcludeFromComponentScan.class)})
运行测试:
② 通过配置文件自定义RibbonClient
官方文档地址:http://cloud.spring.io/spring-cloud-static/Camden.SR7/#_customizing_the_ribbon_client_using_properties
意思就是:配置RibbonClient规则是
<服务名>.ribbon.<类型>=与类型对应的类名(也可以自定义)
类型可以为一下几个:
NFLoadBalancerClassName: 应该实现 ILoadBalancer接口
NFLoadBalancerRuleClassName: 应该实现 IRule接口
NFLoadBalancerPingClassName: 应该实现 IPing接口
NIWSServerListClassName: 应该实现ServerList接口
NIWSServerListFilterClassName: 应该实现ServerListFilter接口
详解:
独立使用Spring Cloud Ribbon,在没有引入Spring Cloud Eureka服务治理框架时, 默认接口实现类:
1.IClientConfig:Ribbon的客户端配置,默认采用com.netflix.cilent.config.DefaultClientConfigImpl实现。
2.IRule:Ribbon的负载均衡策略,默认采用com.netflix.loadbalancer.ZoneAvoidanceRule实现,该策略能够在多区 域环境下选择出最佳区域的实例访问。
3.IPing:Ribbon的实例检查策略,默认采用com.netflix.loadbalancer.NoOpPing实现,该检查策略是一种特殊实现方式,实际上它并不会检查实例是否可用,而是始终返回True,默认认为所有实例都可用。
4.ServerList<Server>:服务实例清单的维护机制,默认采用com.netflix.loadbalancer.ConfigurationBasedServerList实现。
5.ServerListFilter<Server>:服务实例清单过滤机制,默认采用org.springframework.cloud.netflix.ribbon.ZonePreferenceServerListFilter实现,该策略能够优先过滤出与请求调用方处于同区域的服务实例。
6.ILoadBalancer:负载均衡器,默认采用com.netflix.loadbalancer.ZoneAwareLoadBalancer实现,它具备区域感知能力
Spring Cloud Eureka和Spring Cloud Ribbon结合使用,Ribbon默认接口实现类:
1.IPing:Ribbon的实例检查策略,默认采用com.netflix.niws.loadbalancer.NIWSDiscoveryPing实现,该检查策略是一种特殊实现方式,实际上它并不会检查实例是否可用,而是始终返回True,默认认为所有实例都可用
2.ServerList<Server>:服务实例清单的维护机制,默认采用com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList实现,将所有服务清单交给Eureka的服务治理机制进行维护
其中最常用的是配置RibbonClient的负载均衡规则,如下所示:
application.yml中添加
users:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule
自带的IRule实现类有以下几个:
BestAvailableRule 选择最小请求数
ClientConfigEnabledRoundRobinRule 轮询
RandomRule 随机选择一个server
RoundRobinRule 轮询选择server
RetryRule 根据轮询的方式重试
WeightedResponseTimeRule 根据响应时间去分配一个weight ,weight越低,被选择的可能性就越低(响应时间加权)
ZoneAvoidanceRule 根据server的zone区域和可用性来轮询选择
注意:如果多种整合方式都存在的话是存在优先级的,即 文件配置优先级 > 代码配置优先级 > 默认配置优先级
使用示例如下:在application.yml中添加如下配置即可为请求microservice-provider-user的服务提供者时设置随机策略。
-
microservice-provider-user:
-
ribbon:
-
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
经过测试是完全可行的。
Ribbon脱离Eureka使用
官方描述地址:http://cloud.spring.io/spring-cloud-static/Camden.SR7/#spring-cloud-ribbon-without-eureka
Eureka是用于服务发现和服务注册、以及使用服务名来解决服务消费者和服务提供者通信时地址的硬编码问题的。如果Ribbon脱离了Eureka,那么在服务消费者端就无法根据服务名通过心跳机制从EurekaServer端获取对应服务提供者的IP以及端口号。这时就需要在服务消费者端配置对应服务提供者的地址列表,然后Ribbon才能通过配置文件或者自定义的RibbonClient或者默认的配置获取负载均衡的轮询策略进行请求分发。
配置方式:
第一步:检查是否引入了Eureka。如果服务在依赖中添加了spring-cloud-starter-eureka,这种情况下如果想使Ribbon脱离Eureka使用的话就需要将Eureka禁用掉。仅仅需要添加以下配置,如果没有引入Eureka就不需要禁用。
-
ribbon:
-
eureka:
-
enabled: false
第二步:配置某服务提供者的地址列表以及均衡策略(默认是轮询)
-
<服务提供者名称>:
-
ribbon:
-
listOfServers: localhost:7901,localhost:7902
-
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
因为我的Demo中引入了Eureka,所以我的配置如下所示:
-
ribbon:
-
eureka:
-
enabled: false
-
microservice-provider-user:
-
ribbon:
-
listOfServers: localhost:7901,localhost:7902
-
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
具体代码已上传GitHub,地址:https://github.com/liuxun1993728/ribbonDemo