前言:
Spring Cloud系列教程的所有博客均在下方的目录链接中,方便大家查找和阅读。建议按照顺序学习,对于项目搭建有疑问的可以着重看目录里的第二篇博客。
Spring cloud学习专栏目录
一、Ribbon简介
Ribbon是Netflix发布的云中间层服务开源项目,其主要功能是提供客户端侧负载均衡算法。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,Ribbon是一个客户端负载均衡器,我们可以在配置文件中列出Load Balancer后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器,我们也很容易使用Ribbon实现自定义的负载均衡算法。
下图展示了Eureka使用Ribbon时候的大致架构:
Ribbon工作时分为两步:第一步先选择 Eureka Server, 它优先选择在同一个Zone且负载较少的Server;第二步再根据用户指定的策略,在从Server取到的服务注册列表中选择一个地址。其中Ribbon提供了多种策略,例如轮询round robin、随机Random、根据响应时间加权等。
二、利用Ribbon解决车票微服务中的硬编码问题
问题回顾
之前我们在TicketService中的 url是写死的,而我们现在已经会使用Eureka了,在配合上ribbon就可以去eureka中查询服务地址了。
2.1 修改车票微服务启动类,添加负载均衡的注解
打开车票微服务的pom文件,可以看到eureka的依赖中整合了ribbon,所以我们就不需要单独去添加ribbon的依赖。
———————————————————————————————————
在RestTemplate上添加@LoadBalance注解,这样restTemplate就具备了负载均衡的能力。
@SpringBootApplication
@EnableEurekaClient
public class TicketServiceApplication {
public static void main(String[] args) {
SpringApplication.run(TicketServiceApplication.class, args);
}
/*
* 向Spring容器中添加RestTemplate对象
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
2.2 修改service中的方法实现
2.2.1 将地址和端口用我们之前在用户微服务的application.properties中设置的服务名称替换
@Service
public class TicketService {
@Autowired
private RestTemplate restTemplate;
/*
* 查询车票信息时查询用户的信息(这里为了简化操作就不对车票信息进行查询,直接去调用查询用户信息的接口)
*/
public User queryTicketInfo(Long id) {
//向用户微服务中的接口发送请求的地址
//String url = "http://localhost:8081/getUserInfo/"+ id;
String url = "http://microservice-provide-user/getUserInfo/"+ id;
return restTemplate.getForObject(url, User.class);
}
}
2.2.2 启动服务进行测试
将eureka服务,用户微服务以及车票微服务进行启动。
访问车票微服务中的接口地址 http://localhost:8082/getTicketInfo/1,可以看到成功查询出了用户信息,说明硬编码问题得到了解决
三、测试负载均衡
通过刚才的测试我们可以知道,硬编码问题已经得到了解决,车票微服务成功请求到了用户微服务。但要测试负载均衡我们就需要启动多个服务提供者也就是用户微服务来进行测试。
3.1 启动两个用户微服务
3.1.1 修改车票微服务中的service方法
按下图添加代码,打印出端口信息主要是为了方便我们查看负载均衡的情况。
@Service
public class TicketService {
@Autowired
private RestTemplate restTemplate;
@Autowired
private LoadBalancerClient loadBalancerClient;
/*
* 查询车票信息时查询用户的信息(这里为了简化操作就不对车票信息进行查询,直接去调用查询用户信息的接口)
*/
public User queryTicketInfo(Long id) {
String serviceId = "microservice-provide-user";
ServiceInstance serviceInstance = loadBalancerClient.choose(serviceId);
//打印出请求了哪个端口的用户微服务
System.out.println("请求了" + serviceInstance.getPort());
//向用户微服务中的接口发送请求的地址
//String url = "http://localhost:8081/getUserInfo/"+ id;
String url = "http://microservice-provide-user/getUserInfo/"+ id;
return restTemplate.getForObject(url, User.class);
}
}
3.1.2 启动微服务
将eureka服务,用户微服务以及车票微服务进行启动。第一个用户微服务启动好之后,对用户微服务的配置文件中的端口号进行修改。
# 配置api端口号
#server.port=8081
server.port=8090
# tomcat
server.tomcat.uri-encoding=UTF-8
# 服务名称,也就是在eureka
spring.application.name=microservice-provide-user
# 是否启动注册,这是一个客户端需要注册
eureka.client.register-with-eureka=true
# 是否检索服务
eureka.client.fetch-registry=true
# 服务注册中心的地址
eureka.client.service-url.default-zone=http://localhost:8761/eureka
改好之后我们再次启动用户微服务,启动好之后我们去eureka中查看。可以看到两个用户微服务以及启动好了,一个是8090端口一个是8081端口。
3.2 开始测试负载均衡
访问车票微服务的接口: http://localhost:8082/getTicketInfo/1
这里正常的情况应该是一个接口请求一次,但我这里总是只请求一个接口,不是默认的轮询规则。我之后通过自定义配置的方式发现随机规则是正常的但是轮询依旧不正常,所以这里我们先忽略这个问题,继续讲解自定义配置ribbon。
四、通过代码自定义ribbon的负载均衡规则
4.1 新建一个配置类TestConfiguration
注意这个类的放置的位置是有规则的,他不能放在@ComponentScan或者是@SpringBootApplication扫描的包里。这里的话@SpringBootApplication也就是我们启动类上的注解,他扫描的的是启动类所在的包已经它的子包。所以这里我们专门在启动类的外面建了一个包去放配置文件。
如果你一定要和启动类放在同级目录的话,就要通过一些注解和配置把该类,从扫描的列表中除去,我觉得相对来说有点麻烦这里就不做讲解。
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 TestConfiguration {
@Autowired
private IClientConfig config;
@Bean
public IRule ribbonRule(IClientConfig config) {
//自定义为随机规则,你也可以根据需要选择其他规则。只需要将RandomRule改成其他的规则即可
return new RandomRule();
}
}
4.2 在服务消费者车票微服务的启动类上添加注解
name就是用户微服务application.proerties中配置的spring.application.name
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
import com.spring.config.TestConfiguration;
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "microservice-provide-user",configuration = TestConfiguration.class)
public class TicketServiceApplication {
public static void main(String[] args) {
SpringApplication.run(TicketServiceApplication.class, args);
}
/*
* 向Spring容器中添加RestTemplate对象
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
4.3 重启车票微服务进行测试
访问车票微服务的接口: http://localhost:8082/getTicketInfo/1
可以看到8081和8090两个接口被随机访问,说明配置生效了
五、Ribbon 自带的负载均衡策略
这里简单列举几个:
BestAvailableRule 先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
RandomRule: 随机选择
RoundRobinRule: 轮询一个server一次
RetryRule: 先轮询,如果获取失败则在指定时间内重试,重新轮询可用的服务。
WeightedResponseTimeRule: 根据平均响应时间计算所有服务的权重,响应越快的服务权重越高,越容易被选中。一开始启动时,统计信息不足的情况下,使用轮询。
ZoneAvoidanceRule: 复合判断 server 所在区域的性能和 server 的可用性选择服务器