200字
Java Sentinel 学习笔记
2023-01-23
2023-01-23

Java Sentinel 学习笔记

为什么需要 Sentinel

上周我们的订单服务在促销活动中挂了。不是什么复杂的原因,就是请求量突然上来,数据库连接池被打满,然后整个服务就像多米诺骨牌一样倒下去。

当时我就在想:如果有个东西能在流量太大的时候帮忙挡一挡,至少不让服务直接崩溃,该多好。

后来同事推荐了 Sentinel,阿里巴巴开源的。用了一段时间,感觉确实能解决问题。

Sentinel 是什么

Sentinel 是一个流量控制组件,主要做三件事:

  • 流量控制:限制 QPS,超过阈值的请求直接拒绝
  • 熔断降级:下游服务不稳定时,暂时切断调用
  • 系统负载保护:根据系统整体负载来控制流量

说白了就是给服务加个保险丝。电流太大的时候先断开,保护整个电路不被烧坏。

快速上手

1. 添加依赖

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>1.8.6</version>
</dependency>

2. 定义资源

Entry entry = null;
try {
    entry = SphU.entry("hello");
    // 你的业务逻辑
    System.out.println("hello world");
} catch (BlockException e) {
    // 被限流了
    System.out.println("blocked!");
} finally {
    if (entry != null) {
        entry.exit();
    }
}

这段代码的意思是:用 SphU.entry() 包裹住你想保护的代码块。如果流量超过阈值,就会抛出 BlockException,你在 catch 里处理被拒绝的请求。

3. 配置规则

List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("hello");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(10);  // 每秒最多 10 个请求
rules.add(rule);
FlowRuleManager.loadRules(rules);

这里设置 QPS 阈值为 10。超过这个数字的请求会被拒绝。

注解方式更简洁

手动 try-catch 有点啰嗦。Sentinel 提供了注解方式:

@SentinelResource(value = "getUser", blockHandler = "handleBlock")
public User getUser(String userId) {
    return userDao.findById(userId);
}

public User handleBlock(String userId, BlockException e) {
    return new User("default", "默认用户");
}

blockHandler 指定被限流时的兜底方法。注意这个方法的签名要和原方法保持一致,最后加一个 BlockException 参数。

熔断降级

除了限流,熔断也很重要。

假设你的服务依赖一个第三方 API,这个 API 偶尔会抽风,响应时间从 50ms 飙到 5s。如果不做熔断,你的服务线程池会被这些慢请求占满,新请求进不来。

@SentinelResource(value = "callExternal", 
    fallback = "fallback", 
    blockHandler = "handleBlock")
public String callExternal(String param) {
    return externalService.call(param);
}

public String fallback(String param, Throwable t) {
    return "服务暂时不可用,请稍后重试";
}

这里 fallbackblockHandler 的区别是:

  • blockHandler 处理限流(BlockException)
  • fallback 处理业务异常(任何 Throwable)

控制台

Sentinel 有个 Dashboard,可以可视化地查看实时流量和配置规则。

启动方式:

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

然后在应用里配置连接:

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080

控制台可以看到每个资源的实时 QPS、拒绝数、响应时间等。也支持动态修改规则,不用重启服务。

一些踩过的坑

  1. 资源名要唯一。同一个资源名会被当作同一个限流目标,不管在哪个类里。

  2. blockHandler 方法必须是 public。不然 Sentinel 调用不了。

  3. finally 里一定要 exit()。不然 slot chain 不会被清理,会导致统计错误。

  4. 集群限流需要单独部署 token server。单机限流用本地规则就行,但如果要全局限流,得有个中心化的地方计数。

和 Hystrix 对比

之前用过 Hystrix。对比一下:

特性 Sentinel Hystrix
状态 活跃开发中 停止维护(2018)
限流 支持 QPS、线程数 只支持线程数
控制台 有,功能丰富 简单
学习曲线 较低 较高
Spring Cloud 集成 有 starter 有 starter

Hystrix 已经进入维护模式了,Netflix 官方推荐用 resilience4j 或者 Sentinel。如果本来就在用阿里系的技术栈,选 Sentinel 挺自然的。

小结

Sentinel 解决的是一个很实际的问题:服务扛不住的时候怎么办。与其让服务崩溃,不如有选择地拒绝一些请求,保证剩下的请求能正常处理。

用了几个月下来,感觉 Sentinel 的设计挺务实的。没有太多花哨的概念,上手也快。控制台功能比较全,生产环境用起来挺方便。

如果你们服务也遇到过流量突增导致的问题,可以试试 Sentinel。配置几个规则,可能就能避免一次线上事故。


以上是个人使用体会,Sentinel 还有集群限流、网关限流、热点参数限流等高级功能,这里没展开。有兴趣可以看官方文档:https://sentinelguard.io

评论