Spring Cloud Ribbon 是一一基于HTTP 和TCP 的客户端负载均衡工具,它基于NetflixRibbon实现。通过Spring Cloud 的封装,可以让我们轻松地将面向服务的REST 模板请求自动转换成客户端负载均衡的服务调用。Spring Cloud Ribbon 虽然只是一个工具类框架,它不像服务注册中心、配置中心、API 网关那样需要独立部署,但是它儿乎存在于每一个SpringCloud 构建的微服务和基础设施中。因为微服务间的调用,API 网关的请求转发等内容,实际上都是通过Ribbon 来实现的,包括后续我们将要介绍的Feign,它也是基于Ribbon实现的工具。所以,对Spring Cloud Ribbon 的理解和使用,对于我们使用Spring Cloud 来构建微服务非常重要。
在这里,我们将介绍如何使用Ribbon 来实现客户端的负载均衡,并且通过源码分析来了解Ribbon 实现客户端负载均衡的基本原理。
客户端负载均衡
负载均衡在系统架构中是一个非常重要,并且是不得不去实施的内容。因为负载均衡是对系统的高可用、网络压力的缓解和处理能力扩容的重要手段之一。我们通常所说的负载均衡都指的是服务端负载均衡,其中分为硬件负载均衡和软件负载均衡。硬件负载均衡主要通过在服务器节点之间安装专门用于负载均衡的设备,比如F5 等; 而软件负载均衡则是通过在服务器上安装一些具有均衡负载功能或模块的软件来完成请求分发工作,比如Nginx 等。不论采用硬件负载均衡还是软件负载均衡,只要是服务端负载均衡都能以架构方式构建起来:
硬件负载均衡的设备或是软件负载均衡的软件模块都会维护一个下挂可用的服务端清单,通过心跳检测来剔除故障的服务端节点以保证清单中都是可以正常访问的服务端节点。当客户端发送请求到负载均衡设备的时候,该设备按某种算法(比如线性轮询、按权重负载、按流量负载等) 从维护的可用服务端清单中取出一台服务端的地址,然后进行转发。
而客户端负载均衡和服务端负我均衡最大的不同点在于上面所提到的服务清单所存储的位置。在客户端负载均衡中,所有客户端节点都维护着自己要访问的服务端清单,而这些服务端的清单来自于服务注册中心,比如Eureka 服务端。同服务端负载均衡的架构类似,在客户端负载均衡中也需要心跳去维护服务端清单的健康性,只是这个步骤需要与服务注册中心配合完成。在Spring Cloud 实现的服务治理框架中,默认会创建针对各个服务治理框架的Ribbon 自动化整合配置,比如Eureka 中的org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,Consul中的org.springframework.cloud.consul.discovery.RibbonConsulAuto- Configurationo 在实际使用的时候,我们可以通过查看这两个类的实现,以找到它们的配置详情来帮助我们更好地使用它。
通过SpringCloudRibbon 的封装,我们在微服务架构中使用客户端负载均衡调用非常简单,只需要如下两步:
1.服务提供者只需要启动多个服务实例并注册到一个注册中心或是多个相关联的服务注册中心。
2. 服务消费者直接通过调用被@LoadBalanced 注解修饰过的RestTemplate来实现面向服务的接口调用。
这样,我们就可以将服务提供者的高可用以及服务消费者的负载均衡调用一起实现了。 其中,我们使用了个非常有用的对象RestTemplate.该对象会使用Ribbon 的自动化配置,同时通过配置@LoadBalanced 还能够开启客户端负载均衡。之前我们演示了通过RestTemplate实现了最简单的服务访问,下面我们将详细介绍RestTemplate 针对几种不同请求类型和参数类型的服务调用实现。
GET 请求
在RestTemplate 中,对GET 请求可以通过如下两个方法进行调用实现。 第一种: getForEntity 函数。该方法返回的是ResponseEntity,该对象是Spring对HTTP 请求响应的封装,其中主要存储了HTTP 的几个重要元素,比如HTTP 请求状态马的枚举对象HttpStatus (也就是我们常说的404、500 这些错误码)、在它的父类ittpEntity中还存储着HTTP请求的头信息对象HttpHeaders 以及泛型类型的请求体时象。比如下面的例子,就是访问USER-SERVER服务的/user 请求,同时最后一个参数idi 会替换url 中的(1}占位符,而返回的ResponseEntity 对象中的body 内容类型:根据第二个参数转换为String类型。
RestTemplate restTemplate 二newRestTemplate () ;
ResponseEntityStri xesponseEntity 一restTemplate.getFor ("http: //USER-RVICE/user?name={1}",string.class,"didi") ;
String body= responseEntity.getBody () ;
若我们希望返回的body是一个User对象类型,也可以这样实现:
Restremplate restTemplate= new Restremplate() ;
ResponseEntity responseEntity -restremplate.get "http: /USER- vICE/user?name={1}",User.class,"didi") ;
user body= responseEntity.getBody () ;
上面的例子是比较常用的方法
POST 请求
在RestTemplate 中,
对POST 请求时可以通过如下三个方法进行调用实现。
第一种: postEorEntity 函数。该方法同GET 请求中的getrorEntity 类似,会
在调用后返回ResponseEntity对象,其中T 为请求响应的body 类型。
比如下面这
个例子,使用postForEntity 提交POST请求到USER-SERVICE 服务的/user 接口,
提交的body 内容为user对象,请求响应返回的body 类型为String。
RestTemplate restTemplate= new RestTemplate () ;
User user = new User ("didi",30) ;
ResponseEntity responseEntity=
restTemplate.postForEntity ("http: //USER-SERVICE/user",user,String.class) ;
String body= responseEntity.getBody () ;
postForEntity 函数也实现了三种不同的重载方法。
PUT 请求
GResTemplate中,对PUT请求可以通过pot 方法进行调用实现,比如,
RestTemplaterestTemplate=new RestTemplate();
Long id = 100011;
User user=new User("didi",40);
restemplate.put(http://USER-SERVICE/user/{1} ”,user,id ;
put 函数也实现了三种不同的重载方法:
1.put (string url,Object request,0bject...urlVariables)
2.put (Stringurl,Object request,Map urlVariables)
3.put (URI url,object request )
put函数为void类型,所以没有返回内容,也就没有其他函数定义的responserype参数,除此之外的其他传入参数定义与用法与postforobject基本一致。
DELETE 请求
在RestTemplate 中,对DELETE 请求可以通过delete 方法进行调用实现,比如:
RestTemplate restTemplate = new RestTemplate () ;
Long id = 10001L;restTemplate.delete ("http: //USER-SERVICE/user/ (1}",id) ;
delete 函数也实现了三种不同的重载方法:
1.delete (String url,0bject...urlVariables)
2.delete (String url,Map urlVariables)
3.delete (URi url)由于我们在进行REST请求时,通常都将DELETE 请求的唯一标识拼接在url 中,所DELETE 请求也不需要equest 的body信息,就如上面的三个函数实现一样,非常简单。1指定DELETE 请求的位置,urlVariables 绑定url 中的参数即可。
想学习更多更详细的知识的,在此我向大家推荐一个交流学习群:744642380 里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多