今天,我们就使用 Sentinel 实现接口的限流,并使用 Feign 整合 Sentinel 实现服务容错的功能,让我们体验下微服务使用了服务容错功能的效果。
因为内容仅仅围绕着 SpringCloud Alibaba技术栈展开,所以,这里我们使用的服务容错组件是阿里开源的 Sentinel。
当然,能够实现服务容错功能的组件不仅仅有 Sentinel,比如:Hystrix 和 Resilience4J 也能够实现服务容错的目的。
1. 关于 Sentinel
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性
1.1 Sentinel 的特征
- 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
- 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
- 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 SpringCloud、Apache Dubbo、gRPC、Quarkus 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。同时 Sentinel 提供 Java/Go/C++ 等多语言的原生实现。
- 完善的 SPI 扩展机制:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等
1.2 Sentinel 的主要特性
Sentinel 分为两个部分:
- 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo /Spring Cloud 等框架也有较好的支持。
- 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器
2. 项目集成 Sentinel
在微服务项目中整合 Sentinel 是非常简单的,只需要在项目的 pom.xml 文件中引入 Sentinel 的依赖即可。不过在使用 Sentinel 时,需要安装 Sentinel 的控制台
2.1 安装 Sentinel 控制台
Sentinel 提供一个轻量级的控制台, 它提供机器发现、单机资源实时监控以及规则管理等功能
2.1.1 下载 sentinel-dashboard
到链接 下载链接 下载 Sentinel 控制台。我这里下载的是 sentinel-dashboard-1.8.5.jar
2.1.2 启动 sentinel-dashboard
Sentinel 控制台下载完成后,在本地启动 Sentinel 控制台,如下所示:
java -Dserver.port=8888 -Dcsp.sentinel.dashboard.server=localhost:8888 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.5.jar
2.1.3 访问 sentinel-dashboard
启动后在浏览器中输入 http://localhost:8888
访问 Sentinel 控制台,如下所示:
输入默认的用户名 sentinel 和密码 sentinel,登录 Sentinel 控制台,如下所示:
至此,Sentinel 控制台下载并启动成功
2.2 项目集成 Sentinel
1、在订单微服务的 shop-orde r的 pom.xml 文件中添加Sentinel的相关依赖,如下所示
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2、在订单微服务的 shop-order 的 application.yml 文中加入 Sentinel 相关的配置,如下所示:
spring:
cloud:
sentinel:
transport:
port: 9999 #指定和Sentinel控制台交互的端口,任意指定一个未使用的端口即可
dashboard: 127.0.0.1:8888 #Sentinel控制台服务地址
3、为了让大家直观的感受到 Sentinel 的功能,这里我们先在订单微服务的 OrderController 类中新增一个测试接口,如下所示:
@GetMapping(value = "/test_sentinel")
public String testSentinel(){
log.info("测试Sentinel");
return "sentinel";
}
4、启动订单微服务,在浏览器中输入 http://localhost:8080/order/test_sentinel
访问在订单微服务中新增的接口。
5、刷新 Sentinel 页面,会发现已经显示了订单微服务的菜单,如下所示:
这里注意一下:
注意:直接启动订单微服务和 Sentinel,会发现 Sentinel 中没有订单微服务的数据,因为 Sentinel 是懒加载机制,所以需要访问一下接口,再去访问Sentinel 就有数据了
至此,订单微服务成功集成了 Sentinel
2.3 集成 Sentinel 限流功能
对提交订单的接口限流
在提交订单的接口 http://localhost:8080/order/submit_order
上实现限流,步骤如下:
1、首先访问下提交订单的接口 http://localhost:8080/order/submit_order
,使得 Sentinel 中能够捕获到提交订单的接口,并点击操作中的 流控 按钮,如下所示:
2、在新增流控规则显示框中的 QPS 单机阈值设置为 1,点击新增按钮,如下所示:
3、在浏览器中不断刷新 http://localhost:8080/order/submit_order? userId=1001&productId=1001&count=1
使得每秒访问的频率超过 1 次,会被 Sentinel 限流,如下所示:
至此,项目中集成了 Sentinel 并使用 Sentinel 实现了接口的限流。
3. Feign 整合 Sentinel 实现容错
我们之前在项目中集成了 Sentinel,并使用Sentinel实现了限流,如果订单微服务的下游服务,比如用户微服务和商品微服务出现故障,无法访问时,那订单微服务该如何实现服务容错呢?使用Sentinel就可以轻松实现
3.1 添加依赖并开启支持
1、在订单微服务的 shop-order 的 pom.xml 文件中添加 Sentinel 的相关依赖,如下所示:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2、在订单微服务的 application.yml 文件中添加如下配置开启 Feign 对 Sentinel 的支持:
feign:
sentinel:
enabled: true
3.2 为远程调用实现容错
需要在订单微服务 shop-order 中,为远程调用接口实现容错方法。
1、这里,先为用户微服务实现容错。在订单微服务中新建 com.zzc.order.feign.fallback
包,并在此包下创建 UserServiceFallBack
类实现 UserService 接口,用于调用用户微服务的容错类,如下所示:
@Component
public class UserServiceFallBack implements UserService {
@Override
public User getUser(Long uid) {
User user = new User();
user.setId(-1L);
return user;
}
}
注意:
容错类需要实现一个被容错的接口,并实现这个接口的方法
2、指定容错类。,在订单微服务的 com.zzc.order.feign.UserService
接口上的 @FeignClient
注解上指定容错类,如下所示:
@FeignClient(value = "server-user", fallback = UserServiceFallBack.class)
public interface UserService {
@GetMapping(value = "/user/get/{uid}")
User getUser(@PathVariable("uid") Long uid);
}
3、修改订单微服务的业务实现类中提交订单的业务方法,如下所示:
// ...
if (user == null){
throw new RuntimeException("未获取到用户信息: " + JSONObject.toJSONString(orderParamVo));
}
if (user.getId() == -1){
throw new RuntimeException("触发了用户微服务的容错逻辑: " + JSONObject.toJSONString(orderParamVo));
}
Product product = productService.getProduct(orderParamVo.getProductId());
if (product == null){
throw new RuntimeException("未获取到商品信息: " + JSONObject.toJSONString(orderParamVo));
}
if (product.getId() == -1){
throw new RuntimeException("触发了商品微服务的容错逻辑: " + JSONObject.toJSONString(orderParamVo));
}
// ...
Result<Integer> result = productService.updateCount(orderParamVo.getProductId(), orderParamVo.getCount());
if (result.getCode() != HttpCode.SUCCESS){
throw new RuntimeException("库存扣减失败");
}
if (result.getCode() == 1001){
throw new RuntimeException("触发了商品微服务的容错逻辑: " + JSONObject.toJSONString(orderParamVo));
}
可以看到,修改后的提交订单的业务方法主要增加了服务容错的判断逻辑
至此,我们在项目中使用Sentinel实现了服务容错的功能
3.3 测试服务容错
停掉所有的用户微服务和商品微服务(也就是只启动订单微服务),在浏览器中访问 http://localhost:8080/order/submit_order?userId=1001&productId=1001&count=1
,结果如下所示:
当然,读者也可以测试:只启动用户、订单微服务;商品、订单微服务。
返回的原始数据:
触发了用户微服务的容错逻辑: {“count”:1,“empty”:false,“productId”:1001,“userId”:1001}
说明项目集成Sentinel成功实现了服务的容错功能
代码地址
代码已经上传至码云,码云地址
其中,数据库文件位于 db
文件夹下。