1. 什么是 Ribbon?
Spring Cloud Ribbon 是一套实现客户端负载均衡的工具。注意是客户端,当然也有服务端的负载均衡工具,我们后面再介绍。可以认为 Ribbon 就是一个负载均衡器(Load Balancer,简称LB,即:low比~~)。负载均衡就是将用户的请求平摊的分配到多个服务上,从而达到系统的高可用。
简单来说,Ribbon 的主要功能是提供客户端的软件负载均衡算法,将 Netflix 的中间层服务连接在一起。Ribbon 客户端组件给我们提供了一套很完善的配置项,比如可以配置连接超时、重试等等。
再说的通俗一点,就是可以在配置文件中列出 LB 后面所有的机器(即服务),Ribbon 会自动根据某种规则(如轮询、随机等等)去连接这些机器(即服务),我们也可以自定义一些负载均衡算法。
再简单点,Ribbon 就是一个类库,集成在服务消费方,消费方从服务注册中心获知有哪些地址(即服务)可用,然后消费方通过 Ribbon 从这些地址当中选择一个合适的服务器来消费服务。
2. Ribbon 的使用
我们在前面文章中,将订单服务注册到 Eureka,然后消费方可以通过 http 请求去获取订单的信息,但是这是最原始的 http 调用,没有任何 Ribbon 的东西在里面,接下来我们要在消费方植入 Ribbon。
2.1 导入 Ribbon 依赖
我们使用的Spring Cloud 版本是 Finchley,该版本需要导入的依赖如下:
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-netflix-ribbon
可以看到,Eureka Client 的依赖也需要导入,因为服务注册到了 Eureka,Ribbon 也需要和 Eureka 整合,所以在消费方也导入了 Eureka 依赖。
2.2 配置 application.yml
server:
port: 9001
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka01:7001/eureka/,http://eureka02:7002/eureka/,http://eureka
我们搭建了一个 Eureka 集群,那么就用这个集群,这个消费方我们设置不注册到该集群中。
2.3 向 http 中植入 Ribbon
这是什么意思呢?之前的 消费方是使用 RestTemplate 来发送 http 请求,调用订单服务的,但是没有负载均衡,所以现在我们要让这个 http 调用自带负载均衡。
即修改下 RestTemplate 配置:
/**
* 配置RestTemplate
* @author shengwu ni
*/
@Configuration
public class RestTemplateConfig {
/**
* '@LoadBalanced'注解表示使用Ribbon实现客户端负载均衡
* @return RestTemplate
*/
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
在方法上添加一个 @LoadBalanced 注解即可开启 Ribbon 负载均衡。这样就可以通过微服务的名字从 Eureka 中找到对应的服务并访问了。
友情提示:别忘了在主启动类上添加 @EnableEurekaClient,因为这个消费方也是一个 Eureka Client,刚刚我们已经导入了 Eureka Client 的依赖了。
2.4 将ip改成服务名称
刚刚提到了,开启 Ribbon 负载均衡后,就可以通过微服务的名字从 Eureka 中找到对应的服务。我们先来看下原来是怎么实现的。
/**
* 订单消费服务
* @author shengwu ni
*/
@RestController
@RequestMapping("/consumer/order")
public class OrderConsumerController {
/**
* 订单服务提供者模块的 url 前缀
*/
// private static final String ORDER_PROVIDER_URL_PREFIX = "http://localhost:8001";
private static final String ORDER_PROVIDER_URL_PREFIX = "http://MICROSERVICE-ORDER";
@Resource
private RestTemplate restTemplate;
@GetMapping("/get/{id}")
public TOrder getOrder(@PathVariable Long id) {
return restTemplate.getForObject(ORDER_PROVIDER_URL_PREFIX + "/provider/order/get/" + id, TOrder.class);
}
}
可以看出,注释掉的那部分,是原来的访问方式,订单提供服务是8001端口,现在我们将ip+端口号这种访问方式,改成微服务名称,这个名称就是 Eureka 管理界面显示的注册进去的名称,也即服务提供方的application.yml配置文件中配置的服务名称:
spring:
application:
name: microservice-order # 对外暴露的服务名称
2.5 启动服务,测试
分别启动 eureka7001、eureka7002、eureka7003以及订单服务8001,可以看到订单服务已经注册到 Eureka 集群。
{"id":1,"name":"跟社会一起学 Spring Boot","price":39.99,"dbSource":"microservice01"}
说明,我们通过订单的服务名称即可获取订单信息了。可能到这里,读者还不明白我整了一大波,到最后就为了通过服务名称去获取服务提供的信息吗?
是的,这只是第一步,因为在很多微服务中,你不可能去通过每个 ip 和端口号来找对应的服务,更何况,还有 Ribbon 负载均衡还没上场呢?同一个微服务名称,可以有多个服务,而 Ribbon 只需要通过服务名去获取服务信息,至于获取到的是哪一个?就看具体的负载均衡策略了,目前测试的 MICROSERVICE-ORDER 服务就一个提供者,所以不能体现出负载均衡。由于篇幅原因,下篇文章继续。