前面几篇文章主要介绍了 Spring Cloud 中的 Eureka 服务注册与发现,这一篇文章主要介绍一下 Spring Cloud Ribbon,什么是 Ribbon 呢?首先看一下 Ribbon 的相关介绍。
1. 什么是 Ribbon?
Spring Cloud Ribbon 是一套实现客户端负载均衡的工具。注意是客户端,当然也有服务端的负载均衡工具,我们后面再介绍。可以认为 Ribbon 就是一个负载均衡器(Load Balancer,简称LB,即:low比~~)。负载均衡就是将用户的请求平摊的分配到多个服务上,从而达到系统的高可用。
简单来说,Ribbon 的主要功能是提供客户端的软件负载均衡算法,将 Netflix 的中间层服务连接在一起。Ribbon 客户端组件给我们提供了一套很完善的配置项,比如可以配置连接超时、重试等等。
再说的通俗一点,就是可以在配置文件中列出 LB 后面所有的机器(即服务),Ribbon 会自动根据某种规则(如轮询、随机等等)去连接这些机器(即服务),我们也可以自定义一些负载均衡算法。
再简单点,Ribbon 就是一个类库,集成在服务消费方,消费方从服务注册中心获知有哪些地址(即服务)可用,然后消费方通过 Ribbon 从这些地址当中选择一个合适的服务器来消费服务。
更多资料可以观看官方GitHub:https://github.com/Netflix/ribbon
2. Ribbon 的使用
我们在前面文章中,将订单服务注册到 Eureka,然后消费方可以通过 http 请求去获取订单的信息,但是这是最原始的 http 调用,没有任何 Ribbon 的东西在里面,接下来我们要在消费方植入 Ribbon。
2.1 导入 Ribbon 依赖
我们使用的Spring Cloud 版本是 Finchley,该版本需要导入的依赖如下:
<!--eureka Client--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--ribbon负载均衡依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency>
可以看到,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://eureka03:7003/eureka/
由前面的内容(Spring Cloud:使用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 集群。
然后启动消费方服务,然后在浏览器输入 http://localhost:9001/consumer/order/get/1 即可查询到对应的订单服务:
{"id":1,"name":"跟武哥一起学 Spring Boot","price":39.99,"dbSource":"microservice01"}
说明,我们通过订单的服务名称即可获取订单信息了。可能到这里,读者还不明白我整了一大波,到最后就为了通过服务名称去获取服务提供的信息吗?
是的,这只是第一步,因为在很多微服务中,你不可能去通过每个 ip 和端口号来找对应的服务,更何况,还有 Ribbon 负载均衡还没上场呢?同一个微服务名称,可以有多个服务,而 Ribbon 只需要通过服务名去获取服务信息,至于获取到的是哪一个?就看具体的负载均衡策略了,目前测试的 MICROSERVICE-ORDER 服务就一个提供者,所以不能体现出负载均衡。由于篇幅原因,下篇文章继续。