简介
Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模板请求自动转换成客户端负载均衡的服务调用。Spring Cloud Ribbon虽然只是一个工具类框架,它不像服务注册中心、配置中心、API网关那样需要独立部署,但是它几乎存在于每一个SpringCloud构建的微服务和基础设施中。因为微服务间的调用,API网关的请求转发等内容,实际上都是通过Ribbon来实现的,包括后续我们将要介绍的Feign,它也是基于Ribbon实现的工具。所以,对Spring Cloud Ribbon的理解和使用,对于我们使用Spring Cloud来构建微服务非常重要。
服务端负责均衡和客户端负载均衡
负载均衡在系统架构中是一个非常重要,并且是不得不去实施的内容。因为负载均衡是对系统的高可用、网络压力的缓解和处理能力扩容的重要手段之一。我们通常所说的负载均衡都指的是服务端负载均衡,其中分为硬件负载均衡和软件负载均衡。硬件负载均衡主要通过在服务器节点之间按照专门用于负载均衡的设备,比如F5等;而软件负载均衡则是通过在服务器上安装一些用于负载均衡功能或模块等软件来完成请求分发工作,比如Nginx等。不论采用硬件负载均衡还是软件负载均衡,只要是服务端都能以类似下图的架构方式构建起来:
硬件负载均衡的设备或是软件负载均衡的软件模块都会维护一个下挂可用的服务端清单,通过心跳检测来剔除故障的服务端节点以保证清单中都是可以正常访问的服务端节点。当客户端发送请求到负载均衡设备的时候,该设备按某种算法(比如线性轮询、按权重负载、按流量负载等)从维护的可用服务端清单中取出一台服务端端地址,然后进行转发。
而客户端负载均衡和服务端负载均衡最大的不同点在于上面所提到服务清单所存储的位置。在客户端负载均衡中,所有客户端节点都维护着自己要访问的服务端清单,而这些服务端端清单来自于服务注册中心,比如Eureka服务端。同服务端负载均衡的架构类似,在客户端负载均衡中也需要心跳去维护服务端清单的健康性,默认会创建针对各个服务治理框架的Ribbon自动化整合配置,比如Eureka中的org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,Consul中的org.springframework.cloud.consul.discovery.RibbonConsulAutoConfiguration。在实际使用的时候,我们可以通过查看这两个类的实现,以找到它们的配置详情来帮助我们更好地使用它。
通过Spring Cloud Ribbon的封装,我们在微服务架构中使用客户端负载均衡调用非常简单,只需要如下两步:
- 1.服务提供者只需要启动多个服务实例并注册到一个注册中心或是多个相关联的服务注册中心。
- 2.服务消费者直接通过调用被@LoadBalanced注解修饰过的RestTemplate来实现面向服务的接口调用。
Ribbon的使用方式
在前面的介绍中,我们已经说了ribbon是客户端的负载均衡,因此服务端的清单来自于注册中心,因此客户端的负载均衡是需要依靠注册中心的。
Ribbon客户端负载均衡的三种使用方式:
- RestTemplate方式
- LoadBalancerClient方式
- FeignClient的方式(该方式会在Feign的中进行详解)
那么接下来就对前两种方式进行演示,在演示之前作出需要的准备工作:
- 1.启动一个高可用的Eureka-Server服务端
- 2.创建一个服务应用,以对外提供接口服务
- 3.复制一份该服务端服务,除了端口号不一致其他都保持一致,尤其
spring.application.name
要保持一致(保证相同的服务应用由多个服务进行提供),用于验证在外部请求到达时是否负载均衡
关于该具体步凑可以参考:http://blog.youkuaiyun.com/qq_26323323/article/details/78652849
注意:上面的准备工作都是提供注册中心和服务提供者,然而下面的演示都可以算是服务消费者,可以认为消费者通过不同的方式使用Ribbon负责均衡来消费服务提供者。
- 一、RestTemplate方式:
1.添加Ribbon相关的依赖
<dependencies>
<!-- spring-boot-starter-web web项目,集成容器tomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring-boot-starter-actuator 管理工具/web 查看堆栈,动态刷新配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- cloud eureka组件 客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!-- Ribbon依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
</dependencies>
2.向容器中注入RestTemplate
对象,并开启Ribbon的负载均衡
@Configuration
public class MyConfiguration{
@LoadBalanced//开启Ribbon的负载均衡;注意Ribbon默认使用的负载均衡策略是:轮询
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
注意:@LoadBalance注解让注入的RestTemplate
对象可以通过负载均衡的方式获取到服务,如果不添加该注解的话,在使用后续使用RestTemplate
对象去获取服务是会抛出找不到服务异常的。因为去Eureka
注册中心中获取服务是默认通过Ribbon实现了负载均衡的,如果不通过负载均衡策略的方式是拿不到服务的。
在这里补充一下对RestTemplate
的说明,该类是SpringCloud提供的一个Rest客户端访问模板,也可以说是访问Rest请求的工具。该对象中有发送Get
和Post
请求对应的方法;但是如果访问rest路径地址包含微服务的名称,也就是说需要从注册中心中获取服务的地址,就需要添加@LoadBalance注解,因为添加了该注解的RestTemplate
对象会被扫描添加到restTemplates
容器中(该容器就是LoadBalancerAutoConfiguration
中定义的存放RestTemplate对象的容器,存放在该容器中的RestTemplate对象就能获取到注册中心中对应服务)
3.在Controller中依赖RestTemplate
,并调用服务
@RestController("TestController")
public class TestController{
@Autowired
private RestTemplate restTemplate;
@RequstMapping("test")
@ResponseBody
public String test(){
ResponseEntity<String> resp = restTemplate.getForEntity("http://"+{application_name}+"/sms/test",String.class);
return resp.getBody();
}
}
application_name就是微服务的名称, /sms/test:就是该微服务下的接口api
- 二、LoadBalancerClient方式:
1.添加Ribbon的依赖,该依赖和上面一样;
2.在Controller中依赖LoadBalancerClient
@RestController("TestController")
public class TestController {
@Autowired
private LoadBalancerClient loadBalanceClient;
@RequestMapping("test")
@ResponseBody
public String test(){
//通过LoadBalancerClient的choose方法根据服务名称获取服务实例
ServiceInstance serviceInstance = loadBalanceClient.choose("{application_name}");
//服务实例中封装的有该服务的主机地址和端口
String url = "http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/sms/test";
//然后通过Http的方式去访问该地址就可以调用该服务啦。
}
}
该方式是通过loadBalanceClient的choose方法负载均衡的方式从注册中心中获取服务实例;服务实例中就封装的有获取到的服务所在的主机地址和端口。
关于使用第三种方式Feign
通过负载均衡的方式获取调用服务将在Feign中进行讲解
Ribbon配置
通过上面我们可以知道Ribbon默认使用的负载均衡策略是轮询的方式,那么我们如何进行切换Ribbon的负载均衡策略呢?
在解决上面的问题之前,我们需要了解Ribbon为我们提供了哪些负载均衡策略呢?
通过这张图片我们大概可以一目了然啦。那么接下来,就是修改Ribbon的默认策略,修改Ribbon提供的负载均衡默认策略有两个方向:
- 1.修改全局负载均衡策略
向容器中注入所需要提供的负责均衡策略对象:
@SpringBootApplication
@EnableEurekaClient
public class EurekaProviderApp1 {
public static void main(String[] args) {
SpringApplication.run(EurekaProviderApp1.class,args);
}
@Bean
public IRule rule(){
return new WeightedResponseTimeRule();
}
}
向容器中注入所需要的负载均衡策略对象,就会让整个Ribbon对所有的微服务都采用该策略做负载均衡。
- 2.修改针对某个微服务的负载均衡策略
方式1: 使用配置文件的方式
# 微服务名称.ribbon.NFLoadBalancerRuleClassName=负责均衡策略对象
cloud-provider.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
方式2: 使用@RibbonClients或者@RibbonClient注解
引用:
1.https://www.jianshu.com/p/1bd66db5dc46
2.https://blog.youkuaiyun.com/qq_26323323/article/details/78668776