
系列导读
上一篇我们讲解了网关层限流,实现了"流量入口拦截"。但在微服务架构中,服务间的调用流量(如订单服务调用库存服务)不会经过网关,若某服务因上游调用量突增而过载,仍会导致系统雪崩。
本文将聚焦"微服务层限流",详解两大主流方案:Sentinel集群限流(微服务生态首选,支持动态配置)和Resilience4j限流(轻量级注解式实现,适配Spring Boot),帮你实现服务间调用的流量防护。
一、微服务层限流的核心意义
- 服务间调用防护:防止上游服务调用量突增导致下游服务过载(如秒杀订单服务调用库存服务);
- 精细化维度控制:支持按接口、方法、参数等维度限流(如限制
/inventory/deduct方法每秒最多500次调用); - 适配微服务特性:支持动态调整阈值、集群限流(跨实例共享限流状态)、与服务注册中心/配置中心联动。
二、Sentinel集群限流实战(微服务生态首选)
Sentinel是阿里开源的微服务治理组件,支持限流、熔断、降级等功能,集群限流基于"Token Server/Client"架构,通过共享令牌分配状态,实现跨实例的全局限流。
1. 核心架构
- Token Server:中心化令牌服务器,负责计算全局限流阈值,向Token Client分配令牌;
- Token Client:嵌入微服务实例的客户端,每接收一个请求,向Token Server申请令牌,申请成功则通过,失败则限流;
- 通信方式:基于Netty实现Token Client与Server的通信,性能高效。
2. 前置准备
- 服务注册中心:如Nacos/Eureka(Sentinel需通过注册中心发现Token Server);
- Sentinel Dashboard:可视化控制台,用于配置限流规则、监控流量;
- 依赖引入:在微服务项目中添加Sentinel集群限流依赖。
3. 步骤1:部署Token Server(中心化令牌服务器)
3.1 引入依赖(Spring Boot项目)
xml
<!-- pom.xml -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-cluster-server-default</artifactId>
<version>1.8.6</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.8.6</version>
</dependency>
3.2 配置Token Server(application.yml)
yaml
spring:
application:
name: sentinel-token-server
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # Nacos注册中心地址
sentinel:
transport:
port: 8719 # 与Dashboard通信端口
dashboard: 127.0.0.1:8080 # Sentinel Dashboard地址
cluster:
server:
port: 8720 # Token Server通信端口(供Client连接)
enable: true # 启用Token Server模式
flow:
default-threshold: 500 # 全局默认限流阈值(每秒500个请求)
3.3 启动Token Server
启动项目后,在Sentinel Dashboard中可看到SENTINEL-TOKEN-SERVER实例已注册。
4. 步骤2:配置Token Client(微服务实例)
4.1 引入依赖(微服务项目,如order-service)
xml
<!-- pom.xml -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2021.0.4.0</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-cluster-client-default</artifactId>
<version>1.8.6</version>
</dependency>
4.2 配置Token Client(application.yml)
yaml
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
sentinel:
transport:
port: 8719
dashboard: 127.0.0.1:8080
cluster:
client:
enable: true # 启用Token Client模式
server-host: 127.0.0.1 # Token Server地址
server-port: 8720 # Token Server通信端口
datasource:
# 从Nacos获取限流规则(动态配置)
ds1:
nacos:
server-addr: 127.0.0.1:8848
data-id: order-service-sentinel-rules
group-id: DEFAULT_GROUP
rule-type: flow # 限流规则类型
5. 步骤3:配置集群限流规则(Sentinel Dashboard)
- 访问Sentinel Dashboard(默认地址
http://127.0.0.1:8080); - 选择
order-service实例,进入"簇点链路",找到需要限流的接口(如/order/create); - 点击"流控",配置集群限流规则:
- 阈值类型:QPS;
- 单机阈值:100(单实例阈值,全局阈值=单机阈值×实例数);
- 流控模式:集群流控;
- 点击"新增",规则会同步到Nacos。
6. 代码中使用Sentinel限流(注解式)
java
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/order")
public class OrderController {
// 对create接口启用Sentinel限流,资源名=order:create
@SentinelResource(value = "order:create", blockHandler = "handleFlowLimit")
@PostMapping("/create")
public String createOrder() {
// 订单创建逻辑
return "订单创建成功";
}
// 限流后的降级处理方法(参数需与原方法一致,最后加BlockException参数)
public String handleFlowLimit(BlockException e) {
return "当前订单创建请求过多,请稍后重试(限流提示)";
}
}
7. 避坑点
- Token Server高可用:生产环境需部署多个Token Server(通过注册中心集群发现),避免单点故障;
- 阈值计算:集群限流阈值=单机阈值×实例数,需根据服务实例数动态调整;
- 通信端口:Token Client与Server的通信端口(8720)需开放,避免防火墙拦截;
- 规则持久化:需将限流规则持久化到Nacos/Apollo,否则Sentinel Dashboard重启后规则丢失。
三、Resilience4j限流实战(轻量级注解式)
Resilience4j是一款轻量级的微服务治理组件(替代Hystrix),支持限流、熔断、重试等功能,无侵入式设计(基于注解),适配Spring Boot生态,分布式限流需结合Redis实现。
1. 核心特性
- 轻量级:仅依赖Slf4j和Jackson,无其他重量级依赖;
- 注解式:通过
@RateLimiter注解快速启用限流; - 灵活配置:支持YAML/Properties配置,可动态调整阈值;
- 分布式支持:结合Redis存储限流状态(如滑动窗口计数器)。
2. 步骤1:引入依赖(Spring Boot项目)
xml
<!-- pom.xml -->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-ratelimiter</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
3. 步骤2:配置限流规则(application.yml)
yaml
spring:
redis:
host: 127.0.0.1
port: 6379
# Resilience4j限流配置
resilience4j:
ratelimiter:
instances:
# 限流实例名:orderCreateLimiter(与注解中的name对应)
orderCreateLimiter:
limitForPeriod: 100 # 每个周期(默认1秒)的最大请求数
limitRefreshPeriod: 1000 # 周期时长(毫秒)
timeoutDuration: 0 # 请求获取令牌的超时时间(0=立即拒绝)
# 分布式限流配置(使用Redis存储限流状态)
registry:
type: redis
redis:
redisTemplateBeanName: redisTemplate # Spring RedisTemplate Bean名
4. 步骤3:代码中使用Resilience4j限流(注解式)
java
import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/order")
public class OrderController {
// 启用限流,实例名=orderCreateLimiter,fallbackMethod=限流降级方法
@RateLimiter(name = "orderCreateLimiter", fallbackMethod = "handleFlowLimit")
@PostMapping("/create")
public String createOrder() {
// 订单创建逻辑
return "订单创建成功";
}
// 限流降级处理方法(参数需与原方法一致)
public String handleFlowLimit(Exception e) {
return "当前订单创建请求过多,请稍后重试(Resilience4j限流提示)";
}
}
5. 自定义限流维度(如按用户ID限流)
Resilience4j默认按"限流实例名"限流,若需按用户ID等自定义维度,需实现RateLimiterRegistry和KeyResolver:
java
import io.github.resilience4j.ratelimiter.RateLimiter;
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class CustomRateLimiterManager {
private final RateLimiterRegistry rateLimiterRegistry;
private final StringRedisTemplate redisTemplate;
public CustomRateLimiterManager(RateLimiterRegistry rateLimiterRegistry, StringRedisTemplate redisTemplate) {
this.rateLimiterRegistry = rateLimiterRegistry;
this.redisTemplate = redisTemplate;
}
// 按用户ID获取限流实例
public RateLimiter getRateLimiterByUserId(HttpServletRequest request) {
String userId = request.getHeader("X-User-ID");
String limiterName = "orderCreateLimiter:" + userId;
// 从Registry中获取或创建限流实例
return rateLimiterRegistry.rateLimiter(limiterName);
}
}
6. 避坑点
- Redis依赖:分布式场景必须引入
spring-boot-starter-data-redis,否则仅支持单机限流; - 超时时间:
timeoutDuration=0表示请求获取令牌失败时立即拒绝,若需排队等待,可设置为500ms(根据业务调整); - 限流实例名:注解中的
name需与配置文件中的instances名称一致,否则无法加载规则; - 降级方法:降级方法的参数需与原方法完全一致,否则会抛出
NoSuchMethodException。
四、Sentinel vs Resilience4j限流对比
| 特性 | Sentinel集群限流 | Resilience4j限流 |
|---|---|---|
| 生态适配 | 适配Spring Cloud Alibaba生态 | 适配Spring Boot/Spring Cloud生态 |
| 分布式支持 | 原生支持集群限流(Token Server) | 需结合Redis实现分布式限流 |
| 配置方式 | 可视化控制台+配置中心(动态调整) | 配置文件+注解(支持动态调整) |
| 功能丰富度 | 支持限流、熔断、降级、监控等 | 支持限流、熔断、重试等(功能精简) |
| 侵入性 | 注解式+代码埋点(低侵入) | 纯注解式(无侵入) |
| 适用场景 | 中大型微服务集群(需丰富功能) | 中小型微服务(追求轻量级) |
五、下一篇预告
前面讲解的限流方案均适用于"同步请求场景",但分布式系统中存在大量异步场景(如秒杀订单异步通知、日志采集),需通过消息队列实现削峰填谷。
下一篇将聚焦"异步场景限流",详解消息队列(Kafka/RocketMQ)的生产者/消费者限流配置,以及动态限流(结合服务伸缩)的实现,帮你覆盖全场景限流需求!