跳到主要内容

开源框架适配

Sentinel 提供了丰富的框架适配模块,可以轻松地将各种主流框架接入 Sentinel 进行流量控制和熔断降级。本章介绍 Sentinel 与常用框架的整合方式。

适配模块概览

Sentinel 提供的适配模块可以分为以下几类:

类别支持的框架
Web 框架Servlet、Spring WebFlux、JAX-RS
RPC 框架Dubbo、gRPC、SOFARPC、Feign
HTTP ClientApache HttpClient、OkHttp
API GatewaySpring Cloud Gateway、Zuul
消息队列Apache RocketMQ
响应式Reactor
微服务Spring Cloud、Quarkus

Web Servlet 适配

Sentinel 提供针对 Servlet 的原生整合,可以对 Web 请求进行流量控制。

引入依赖

<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-web-servlet</artifactId>
<version>1.8.8</version>
</dependency>

配置 Filter

web.xml 中配置:

<filter>
<filter-name>SentinelCommonFilter</filter-name>
<filter-class>com.alibaba.csp.sentinel.adapter.servlet.CommonFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SentinelCommonFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

在 Spring Boot 中配置:

@Configuration
public class FilterConfig {

@Bean
public FilterRegistrationBean<Filter> sentinelFilterRegistration() {
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
registration.setFilter(new CommonFilter());
registration.addUrlPatterns("/*");
registration.setName("sentinelFilter");
registration.setOrder(1);
return registration;
}
}

自定义限流处理

默认情况下,被限流的请求会返回 Blocked by Sentinel (flow limiting)。可以通过以下方式自定义处理逻辑:

方式一:设置跳转页面

// 通过代码设置
WebServletConfig.setBlockPage("/blocked");

// 或通过 JVM 参数
// -Dcsp.sentinel.web.servlet.block.page=/blocked

方式二:实现自定义处理器

WebCallbackManager.setUrlBlockHandler(new UrlBlockHandler() {
@Override
public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException e) throws IOException {
response.setStatus(429);
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("{\"code\":429,\"message\":\"系统繁忙\"}");
}
});

URL 资源清洗

对于 REST 风格的 API,需要清洗 URL 资源,避免资源数量过多:

WebCallbackManager.setUrlCleaner(new UrlCleaner() {
@Override
public String clean(String originUrl) {
if (originUrl == null || originUrl.isEmpty()) {
return originUrl;
}

// 将 /user/123 归一化为 /user/*
if (originUrl.matches("/user/\\d+")) {
return "/user/*";
}

// 将 /order/abc-123 归一化为 /order/*
if (originUrl.matches("/order/[a-z0-9-]+")) {
return "/order/*";
}

// 过滤静态资源
if (originUrl.endsWith(".ico") || originUrl.endsWith(".css") || originUrl.endsWith(".js")) {
return "";
}

return originUrl;
}
});

请求来源解析

按来源限流需要实现 RequestOriginParser

WebCallbackManager.setRequestOriginParser(new RequestOriginParser() {
@Override
public String parseOrigin(HttpServletRequest request) {
// 从请求头获取来源
String origin = request.getHeader("X-Request-Source");
if (origin != null && !origin.isEmpty()) {
return origin;
}

// 从请求参数获取
origin = request.getParameter("source");
if (origin != null && !origin.isEmpty()) {
return origin;
}

// 默认使用 IP
return request.getRemoteAddr();
}
});

Dubbo 适配

Sentinel 提供 Dubbo 的适配模块,可以自动统计 Dubbo 服务接口和方法的调用。

引入依赖

根据 Dubbo 版本选择对应的适配模块:

<!-- Apache Dubbo 3.x -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-apache-dubbo3-adapter</artifactId>
<version>1.8.8</version>
</dependency>

<!-- Apache Dubbo 2.7.x -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-apache-dubbo-adapter</artifactId>
<version>1.8.8</version>
</dependency>

<!-- Dubbo 2.6.x -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-dubbo-adapter</artifactId>
<version>1.8.8</version>
</dependency>

资源名规则

引入依赖后,Dubbo 的服务接口和方法会自动成为 Sentinel 资源:

  • 接口级别:接口全限定名,如 com.example.UserService
  • 方法级别接口全限定名:方法名(参数类型),如 com.example.UserService:getUser(java.lang.String)

配置限流规则

// 对接口限流
FlowRule interfaceRule = new FlowRule();
interfaceRule.setResource("com.example.UserService");
interfaceRule.setCount(100);

// 对方法限流
FlowRule methodRule = new FlowRule();
methodRule.setResource("com.example.UserService:getUser(java.lang.String)");
methodRule.setCount(50);

FlowRuleManager.loadRules(Arrays.asList(interfaceRule, methodRule));

自定义降级处理

// 实现自定义 fallback
DubboFallback fallback = new DubboFallback() {
@Override
public Result handle(Invoker<?> invoker, Invocation invocation, BlockException ex) {
// 返回降级结果
return new AppResponse("服务繁忙,请稍后重试");
}
};

// 注册 fallback
DubboFallbackRegistry.setConsumerFallback(fallback);

关闭适配

如果不需要某个 Filter,可以手动关闭:

<!-- 关闭 Consumer 端 Filter -->
<dubbo:consumer filter="-sentinel.dubbo.consumer.filter"/>

<!-- 关闭 Provider 端 Filter -->
<dubbo:provider filter="-sentinel.dubbo.provider.filter"/>

gRPC 适配

Sentinel 提供 gRPC 的适配模块,通过 ServerInterceptor 和 ClientInterceptor 保护 gRPC 服务。

引入依赖

<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-grpc-adapter</artifactId>
<version>1.8.8</version>
</dependency>

服务端配置

import com.alibaba.csp.sentinel.adapter.grpc.SentinelGrpcServerInterceptor;
import io.grpc.Server;
import io.grpc.ServerBuilder;

public class GrpcServer {

public static void main(String[] args) throws Exception {
Server server = ServerBuilder.forPort(50051)
.addService(new MyServiceImpl())
.intercept(new SentinelGrpcServerInterceptor()) // 注册拦截器
.build();

server.start();
server.awaitTermination();
}
}

客户端配置

import com.alibaba.csp.sentinel.adapter.grpc.SentinelGrpcClientInterceptor;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

public class GrpcClient {

private final ManagedChannel channel;

public GrpcClient(String host, int port) {
this.channel = ManagedChannelBuilder.forAddress(host, port)
.intercept(new SentinelGrpcClientInterceptor()) // 注册拦截器
.build();
}
}

资源名规则

  • 服务端方法全限定名,如 com.example.MyService/getUser
  • 客户端方法全限定名,与服务端相同

注意:Sentinel gRPC 适配目前只支持 unary call。

Spring WebFlux 适配

Sentinel 提供与 Spring WebFlux 的整合模块,支持响应式 Web 应用的流量控制。

引入依赖

<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-webflux-adapter</artifactId>
<version>1.8.8</version>
</dependency>

配置

import com.alibaba.csp.sentinel.adapter.spring.webflux.SentinelWebFluxFilter;
import com.alibaba.csp.sentinel.adapter.spring.webflux.exception.SentinelBlockExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

@Configuration
public class WebFluxConfig {

@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelBlockExceptionHandler sentinelBlockExceptionHandler() {
return new SentinelBlockExceptionHandler();
}

@Bean
@Order(-1)
public SentinelWebFluxFilter sentinelWebFluxFilter() {
return new SentinelWebFluxFilter();
}
}

自定义限流处理

import com.alibaba.csp.sentinel.adapter.spring.webflux.callback.WebFluxCallbackManager;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;

@Configuration
public class SentinelConfig {

@PostConstruct
public void init() {
// 自定义限流处理
WebFluxCallbackManager.setBlockHandler((exchange, t) -> {
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);

String result = "{\"code\":429,\"message\":\"系统繁忙\"}";
return exchange.getResponse().writeWith(
Mono.just(exchange.getResponse().bufferFactory().wrap(result.getBytes()))
);
});
}
}

Reactor 适配

Sentinel 提供对 Reactor 的适配,可以在响应式应用中接入 Sentinel。

引入依赖

<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-reactor-adapter</artifactId>
<version>1.8.8</version>
</dependency>

使用方式

import com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorTransformer;
import reactor.core.publisher.Mono;

public class ReactiveService {

public Mono<String> doSomething(String param) {
return Mono.fromCallable(() -> {
// 业务逻辑
return "result: " + param;
})
// 使用 Sentinel 转换器包装
.transform(new SentinelReactorTransformer<>("resourceName"));
}

// 对于 Flux
public Flux<String> doSomethingFlux() {
return Flux.range(1, 10)
.map(i -> "item-" + i)
.transform(new SentinelReactorTransformer<>("fluxResource"));
}
}

HTTP Client 适配

Apache HttpClient

<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-apache-httpclient-adapter</artifactId>
<version>1.8.8</version>
</dependency>
import com.alibaba.csp.sentinel.adapter.httpclient.SentinelHttpRequestRetryHandler;
import com.alibaba.csp.sentinel.adapter.httpclient.SentinelHttpClientBuilder;
import org.apache.http.impl.client.CloseableHttpClient;

// 创建 Sentinel 包装的 HttpClient
CloseableHttpClient httpClient = new SentinelHttpClientBuilder()
.setRetryHandler(new SentinelHttpRequestRetryHandler(3, true))
.build();

// 执行请求时会自动进行限流
HttpGet request = new HttpGet("http://example.com/api");
HttpResponse response = httpClient.execute(request);

OkHttp

<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-okhttp-adapter</artifactId>
<version>1.8.8</version>
</dependency>
import com.alibaba.csp.sentinel.adapter.okhttp.SentinelOkHttpInterceptor;
import okhttp3.OkHttpClient;

OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new SentinelOkHttpInterceptor("okhttp-resource"))
.build();

RocketMQ 适配

在 RocketMQ 消费场景中,Sentinel 可以实现消息的削峰填谷,平滑处理突发消息。

使用场景

当消费者处理消息时,可能会遇到消息突刺。Sentinel 的匀速排队模式可以将消息均匀处理,避免系统负载过高。

配置示例

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;

public class RocketMQConsumer {

private static final String KEY = "myGroup:myTopic";

public static void main(String[] args) {
// 初始化限流规则
initFlowControlRule();

// 创建消费者
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("myGroup");
consumer.subscribe("myTopic", "*");

consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
for (MessageExt msg : msgs) {
Entry entry = null;
try {
// 资源名为 groupName:topicName
entry = SphU.entry(KEY);

// 处理消息
processMessage(msg);

} catch (BlockException e) {
// 被限流,等待重试
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
} finally {
if (entry != null) {
entry.exit();
}
}
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});

consumer.start();
}

private static void initFlowControlRule() {
FlowRule rule = new FlowRule();
rule.setResource(KEY);
rule.setCount(5); // 每秒处理 5 条消息
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER); // 匀速排队
rule.setMaxQueueingTimeMs(5000); // 最大排队时间 5 秒

FlowRuleManager.loadRules(Collections.singletonList(rule));
}

private static void processMessage(MessageExt msg) {
// 消息处理逻辑
System.out.println("Processing: " + new String(msg.getBody()));
}
}

削峰填谷效果

配置匀速排队后,消息处理的效果:

  • QPS 设置为 5,则每 200ms 处理一条消息
  • 多余的消息在队列中等待
  • 等待超过 maxQueueingTimeMs 的消息会被拒绝

Feign 整合

Feign 的适配整合在 Spring Cloud Alibaba 中,使用时需要开启 Sentinel 支持:

feign:
sentinel:
enabled: true

定义 Feign Client 并配置 fallback:

@FeignClient(name = "user-service", fallback = UserServiceFallback.class)
public interface UserServiceClient {

@GetMapping("/api/users/{id}")
User getUser(@PathVariable Long id);
}

@Component
public class UserServiceFallback implements UserServiceClient {
@Override
public User getUser(Long id) {
return User.defaultUser();
}
}

注意事项

1. 资源数量控制

不同 URL 会作为不同资源处理,对于 REST 风格 API,务必使用 UrlCleaner 进行资源清洗,避免资源数量超过阈值(默认 6000)。

2. 接入控制台

适配模块只提供适配功能,若希望接入 Sentinel 控制台,需要额外引入 sentinel-transport-simple-http 依赖并配置控制台地址。

3. 版本兼容性

选择适配模块时,注意与框架版本的兼容性:

适配模块支持的框架版本
sentinel-apache-dubbo3-adapterApache Dubbo 3.0.5+
sentinel-apache-dubbo-adapterApache Dubbo 2.7.x
sentinel-dubbo-adapterDubbo 2.6.x

4. 性能考虑

适配模块会增加一定的性能开销,在高性能场景下需要评估影响。

最佳实践

1. 选择合适的适配模块

根据项目使用的框架选择对应的适配模块,避免引入不必要的依赖。

2. 合理配置资源粒度

  • 对于 Web 接口,建议按业务模块清洗 URL
  • 对于 RPC 调用,建议在接口和方法两个级别分别配置规则

3. 提供有意义的降级响应

针对不同框架的特点,提供合适的降级响应:

  • Web 接口:返回 JSON 格式的错误信息
  • RPC 调用:返回默认值或抛出业务异常
  • 消息队列:返回重试状态

4. 监控与告警

接入 Sentinel 控制台,实时监控各资源的调用情况,配置告警规则。

下一步