Spring Cloud之Ribbon负载均衡(Spring Cloud 2020.0.3版)
1. Ribbon简介
一般来说,在生产环境中,各个微服务都会部署多个实例。那么消费者要如何将请求分摊到多个服务提供者实例上呢?负载均衡在系统架构中一个非常重要,不得不去实施的内容,负载均衡是对系统的高可用、网络压力的缓解和处理能力扩容的重要手段之一。通常所说的负载均衡都是指服务端负载均衡,其中分为硬件负载均衡(如F5)和软件负载均衡(如Nginx)。Ribbon是NetFlix发布的客户端负载均衡器,它有助于控制Http和Tcp客户端的行为。通过SpringCloud的封装,可以让我们轻松的将面向服务的REST模板请求自动转换成客户端负载均衡的服务调用。Spring Cloud Ribbon虽然只是一个工具类框架,它不像服务注册中心、配置中心、API网关那样需要独立部署,但是它几乎存在于每一个SpringCloud构建的微服务和基础设施中。
客户端负载均衡和服务端负载均衡的区别?
-
服务端负载均衡
2. Ribbon的使用
-
通过Spring Cloud Ribbon的封装,在微服务架构中使用客户端负载均衡调用非常简单,只需要如下两步:
-
服务提供者只需要启动多个服务实例并注册到服务注册中心
-
服务消费者直接通过调用被@LoadBalanced注解修饰过的RestTemplate来实现面向服务的接口调用
-
-
具体布步骤如下:
-
在服务消费者微服务的POM文件中添加ribbon的依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <version>2.2.8.RELEASE</version> </dependency>
在spring cloud Eureka依赖中已经包含了spring cloud ribbon,因此无需再次引入。如过已经添加了的spring cloud Eureka依赖,不要添加该依赖,否则会遇到空指针错误。
-
服务提供者微服务中给RestTemplate添加@LoadBalanced注解
@Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); }
-
对服务消费者的controller代码进行修改
@Autowired private RestTemplate restTemplate; @Autowired private LoadBalancerClient loadBalancerClient; @GetMapping("/user/{id}") public User findById(@PathVariable long id) { //hardCode硬编码方式不可取 //return restTemplate.getForObject("http://localhost:8000/" + id,User.class); //修改成通过微服务的虚拟主机名来访问 return restTemplate.getForObject("http://userservice/"+id,User.class); } @GetMapping("/log-user-instance") public void logUserInstances() { ServiceInstance serviceInstance = loadBalancerClient.choose("userservice"); log.info("serviceId-->{},Host-->{},port-->{}",serviceInstance.getServiceId(),serviceInstance.getHost(),serviceInstance.getPort()); }
新增加了一个API接口,服务消费者访问该接口时打印出IP地址和端口号
-
现在分别启动1个服务注册中和2个服务提供者、1个服务消费者
-
服务注册中心
-
服务提供者
这里提供一下如何在idea中如何启动两个不同端口号的服务提供者的实例
-
在服务提供者的配置文件中已经配置了server.port=8000,因此第一个实例直接点击运行就可以咯
-
选择Idea右上角启动按钮边上的Edit Configurations,在打开的对话框中,选择UserServiceApplication-->点击复制按钮->VM Options中增加-Dserver.port=8001,Apply应用,如图:
最后点击运行就可以运行port=8001的实例咯
-
-
服务消费者
启动服务消费者,然后不断的访问API接口地址http://localhost:8081/log-user-instance,发现交替打印服务消费者的ip地址。
-
-
搭建过程中遇到的问题:
添加该依赖后,运行时报空指针错误,去掉该依赖后能正常访问。
报错信息如下:
出现该问题的根本原因是Spring Cloud 2020.0.0版本以后对Spring Cloud NetFlix 组件进行剔除,仅保留了Eureka组件,其核心组件 Hystrix、Ribbon、Zuul、Archaius 等均进入维护状态
旧版本的spring-cloud-netflix-dependencies管理着Netflix所有组件,包括Hystrix、Ribbon、Zuul、Eureka等。而自2020.0版本起,它有且只管理Eureka(包括Server和Client)
其中Feign虽然最初属Netflix公司,但从9.x版本开始就移交给OpenFeign组织管理了,因此不再划入Netflix管辖范畴。
简单一句话概括:Spring Cloud 2020.0.0版本彻底删除掉了Netflix除Eureka外的所有组件
Spring Cloud 既然把 Netflix 套件大刀阔斧的砍掉了,那总归得有替代方案吧。那是必然的,Spring Cloud 团队给我们推荐了用于替代的组件:
Spring Cloud LoadBalancer 目前仅支持轮询负载均衡策略,相对于 Ribbon 多种高可用策略还是过于简单。
3. Ribbon负载均衡策略
很多场景下,可能根据需要自定义Ribbon的配置,例如修改Ribbon的负载均衡规则等。
方法一和二适合于Spring Cloud 2020.0.0版本之前的版本,方法三适合Spring Cloud 2020.0.0版之后的Spring Cloud版本
方法一:配置文件的方式
在application.propertites文件中添加如下代码:
#更改负载均衡的负载策略
userservice.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
方法二:使用Java代码自定义Ribbon配置
使用Ribbon提供的负载均衡策略很简单
-
创建具有负载均衡功能的RestTemplate实例
@Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); }
使用RestTemplate进行rest操作的时候,会自动使用负载均衡策略,它内部会在RestTemplate中加入LoadBalancerInterceptor这个拦截器,这个拦截器的作用就是使用负载均衡。
-
默认情况下会采用轮询策略,如果希望采用其它策略,则指定IRule实现,如:
@Bean public IRule ribbonRule() { return new BestAvailableRule(); }
方法三:负载均衡策略配置(适用于Spring Cloud 2020.0.0版之后的版本)
spring cloud加入了一个新模块Spring-Loadbalancer来替代ribbon,有两种负载均衡模式(轮询和随机),默认是用轮询,假如想使用随机或者自定义负载均衡策略,就不能按照以前使用ribbon的模式(注入IRule类,必须引入ribbon依赖),那么如果我使用Loadbalancer的随机负载均衡,要怎么设置呢?官网给出比较详细的方法
显然官方写了一个切换成随机负载均衡的例子,我们拷贝过来即可。
@Bean ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) { String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); return new RandomLoadBalancer(loadBalancerClientFactory .getLazyProvider(name, ServiceInstanceListSupplier.class), name);
-
搭建步骤
-
把官方的@Bean方法拷贝到自己的配置类(这个类可以放到主启动类所在包及子包下,这一点和Ribbon不同)
-
在启动类,使用@LoadBalancerClient或者@LoadBalancerClients注解,加载自己的配置类,由此切换loadBalancer默认的负载均衡策略
-
然后运行代码发现就切换成随机负载均衡策略咯
-
4. Ribbon自定义负载均衡策略
可以参考这篇博客: https://blog.csdn.net/qq_35799668/article/details/114534023