这是我参与「掘金日新计划 · 6 月更文挑战」的第23天 ,点击查看活动详情
\
一、Ribbon
1、基本概念
Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。Spring Cloud Ribbon虽然只是一个工具类框架,它不像服务注册中心、配置中心、API网关那样需要独立部署,但是它几乎存在于每一个Spring Cloud构建的微服务和基础设施中。因为微服务间的调用,API网关的请求转发等内容,实际上都是通过Ribbon来实现的,包括后续我们将要介绍的Feign,它也是基于Ribbon实现的工具。所以,对Spring Cloud Ribbon的理解和使用,对于我们使用Spring Cloud来构建微服务非常重要。
2、客户端负载均衡
负载均衡在系统架构中是一个非常重要,并且是不得不去实施的内容。因为负载均衡是对系统的高可用、网络压力的缓解和处理能力扩容的重要手段之一。我们通常所说的负载均衡都指的是服务端负载均衡,其中分为硬件负载均衡和软件负载均衡。硬件负载均衡主要通过在服务器节点之间按照专门用于负载均衡的设备,比如F5等;而软件负载均衡则是通过在服务器上安装一些用于负载均衡功能或模块等软件来完成请求分发工作,比如Nginx等。不论采用硬件负载均衡还是软件负载均衡,只要是服务端都能以类似下图的架构方式构建起来:
硬件负载均衡的设备或是软件负载均衡的软件模块都会维护一个可用的服务端清单,通过心跳检测来剔除故障的服务端节点,以保证清单中都是可以正常访问的服务端节点。当客户端发送请求到负载均衡设备的时候,该设备按某种算法(比如线性轮询、按权重负载、按流量负载等)从维护的可用服务端清单中取出一台服务端地址,然后进行转发。
而客户端负载均衡和服务端负载均衡最大的不同点在于上面所提到服务清单所存储的位置。在客户端负载均衡中,所有客户端节点都维护着自己要访问的服务端清单,而这些服务端端清单来自于服务注册中心,比如上一章我们介绍的Eureka服务端。同服务端负载均衡的架构类似,在客户端负载均衡中也需要心跳去维护服务端清单的健康性。
Ribbon默认会创建针对各个服务治理框架的自动化整合配置,比如
Eureka中的org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,
Consul中的org.springframework.cloud.consul.discovery.RibbonConsulAutoConfiguration。
在实际使用的时候,我们可以通过查看这两个类的实现,以找到它们的配置详情来帮助我们更好地使用它。\
二、实现服务调用
通过Spring Cloud Ribbon的封装,我们在微服务架构中使用客户端负载均衡调用非常简单,只需要如下两步:
-
服务提供者只需要启动多个服务实例并注册到一个注册中心或是多个相关联的服务注册中心。\
-
服务消费者直接通过调用被@LoadBalanced注解修饰过的RestTemplate来实现面向服务的接口调用。\
这样,我们就可以将服务提供者的高可用以及服务消费者的负载均衡调用一起实现了。
1、在调用端添加pom依赖
在statistics微服务中添加\
<!--服务调用/负载均衡-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
因为statistics服务的pom.xml中引入了eureka-client的依赖,eureka-client的依赖包含了ribbon的依赖所以这一步省略
2、创建配置文件
RibbonConfig.java
package com.guli.statistics.config;
@Configuration
public class RibbonConfig {
//负载均衡
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
3、调用微服务
在调用端的DailyService中使用 RestTemplate 给远程发送请求
接口
void createStatisticsByDay(String day);
实现
@Autowired
RestTemplate restTemplate;
@Transactional(rollbackFor = Exception.class)
@Override
public void createStatisticsByDay(String day) {
//如果当日的统计记录已存在,则删除重新统计|或 提示用户当日记录已存在
QueryWrapper<Daily> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("date_calculated", day);
baseMapper.delete(queryWrapper);
//生成统计记录
R r = restTemplate.getForObject("http://guli-ucenter/admin/ucenter/member/count-register/{day}", R.class, day);
Integer registerNum = (Integer) r.getData().get("countRegister");
Integer loginNum = RandomUtils.nextInt(100, 200); //TODO
Integer videoViewNum = RandomUtils.nextInt(100, 200); //TODO
Integer courseNum = RandomUtils.nextInt(100, 200); //TODO
Daily daily = new Daily();
daily.setRegisterNum(registerNum);
daily.setLoginNum(loginNum);
daily.setVideoViewNum(videoViewNum);
daily.setCourseNum(courseNum);
daily.setDateCalculated(day);
baseMapper.insert(daily);
}
5、controller
package com.guli.statistics.controller.admin;
@Api(description="统计分析管理")
@CrossOrigin
@RestController
@RequestMapping("/admin/statistics/daily")
public class DailyAdminController {
@Autowired
private DailyService dailyService;
@ApiOperation(value = "生成统计记录", notes = "生成统计记录")
@PostMapping("{day}")
public R createStatisticsByDate(
@ApiParam(name = "day", value = "统计日期")
@PathVariable String day) {
dailyService.createStatisticsByDay(day);
return R.ok();
}
}
6、Swagger测试
启动eureka、ucenter、statistics三个微服务
在swagger中测试
\
三、测试负载均衡
1、Ucenter中打印日志
MemberAdminController.java 中读取端口号
@Value("${server.port}")
private Integer port;
registerCount方法中打印日志
System.out.println("用户服务被调用:port=" + port);
2、启动Ucenter微服务
分别为三个服务分配8140、8141、8142端口
\
3、测试
默认会使用负载均衡轮询方式访问
扩展阅读:Ribbo负载均衡策略及原理:blog.csdn.net/wudiyong22/…
\
负载均衡策略配置: