苦恼!教你拿下Sentinel的使用,你还搞不定分布式系统流控、熔断吗

文章讲述了如何在SpringBoot项目中集成阿里巴巴的Sentinel流量控制工具,包括设置规则、控制台集成、系统集成实践以及最佳实践,如规则持久化、框架适配和使用Nacos作为数据源。
摘要由CSDN通过智能技术生成

Entry entry = null;
try {
entry = SphU.entry(resource);
logger.info(“业务操作…{}”,count.get());
Thread.sleep(15);
} catch (BlockException e) {
if (e instanceof DegradeException){
logger.error(“触发熔断机制…{}”,count.get());
Thread.sleep(500);
}
} finally {
if (entry != null) {
entry.exit();
}
if (count.get()>=20){
stop = true;
}
}
}
logger.info(“----------------------------”);
}

在上面的代码中,我们一共有20个请求。我们让线程停顿15ms使平均RT超过阈值,也就是超过10ms。

我们定义的规则里面是1秒内连续5个请求的平均RT超出阈值,就可以触发熔断,所以当第6个请求到达时,就会触发熔断。

熔断多久呢?就在3秒的时间窗口。

上面的测试代码中,在触发熔断之后,我们又手动让线程停顿了 1000ms ,所以每次熔断的请求会有3个。

是不是这样,我们运行代码,看下结果:

10:56:20.022 [main] INFO orderService - 业务操作…1
10:56:20.040 [main] INFO orderService - 业务操作…2
10:56:20.056 [main] INFO orderService - 业务操作…3
10:56:20.072 [main] INFO orderService - 业务操作…4
10:56:20.088 [main] INFO orderService - 业务操作…5
10:56:20.127 [main] ERROR orderService - 触发熔断机制…6
10:56:21.128 [main] ERROR orderService - 触发熔断机制…7
10:56:22.128 [main] ERROR orderService - 触发熔断机制…8
10:56:23.129 [main] INFO orderService - 业务操作…9
10:56:23.145 [main] INFO orderService - 业务操作…10
10:56:23.160 [main] INFO orderService - 业务操作…11
10:56:23.176 [main] INFO orderService - 业务操作…12
10:56:23.192 [main] INFO orderService - 业务操作…13
10:56:23.207 [main] ERROR orderService - 触发熔断机制…14
10:56:24.208 [main] ERROR orderService - 触发熔断机制…15
10:56:25.208 [main] ERROR orderService - 触发熔断机制…16
10:56:26.209 [main] INFO orderService - 业务操作…17
10:56:26.224 [main] INFO orderService - 业务操作…18
10:56:26.240 [main] INFO orderService - 业务操作…19
10:56:26.255 [main] INFO orderService - 业务操作…20
10:56:26.271 [main] INFO orderService - ----------------------------

至此,我们就可以说,Sentinel 能够正常工作了。

二、系统集成

上面只是一个很简单的Demo示例,如果我们希望在我们的SpringBoot项目中使用Sentinel,还需要一些工作。

1、Sentinel 控制台

Sentinel 提供一个轻量级的开源控制台,它是使用SpringBoot开发的。

它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。

所以,我们先把这个控制台运行起来。

第一步,需要在https://github.com/alibaba/Sentinel/releases这个地址,下载最新版本的控制台 jar 包。

第二步,使用命令启动控制台程序,其中 -Dserver.port=9080 用于指定 Sentinel 控制台端口。

java -Dserver.port=9080 -Dcsp.sentinel.dashboard.server=localhost:9080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

第三步,我们的业务系统引入 Transport 模块来与 Sentinel 控制台进行通信。

com.alibaba.csp sentinel-transport-simple-http 1.7.2

第四步,在我们的业务系统中,设置JVM启动参数,用来指明Sentinel控制台的地址。

-Dcsp.sentinel.dashboard.server=127.0.0.1:9080

最后,启动我们的业务系统,然后打开Sentinel控制台,如果可以看到机器列表就可以了。

2、定义规则

在定义规则之前,我们需要规划好资源范围。

什么意思呢?比如我们拿一个订单业务来说,是不是所有的订单操作都算一个资源?还是拆分开来看,创建订单算一个资源,订单查询算另外一个资源。

所以,我们可以先把希望流控的资源名称定义出来。

public final class ResourceConstants {
public static final String ORDER_SERVICE = OrderService.class.getName();
public static final String ORDER_SERVICE_ORDERS = ORDER_SERVICE+“.orders”;
public static final String ORDER_SERVICE_CREATE = ORDER_SERVICE+“.create”;
}

由于是一个SpringBoot项目,我们可以在系统启动的时候,来加载流控规则。

@Component
public class ApplicationStartup implements ApplicationListener {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
initFlowRule(ResourceConstants.ORDER_SERVICE,5);
initFlowRule(ResourceConstants.ORDER_SERVICE_ORDERS,5);
}
public void initFlowRule(String resourceName,int count) {
FlowRule flowRule = new FlowRule(resourceName)
.setCount(count)
.setGrade(RuleConstant.FLOW_GRADE_QPS);
List list = new ArrayList<>();
list.add(flowRule);
FlowRuleManager.loadRules(list);
}
}

然后,我们在Controller加入Sentinel的代码,来达到流控的效果。

@RequestMapping(“/getOrders”)
public ResponseEntity getOrders(){
Entry entry = null;
try {
entry = SphU.entry(ResourceConstants.ORDER_SERVICE_ORDERS);
return ResponseEntity.ok(orderService.orders());
} catch (BlockException e) {
logger.error(“请求被限流…{}”,e.getRule().getResource());
return ResponseEntity.badRequest().body(e.getRule());
} finally {
if (entry != null) {
entry.exit();
}
}
}

现在,我们拿JMeter来测试一下,启动10个线程来请求这个接口。只会通过5个请求,拒绝5个请求。

至此,我们已经可以在SpringBoot项目中简单使用Sentinel了,不过此时还有两个很明显的问题。

  • 在每个需要流控的地方,通过API硬编码,侵入性太强而且也不方便;
  • 流控规则只保留在内存中,系统重启就没了,没有持久化规则数据。

接下来,我们来解决上述的两个问题。

三、框架适配

得益于广泛的开源生态,Sentinel 提供开箱即用的与其它开源框架/库的整合模块。我们只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。

我们希望可以对 Web 请求进行流量控制,那么需要引入Sentinel 提供与 Servlet 的整合。

com.alibaba.csp sentinel-web-servlet 1.7.2
1、Filter配置

因为是SpringBoot应用,我们通过Configuration进行配置。

@Configuration
public class SentinelFilterConfig {
@Bean
public FilterRegistrationBean sentinelFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean<>();
registration.setFilter(new CommonFilter());
registration.addUrlPatterns(“/*”);
registration.setName(“sentinelFilter”);
registration.setOrder(1);
return registration;
}
}

在我们自己的业务代码中,就可以免去Sentinel API部分了。

@RequestMapping(“/getOrders”)
public ResponseEntity getOrders(){
return ResponseEntity.ok(orderService.orders());
}

在流控规则不变的情况下,我们拿JMeter启动10个线程来请求这个接口。同样的只会通过5个请求,拒绝5个请求。

2、UrlBlockHandler

默认情况下,当请求被限流时会返回默认的提示页面。

我们可以在代码中调用 WebServletConfig.setBlockPage(blockPage) 方法设定自定义的跳转 URL,当请求被限流时会自动跳转至设定好的 URL。

如果不打算让它跳转页面,我们也可以实现 UrlBlockHandler 接口并编写定制化的限流处理逻辑。

比如像下面这样,限流或熔断之后,会向客户端返回一个异常的HTTP状态码和提示信息。

public class SentinelUrlBlockHandler implements UrlBlockHandler {

public static final String flowMsg = “触发流控机制~”;
public static final String degradeMsg = “触发熔断机制~”;
Logger logger = LoggerFactory.getLogger(this.getClass());

@Override
public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException ex){
logger.error(“熔断限流…{}”,ex.getRule());
response.setCharacterEncoding(“UTF-8”);
response.setStatus(HttpStatus.BAD_REQUEST.value());
PrintWriter out = response.getWriter();
if (ex instanceof FlowException){
out.print(flowMsg);
}else if (ex instanceof DegradeException){
out.print(degradeMsg);
}
out.flush();
out.close();
}
}

然后将其注册至 WebCallbackManager 中。

WebCallbackManager.setUrlBlockHandler(new SentinelUrlBlockHandler());

3、UrlCleaner

Sentinel Web Filter 会将每个到来的不同的 URL 都作为不同的资源处理。

比如订单业务中的,创建订单、订单查询、订单删除等等,因为URL的不同,都会被当作不同的资源。

如果我们希望将这些操作都归到订单资源下/order/*,就需要实现 UrlCleaner 接口清洗一下资源。

比如像下面这样,将资源归类。比如/order/getOrders和/order/createOrder,都会变成/order/*

public class SentinelUrlClean implements UrlCleaner {
@Override
public String clean(String originUrl) {
if (originUrl == null || originUrl.isEmpty()) {
return originUrl;
}
int lastSlashIndex = originUrl.lastIndexOf(“/”);
if (lastSlashIndex >= 0) {
originUrl = originUrl.substring(0, lastSlashIndex) + “/*”;
}
return originUrl;
}
}

然后将其注册至 WebCallbackManager 中。

WebCallbackManager.setUrlCleaner(new SentinelUrlClean());

当时,更绝对一些,如果整个系统都采用一个资源,那么这里只返回一个固定的url也可以。

四、最佳实践

上面我们说到,现在的Sentinel规则数据都只保留在内存中,没办法做到集中管理和推送规则,不具备生产环境可用性。

规则管理及推送,一般有三种方式。

  • 原始模式

将规则推送至客户端并直接更新到内存中。重启即消失,不建议在生产环境中使用。

  • Pull 模式

客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件 等。不保证实时性,拉取过于频繁可能会导致性能问题。

  • Push 模式

规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心,有更好的实时性和一致性。生产环境下一般采用 push 模式的数据源。

生产环境下一般更常用的是 push 模式的数据源。对于 push 模式的数据源,如远程配置中心(ZooKeeper, Nacos, Apollo等等),推送的操作不应由 Sentinel 客户端进行,而应该经控制台统一进行管理,直接进行推送,数据源仅负责获取配置中心推送的配置并更新到本地。因此推送规则正确做法应该是 ** 配置中心控制台/Sentinel 控制台 → 配置中心 → Sentinel 数据源 → Sentinel **,而不是经 Sentinel 数据源推送至配置中心。

接下来我们来实现由Nacos配置中心统一管理数据。

1、启动Nacos

关于Nacos本文不再多说,下载一个启动就好了。

2、引入依赖

NacosDataSource,官方已经提供了,我们引入相关依赖即可。

com.alibaba.csp sentinel-datasource-extension 1.7.2 com.alibaba.csp sentinel-datasource-nacos 1.7.2
3、从数据源中读取规则数据

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。

下面的面试题答案都整理成文档笔记。也还整理了一些面试资料&最新2021收集的一些大厂的面试真题(都整理成文档,小部分截图)

在这里插入图片描述

最新整理电子书

在这里插入图片描述

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!
36.jpg" alt=“img” style=“zoom: 33%;” />

最后

针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。

下面的面试题答案都整理成文档笔记。也还整理了一些面试资料&最新2021收集的一些大厂的面试真题(都整理成文档,小部分截图)

[外链图片转存中…(img-tSBhVDad-1712510028196)]

最新整理电子书

[外链图片转存中…(img-2VDzESYM-1712510028196)]

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值