Ribbon简介
Ribbon是Netflix的组件之一,负责注册中心的负载均衡,有助于控制HTTP和TCP客户端行为。Spring Cloud Netflix Ribbon一般配合Ribbon进行使用,利用在Eureka中读取的服务信息,在调用服务节点时合理进行负载。
SpringCloud中可以将注册中心和Ribbon配合使用,Ribbon自动的从注册中心获取提供者的列表信息,并基于内置的负载均衡算法,请求服务。
基于Spring Cloud Netflix Ribbon 实现负载均衡的结构图如图 4-1 所示,可以看到各个微服务实例会和Ribbon 服务一样注册到 Eureka 服务器 然后 Ribbon从 Eur eka 服务器中获取所有注册服务的服务列表 ,一旦获取服务列衰, Ribbon就能通过各种负载均衡策略实现服务调用。
根据服务列表的获取和存储方式,负载均衡可以分为客户端负载均衡和服务器端负载均衡两种形式 上图中展示的是一种客户端负均衡机制。 Ribbon 作为一种独立的客户端负载均衡实现工具,一方面可以通过 Eureka 完成负载均衡,另一方面它也支持直接访问服务列表。
服务端负载均衡
图 4-3 展示了服务器端负载均衡机制示意图,首先客户端发送请求到负载均衡器,然后这台负载均衡器负责将接收到的各个请求转发到运行中的某个微服务节点上,最后接收到请求的微服务节点做响应处理。基于服务器端的负载均衡机制实现比较简单 只需要在客户端与各 微服务实例之间架设集中式的负载均衡器即可。为当服务请求 越来越大肘 负载均衡器将会成为系统的瓶颈,为了避免集中式负载均衡所带来的这种问题,客户端负载均衡同样也是一种常用的方式。
客户端负载均衡
客户端负载均衡机制的主要优势在于不会出现集中式负载均衡所产生的瓶颈问题,因为每个客户端都有自己的负载均衡器。客户端负载均衡就是在客户端程序内部设定一个调度算法,在向服务器发起请求时,先执行调度算法计算出目标服务器地址,再调用目标地址服务。
客户端负载均衡是常见的负载均衡实现方案 包括Dubbo 、SpringCloud 在内的很多框架采用的都是客户端负载均衡机制。
Ribbon 主要有以下 大子模块。
ribbon-core
:该模块为 Ribbon 项目的核心,主要包括负载均衡器接口定义、 客户端、接口定义、内置的负载均衡实现等 API。ribbon-eureka
:为 Eureka 客户端提供的负载均衡实现类。ribbon-httpclient
:对 Apache HttpClient 进行封装,该模块提供了 有负载均衡功,能的阻ST 客户。
Ribbon的主要作用
- 服务调用
基于Ribbon实现服务调用,是通过拉取到的所有服务列表组成的映射关系,借助RestTemplate
进行最终的调用。
- 负载均衡
当多个服务提供者时,Ribbon可以根据负载均衡算法自动选择需要调用的地址。
Ribbon 的负载均衡器主要与集群中的各个服务器进行通信,负载均衡器 要提供以下基础功能:
- 维护服务器的 IP,DNS ,名称等信息
- 根据特定的逻辑在服务器列表中循环。
为了实现负载均衡的基础功能, Ribbon 的负载均衡器有以下 大子模块。- Rule 个逻辑组件,这些逻辑将会决定从服务器列表中返回哪个服务器实例
- Ping :该组件主要使用定时器来确保服务器网络可以连接。
- ServerList :服务器列表,可以通过静态的配置确定负载的服务器, 可以动态指定
服务器列表。 如果动态指定服务器列表, 会有后台的线程来刷新该列表
Ribbon 实现客户端负载均衡
Netflix Ribbon 会自动地基于某种负载均衡算法(如随机、轮询等)去连接服务实例。Spring Cloud Netflix Ribbon Netfl bbon 做了封装以便更好地使用 Spring Boot 的自动配置理念即spring cloud集成了Ribbon。通过Sping Cloud Netflix Ribbon 大大简化了在微服务架构中使用客户端负载均衡的成本,通过
注解就能简单实现在面向服务的接口调用中自动集成负载均衡功能。
接上一节,构建完eureka多注册中心后,再使用Ribbon完成负载均衡功能,由于Ribbon是基于客户端的负载均衡,因此只需要修改客户端的代码和配置。如下是上一节的远程调用代码:
@RestController
@RequestMapping(value = "/test")
public class TestController {
//获取服务中心实例
@Autowired
private DiscoveryClient discoveryClient;
//java代码访问api接口的实例对象
@Autowired
private RestTemplate restTemplate;
//bill_service的调用
@GetMapping(value = "/bill/{id}")
public BillMessage testMethod1(@PathVariable Integer id){
List<ServiceInstance> bill_service = discoveryClient.getInstances("bill_service");
//该服务只有一个
ServiceInstance instance = bill_service.get(0);
BillMessage billMessage = restTemplate.getForObject(instance.getUri() + "/bill/" + id, BillMessage.class);
System.out.println(instance.getUri());
return billMessage;
}
}
多个服务通过服务id来获取实例,在分布式环境下会有同名称部署在不同服务器上的服务即名称相同但ip不同的服务,在具体调用哪个时都由Ribbon的负载均衡(负载均衡算法)来分配。
如何在客户端使用Ribbon ?
在创建并注入RestTemplate
对象时加入@LoadBalanced
注解:
@SpringBootApplication
@EnableEurekaClient
public class TestModuleApplication {
//java代码访问url获取返回值的对象
@LoadBalanced //spring cloud提供连接Ribbon的注解
@Bean
public RestTemplate getRestTemplate(){ return new RestTemplate(); }
public static void main(String[] args) {
SpringApplication.run(TestModuleApplication.class, args);
}
}
使用该注解会在客户端启动Ribbon,通过客户端Ribbon的负载均衡调度算法获取服务。
RestTemplate是spring-web项目的一个REST客户端,提供API去调用HTTP服务,其本身不具有负载均衡功能,也与Spring Cloud没有关系,为何加入了@LoadBalanced
就具有负载均衡功能呢?
在使用@LoadBalanced
注解后,spring容器在启动时会为被这些修饰的RestTemplate添加拦截器,并使用LoadBalancerClient
处理请求,该类本身具有负载均衡的客户端,通过间接处理使RestTemplate具有了负载均衡的功能。
如何引入依赖 ?
Spring Cloud项目集成Ribbon,需要导入依赖:
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>...</version>
</dependency>
如果之前以及引入了eureka
的依赖就不需要再导入ribbon
的依赖了,因为前者已经集成了后者。
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>...</version>
</dependency>
在之前的api接口处获取的服务实例是通过注册中心获取的,没有使用Ribbon的负载均衡功能:
//bill_service的调用
@GetMapping(value = "/bill/{id}")
public BillMessage testMethod1(@PathVariable Integer id){
List<ServiceInstance> bill_service = discoveryClient.getInstances("bill_service");
//该服务只有一个
ServiceInstance instance = bill_service.get(0);
BillMessage billMessage = restTemplate.getForObject(instance.getUri() + "/bill/" + id, BillMessage.class);
System.out.println(instance.getUri());
return billMessage;
}
}
使用Ribbon组件后就不需要再通过注册中心获取实例再获取IP地址等信息了,而是直接将Ribbon作为中间件,向Ribbon请求,由其负载均衡算法再从注册中心获取,那么新的接口也简洁了很多:
//使用Ribbon获取服务
@GetMapping(value = "/bill1/{id}")
public BillMessage testMethod2(@PathVariable Integer id){
BillMessage billMessage = restTemplate.getForObject("http://bill-service/bill/"+id,BillMessage.class);
return billMessage;
}
启动服务:
在中途遇到了一个小错误就是使用在使用Ribbon实现负载均衡的时候,服务名称不能用下划线改为中划线或其他,不然就会报错:
Request URI does not contain a valid hostname: http://bill_service/1
全部改为中划线类型的服务名称:
需要注意的地方就是服务路径的拼接了:
BillMessage billMessage = restTemplate.getForObject("http://bill-service/bill/"+id,BillMessage.class);
使用Ribbon插件只需通过服务名(bill-service)
就可以获取该服务的ip信息,在加上url
地址就可以调用其服务了。
负载均衡策略
负载均衡的策略也可以通过配置文件修改,当然spring 也提供了@RibbonClient注解来自定义负载均衡,
SpringCloud重试机制配置
SpringCloud重试retry是一个很赞的功能,能够有效的处理单点故障的问题。主要功能是当请求一个服务的某个实例时,譬如你的User服务启动了2个,它们都在eureka里注册了,那么正常情况下当请求User服务时,ribbon默认会轮询这两个实例。此时如果其中一个实例故障了,发生了宕机或者超时等,如果没有配置启用重试retry策略,那么调用方就会得到错误信息或者超时无响应或者是熔断返回的信息。我们希望的自然是一个故障了,会自动切换到另一个去访问。最简单的方法就是retry。
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
重试机制在ribbon的配置
@Bean
@LoadBalanced
RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpRequestFactory.setReadTimeout(5000);
httpRequestFactory.setConnectTimeout(5000);
return new RestTemplate(httpRequestFactory);
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/156252.html