Java 高并发限流实战:Guava RateLimiter 与 Sentinel 对比
照着做完,你能跑通 Guava RateLimiter 与 Sentinel 两套限流代码,并知道什么场景该用哪个、各自的坑在哪。
第一步:先分清你要的是单机限流还是集群限流
这是选型的唯一分水岭。Guava RateLimiter 是进程内的令牌桶,几个 JVM 就有几个桶——服务部署 4 个实例、每个配 100 QPS,实际入口能打进来 400 QPS。Sentinel 的规则可以走 Nacos/Apollo 下发到全部实例,也可以做集群限流。
判断方法很简单:你有一台机器就 Guava,多台机器且要卡住总入口 QPS,就 Sentinel。
第二步:跑起 Guava RateLimiter
引入依赖,只要一个包:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.3-jre</version>
</dependency>
最小可用代码:
// 每秒放行 100 个请求,令牌桶平滑发放
private final RateLimiter limiter = RateLimiter.create(100.0);
public void handle() {
// 拿不到就立刻返回,不阻塞线程(推荐)
if (!limiter.tryAcquire(1, 200, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("请求过于频繁");
}
// 业务逻辑
}
两个构造函数要选对:
- `RateLimiter.create(100)` → SmoothBursty,允许突发,桶里会攒令牌;
- `RateLimiter.create(100, 5, TimeUnit.SECONDS)` → SmoothWarmingUp,5 秒预热到 100 QPS,适合刚启动还没热缓存、连接池没建满的服务。
注意:`limiter.acquire()` 是阻塞的,高并发下大量线程卡在这里会把 Tomcat 线程池占满,限流反而变成雪崩。线上优先用带超时的 `tryAcquire`。
第三步:跑起 Sentinel
Sentinel 分三块:核心包、注解切面、控制台。
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.6</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.8.6</version>
</dependency>
启动控制台(默认账号密码都是 `sentinel`):
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 \
-Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.6.jar
业务代码加注解,并注册切面:
@Configuration
public class SentinelConfig {
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
@SentinelResource(value = "queryOrder",
blockHandler = "handleBlock",
fallback = "handleFallback")
public Order queryOrder(Long id) { ... }
// 限流触发时走这里,方法签名要和原方法一致,末尾多一个 BlockException
public Order handleBlock(Long id, BlockException ex) {
throw new RuntimeException("系统繁忙,请稍后再试");
}
然后到控制台「簇点链路」里找到 `queryOrder`,点「流控」新建规则,关键参数:阈值类型选 QPS、单机阈值填 200、流控模式选直接、流控效果选快速失败。
注意:`blockHandler` 必须和被保护方法在同一个类里,跨类调用不生效;只写了 `@SentinelResource` 但没注册 `SentinelResourceAspect`,注解等于没写。
注意:Sentinel 规则默认只存在内存里,应用一重启规则全丢。生产环境要接 Nacos 数据源持久化,否则限流形同虚设。
第四步:按场景选型
| 维度 | Guava RateLimiter | Sentinel |
|---|---|---|
| 作用范围 | 单 JVM | 单机 + 集群 |
| 限流模型 | 令牌桶(平滑/预热) | QPS、线程数、关联、链路 |
| 熔断降级 | 无 | 有(慢调用、异常比例) |
| 动态改规则 | 改代码重启 | 控制台实时下发 |
| 接入成本 | 一个依赖 | 依赖 + 控制台 + 持久化 |
结论:单体应用、只想给某个方法或第三方接口调用做保护,用 Guava,几行代码搞定;微服务、需要熔断降级和动态调参,用 Sentinel。
小结
- 选型先看部署形态:单机 Guava,集群/微服务 Sentinel。
- Guava 用 `tryAcquire` 带超时,别用阻塞的 `acquire`;冷启动服务用 SmoothWarmingUp。
- Sentinel 三件套缺一不可:核心包、AspectJ 切面、控制台;`blockHandler` 要同签名同类。
- Sentinel 规则务必接 Nacos 持久化,否则重启即失效。
- 两者可以叠加:Sentinel 卡总入口,Guava 细粒度保护下游依赖。
转载请注明出处,版权归原作者所有。
星耀SVIP
管理员
黑卡会员





