五、Ribbon客户端负载均衡
1、基本概念
为什么要使用Ribbon:为防止应用出现单节点故障,为服务集群得时候,会出现一个服务在注册中心有两个通讯地址,当我们在调用这个服务得时候应该如何选择,这时候我们就要用到 Ribbon,也就是负载均衡器,他的功能就是帮助我们做请求得转发。Ribbon可以按照负载均衡算法(如简单轮询,随机连接等)向多个服务发起调用(正好可以解决访问集群服务的问题),我们也很容易使用Ribbon实现自定义的负载均衡算法。Ribbon客户端组件提供一系列完善的配置项,如,连接超时,重试等。
2、调用关系
如上图,我们会对用户服务做一个集群,然后通过订单服务端得Ribbon通过一个轮询得方式对用户服务发起一个http请求得调用
3、用户服务集群配置
我们使用SpringBoot多环境配置方式集群,一个配置文件配置多个user-server环境 ,注意的是集群中的多个服务名(spring.application.name)应该一样,我们把相同的东西提取到最上面,不同的配置用分割线---
区分开来。
#注册到EurekaServer
eureka:
client:
serviceUrl:
defaultZone: http://localhost:1010/eureka/
instance:
prefer-ip-address: true #使用ip地址进行注册
spring:
application:
name: user-server #服务名都是相同的
profiles:
active: user-server1
---
server:
port: 1020
eureka:
instance:
instance-id: user-server:1020 #实例ID
spring:
profiles: user-server1
---
eureka:
instance:
instance-id: user-server:1021 #实例ID
spring:
profiles: user-server2
server:
port: 1021
为了后期测试能够更加直观的看到测试结果,我们对User的controller进行改造,在读取到访问的接口时,随user返回到页面中
@RestController
public class UserController {
//为了看到ribbon得效果,我们可以将集群配置中得端口取出来进行对比,@Value读取配置文件中的信息
@Value("${server.port}")
private int port;
@GetMapping("user/{id}")
public UserTo getUserById(@PathVariable("id") Long id) {
return new UserTo(id, "张三", "这是测试得内容"+port);
}
}
4、消费者Order-server集成Ribbon
Ribbon集成官方文档:https://cloud.spring.io/spring-cloud-static/Greenwich.SR5/multi/multi_spring-cloud-ribbon.html#netflix-ribbon-starter
首先导入Ribbon的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
开启负载均衡功能,需要修改RestTemplate的Bean的定义方法,加上Ribbon的负载均衡注解@LoadBalanced赋予RestTemplate有负债均衡的能力。
//手动配置一个RestTemplate,Spring封装的一个基于Restful风格的http客户端工具,交给spring进行管理
//@LoadBalanced使得RestTemplate具备负载均衡得能力
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
修改Order中的controller,之前我们用的url是通过IP进行访问的,现在我们通过服务名进行访问,要注意的时服务名必须正确,可以通过注册中心中显示的服务名直接进行拷贝,较为保险
@GetMapping("order/{id}")
public UserTo getUserToById(@PathVariable("id")Long id) {
//目标得资源路径,是调用得user服务中controller得路径
//String url = "http://localhost:1020/user/" + id;
//使用ribbon后,需要通过服务名进行调用,而不是ip
String url = "http://user-server:1020/user/" + id;
//发送http请求
return restTemplate.getForObject(url, UserTo.class);
}
5、测试结果
可以看的出来,虽然调用的是同一个方法,但是打印出来的后面的端口是在变的,会交替出现1020、1021,此处Ribbon默认的方式为轮询