5-1. Spring Cloud 中的Ribbon是什么?
我们通常说的负载均衡是将一个请求均匀分摊到不同的节点单元上执行,负责均衡分为硬件负载均衡和软件负载均衡
- 硬件负载均衡: 比如F5、深信服、Array等。
- 软件负载均衡: 比如 Nginx,LVS、HAProxy等。
硬件负载均衡或者软件负载均衡,他们都会维持一个可用的服务端清单,通过心跳检测来剔除故障的服务端节点以保证清单中都是可以正产访问的服务端节点。当客户端发送请求到负载均衡设备的时候,该设备按照某种算法(比如:轮询、权重、最小连接数等)从维护的可用服务器清单中取出一台服务器的地址,然后进行转发。、
Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,是一个基于HTTP和TCP的客户端负载均衡工具。 Spring Cloud 对Ribbon进行了二次封装,可以让我们使用RestTemplate的服务请求,自动转换成客户端负载均衡的服务调用。
Ribbon支持多种负载均衡算法,还支持自定义的负载均衡算法。
Ribbon只是一个工具类框架,比较小巧,Spring Cloud对它封装后使用也非常方便,它不像注册中心、配置中心、API网关那样需要独立部署,Ribbon只需要在代码直接使用即可。
Ribbon与Nginx的区别?
Ribbon是客户端的负载均衡工具,而客户端的负载均衡和服务端的负载均衡最大的区别在于服务清单所存储的位置不同,在客户端的负载均衡中,所有客户端节点下的服务端清单,需要自己从服务注册中心上去获取,比如Eureka服务注册中心。同服务端负载均衡的架构类似,在客户端负载均衡中也需要心跳去维护服务端清单的健康性,只是这个步骤需要与服务中心配合完成。在Spring Cloud中,由于Spring Cloud 对Ribbon进行了二次封装,所以默认会创建针对Ribbon的自动化整合配置。
在Spring Cloud中,Ribbon主要与RestTemplate对象配合起来使用,Ribbon会自动化配置RestTemplate对象,通过@LoadBalanced注解开启RestTemplate对象调用过的负载均衡。
5-2. Ribbon实现客户端负载均衡
由于Spring Cloud Ribbon的封装,我们在微服务架构中使用客户端负载均衡调用非常简单,只需要以下两步:
- 启动多个服务提供者实例并且将实例注册到服务中心上或者服务中心集群上
- 服务消费者通过被@LoadBalanced注解修饰过的RestTemplate来调用服务提供者提供的服务。
这样我们就可以实现服务提供者的高可用以及服务消费者的负载均衡调用。
5-3.Ribbon的负载均衡策略
Ribbon的负载均衡策略是由IRule接口定义,该接口实现如下:
策略类 | 命名 | 描述 |
---|---|---|
RandomRule | 随机策略 | 随机选择server |
RoundRobinRule | 轮询策略 | 按照顺序选择server(ribbon默认策略) |
RetryRule | 重试策略 | 先按照轮询策略分发。在一个配置时间段内,当选择server不成功,则一直尝试选择一个可用的server |
BestAvailableRule | 最低并发策略 | 逐个考察server,如果server断路器打开,则忽略,再选择其中并发链接最低的server |
AvailabilityFilteringRule | 可用过滤策略 | 过滤掉一直失败并被标记为circuit tripped的server,过滤掉那些高并发链接的server(active connections超过配置的阈值),剩下的服务按照轮询策略进行访问 |
ResponseTimeWeightedRule | 响应时间加权重策略 | 根据server的响应时间分配权重,响应时间越长,权重越低,被选择到的概率也就越低。响应时间越短,权重越高,被选中的概率越高,这个策略很贴切,综合了各种因素,比如:网络,磁盘,io等,都直接影响响应时间 |
ZoneAvoidanceRule | 区域权重策略 | 综合判断server所在区域的性能,和server的可用性,轮询选择server并且判断一个AWS Zone的运行性能是否可用,剔除不可用的Zone中的所有server |
如果想要创建一个全局的负载策略,只需添加一个配置类,也可自己扩展,添加逻辑,如下:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
@Configuration
public class RibbonConfiguration {
@Bean
public IRule ribbonRule() {
return new RandomRule();
}
}
5-4. Rest请求模板类解读
当我们从服务端去调用服务提供者服务的时候,使用了一个极其方便的对象RestTemplate,在日常操作中基于Rest的方式的请求方式通常为四种情况:
- GET请求 --查询数据
- POST请求 – 添加数据
- PUT请求 --修改数据
- DELETE请求 --删除数据
5-5. RestTemplate的GET请求 两种方式
- getForEntity: 该方法返回一个ResponseEntity对象,ResponseEntity是Spring对HTTP请求响应的封装,包括了几个重要的因素,比如响应码、contentType、contentLength、响应消息体等。
ResponseEntity<String>responseEntity=restTemplate.getForEntity("http://服务名称/service/hello",String.class);
-
以上方法getForEntity第一个参数为调用服务的地址,即服务提供者提供的接口地址,注意这里是通过服务名称调用而不是服务地址,如果改为服务地址就无法使用Ribbon实现负载均衡了。
-
getForEntity的第二个参数为String.class,表示希望返回的body类型为String类型,如果我们希望返回一个对象也是可以的,比如user对象。
另外两个重载方法
// 第一种 调用有参方法时 可以用数组传参
String [] strArray={"102","张三","13700000000"}
ResponseEntity<String>responseEntity=restTemplate.getForEntity("http://服务名称/service/getUser?id={0}&name={1}&phone={2}",String.class,strArray).getBody();
// 第二种 调用有参服务方法时 也可以用Map传参
Map<String,Object>paramMap = new ConcurrentHashMap<>();
paramMap.put("id",103);
paramMap.put("name","lis");
paramMap.put("phone","13800000000");
restTemplate.getForEntity("http://服务名称/service/getUser?id={id}&name={name}&phone={phone}",String.class,paramMap).getBody();
-
getForObject():与getForEntity使用类似,只不过getForObjet是在getForEntity基础上进行了再次封装,可以将http的响应体Body信息转化为指定的对象,方便我们的代码开发。
当你不需要返回响应中的其它信息时,只需要body体信息的时候,可以使用它更方便,它也有两个重载方法
5-6. RestTemplate的POST请求
Post与Get非常类似
restTemplate.postForObject();
restTemplate.postForEntity();
restTemplate.postForLocation();
注意:传参数使用 : MultiValueMap<String,Object> dataMap= new LinkedMultiValueMap<~>();
5-7. RestTemplate的PUT请求
restTemplate.put);
5-8. RestTemplate的DELETE请求
restTemplate.delete);