云原生微服务体系

Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。Sentinel 与 Spring Boot/Spring Cloud 的整合见 。

Spring Cloud Alibaba 默认为 Sentinel 整合了 Servlet、RestTemplate、FeignClient 和 Spring WebFlux。Sentinel 在 Spring Cloud 生态中,不仅补全了 Hystrix 在 Servlet 和 RestTemplate 这一块的空白,而且还完全兼容了 Hystrix 在 FeignClient 中限流降级的用法,并且支持运行时灵活地配置和调整限流降级规则。

Spring Cloud Alibaba Sentinel 的示例可以参考 sentinel-guide-spring-cloud

Quarkus

注:从 1.8.0 版本开始支持,需要 Java 8 及以上版本。

Sentinel 提供(支持 native image),可以很方便地将 JAX-RS Web 服务接入并进行高可用防护,同时支持注解方式自定义埋点(基于 CDI)。

相关模块:

  • sentinel-annotation-quarkus-adapter

Web 适配

Web Servlet

Sentinel 提供针对 Servlet 的原生整合,可以对 Web 请求进行流量控制。使用时需引入以下模块(以 Maven 为例):

您只需要在 Web 容器中的 web.xml 配置文件中进行如下配置即可开启 Sentinel 支持:

  1. <filter>
  2. <filter-name>SentinelCommonFilter</filter-name>
  3. <filter-class>com.alibaba.csp.sentinel.adapter.servlet.CommonFilter</filter-class>
  4. </filter>
  5. <filter-mapping>
  6. <filter-name>SentinelCommonFilter</filter-name>
  7. <url-pattern>/*</url-pattern>
  8. </filter-mapping>

若是 Spring 应用可以通过 Spring 进行配置,例如:

  1. @Configuration
  2. public class FilterConfig {
  3. @Bean
  4. public FilterRegistrationBean sentinelFilterRegistration() {
  5. FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
  6. registration.setFilter(new CommonFilter());
  7. registration.addUrlPatterns("/*");
  8. registration.setName("sentinelFilter");
  9. registration.setOrder(1);
  10. return registration;
  11. }
  12. }

接入 filter 之后,所有访问的 Web URL 就会被自动统计为 Sentinel 的资源,可以针对单个 URL 维度进行流控。若希望区分不同 HTTP Method,可以将 HTTP_METHOD_SPECIFY 这个 init parameter 设为 true,给每个 URL 资源加上前缀,比如 GET:/foo

限流处理逻辑:默认情况下,当请求被限流时会返回默认的提示页面 Blocked by Sentinel (flow limiting)。您也可以通过 JVM 参数 -Dcsp.sentinel.web.servlet.block.page 或代码中调用 WebServletConfig.setBlockPage(blockPage) 方法设定自定义的跳转 URL,当请求被限流时会自动跳转至设定好的 URL。同样您也可以实现 UrlBlockHandler 接口并编写定制化的限流处理逻辑,然后将其注册至 WebCallbackManager 中。

提示:1.7.0 版本开始默认的限流页面 HTTP 返回码是 429。您可以通过 csp.sentinel.web.servlet.block.status 配置项自定义限流页面的 HTTP 状态码。

按来源限流:若希望对 HTTP 请求按照来源限流,则可以自己实现 RequestOriginParser 接口从 HTTP 请求中解析 origin 并注册至 WebCallbackManager 中。注意来源数目不能太多,若太多请自定义埋点作为参数传入并使用热点规则。

注意:Sentinel Web Filter 会将每个到来的不同的 URL 都作为不同的资源处理,因此对于 REST 风格的 API,需要自行实现 UrlCleaner 接口清洗一下资源(比如将满足 /foo/:id 的 URL 都归到 /foo/* 资源下),然后将其注册至 WebCallbackManager 中。否则会导致资源数量过多,超出资源数量阈值(目前是 6000)时多出的资源的规则将 不会生效

从 1.6.3 版本开始,UrlCleaner 还可以来过滤掉不希望统计的 URL,只需要在 UrlCleaner 中将不希望统计的 URL 转换成空字符串(””)即可。示例:

  1. WebCallbackManager.setUrlCleaner(new UrlCleaner() {
  2. @Override
  3. if (originUrl == null || originUrl.isEmpty()) {
  4. return originUrl;
  5. }
  6. // 比如将满足 /foo/{id} 的 URL 都归到 /foo/*
  7. if (originUrl.startsWith("/foo/")) {
  8. return "/foo/*";
  9. }
  10. // 不希望统计 *.ico 的资源文件,可以将其转换为 empty string (since 1.6.3)
  11. if (originUrl.endsWith(".ico")) {
  12. return "";
  13. }
  14. return originUrl;
  15. }
  16. });

如果您正在使用 Spring Boot / Spring Cloud,那么可以通过引入 Spring Cloud Alibaba Sentinel 来更方便地整合 Sentinel,详情请见 Spring Cloud Alibaba 文档

Spring WebFlux

Sentinel 提供与 Spring WebFlux 的整合模块,从而 Reactive Web 应用也可以利用 Sentinel 的流控降级来保障稳定性。该整合模块基于 Sentinel Reactor Adapter 实现。

使用时需引入以下模块(以 Maven 为例):

  1. <dependency>
  2. <groupId>com.alibaba.csp</groupId>
  3. <artifactId>sentinel-spring-webflux-adapter</artifactId>
  4. <version>x.y.z</version>
  5. </dependency>

使用时只需注入对应的 SentinelWebFluxFilter 实例以及 SentinelBlockExceptionHandler 实例即可。比如:

  1. @Configuration
  2. public class WebFluxConfig {
  3. private final List<ViewResolver> viewResolvers;
  4. public WebFluxConfig(ObjectProvider<List<ViewResolver>> viewResolversProvider,
  5. ServerCodecConfigurer serverCodecConfigurer) {
  6. this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
  7. this.serverCodecConfigurer = serverCodecConfigurer;
  8. }
  9. @Bean
  10. @Order(-1)
  11. public SentinelBlockExceptionHandler sentinelBlockExceptionHandler() {
  12. // Register the block exception handler for Spring WebFlux.
  13. return new SentinelBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
  14. }
  15. @Bean
  16. @Order(-1)
  17. public SentinelWebFluxFilter sentinelWebFluxFilter() {
  18. // Register the Sentinel WebFlux filter.
  19. return new SentinelWebFluxFilter();
  20. }
  21. }

您可以在 WebFluxCallbackManager 注册回调进行定制:

  • setBlockHandler:注册函数用于实现自定义的逻辑处理被限流的请求,对应接口为 BlockRequestHandler。默认实现为 DefaultBlockRequestHandler,当被限流时会返回类似于下面的错误信息:Blocked by Sentinel: FlowException
  • setUrlCleaner:注册函数用于 Web 资源名的归一化。函数类型为 (ServerWebExchange, String) → String,对应含义为 (webExchange, originalUrl) → finalUrl
  • setRequestOriginParser:注册函数用于从请求中解析请求来源。函数类型为 ServerWebExchange → String

相关示例:

注:从 1.8.0 版本开始原生支持。若您的服务是 Spring Web 服务,可参考 Spring Web 适配文档接入。

Dubbo

Sentinel 提供 Dubbo 的相关适配 Sentinel Dubbo Adapter,主要包括针对 Service Provider 和 Service Consumer 实现的 Filter。相关模块:

  • sentinel-apache-dubbo-adapter(兼容 Apache Dubbo 2.7.x 及以上版本,自 Sentinel 1.5.1 开始支持)
  • sentinel-dubbo-adapter(兼容 Dubbo 2.6.x 版本)

对于 Apache Dubbo 2.7.x 及以上版本,使用时需引入以下模块(以 Maven 为例):

  1. <dependency>
  2. <groupId>com.alibaba.csp</groupId>
  3. <artifactId>sentinel-apache-dubbo-adapter</artifactId>
  4. <version>x.y.z</version>
  5. </dependency>

对于 Dubbo 2.6.x 及以下版本,使用时需引入以下模块(以 Maven 为例):

引入此依赖后,Dubbo 的服务接口和方法(包括调用端和服务端)就会成为 Sentinel 中的资源,在配置了规则后就可以自动享受到 Sentinel 的防护能力。

注:若希望接入 Dashboard,请参考 。只引入 Sentinel Dubbo Adapter 无法接入控制台!

若不希望开启 Sentinel Dubbo Adapter 中的某个 Filter,可以手动关闭对应的 Filter,比如:

  1. <!-- 关闭 Sentinel 对应的 Service Consumer Filter -->
  2. <dubbo:consumer filter="-sentinel.dubbo.consumer.filter"/>

限流粒度可以是服务接口和服务方法两种粒度:

  • 服务接口:resourceName 为 接口全限定名,如 com.alibaba.csp.sentinel.demo.dubbo.FooService
  • 服务方法:resourceName 为 接口全限定名:方法签名,如 com.alibaba.csp.sentinel.demo.dubbo.FooService:sayHello(java.lang.String)

Sentinel Dubbo Adapter 还支持配置全局的 fallback 函数,可以在 Dubbo 服务被限流/降级/负载保护的时候进行相应的 fallback 处理。用户只需要实现自定义的 DubboFallback 接口,并通过 DubboFallbackRegistry 注册即可。默认情况会直接将 BlockException 包装后抛出。同时,我们还可以配合 来为降级的服务提供替代的实现。

我们提供了 Dubbo 的相关示例,请见 sentinel-demo-dubbo

有关 Sentinel 在 Dubbo 中的最佳实践,请参考 。

关于 Dubbo Filter 的更多信息,请参考 Dubbo Filter 文档

gRPC

Sentinel 提供与 的整合,以 gRPC ServerInterceptor 和 的形式保护 gRPC 服务资源。使用时需引入以下模块(以 Maven 为例):

  1. <dependency>
  2. <groupId>com.alibaba.csp</groupId>
  3. <artifactId>sentinel-grpc-adapter</artifactId>
  4. <version>x.y.z</version>
  5. </dependency>

在使用 Sentinel gRPC Adapter 时,只需要将对应的 Interceptor 注册至对应的客户端或服务端中。其中客户端的示例如下:

  1. public class ServiceClient {
  2. private final ManagedChannel channel;
  3. ServiceClient(String host, int port) {
  4. this.channel = ManagedChannelBuilder.forAddress(host, port)
  5. .intercept(new SentinelGrpcClientInterceptor()) // 在此处注册拦截器
  6. // 在此处初始化客户端 stub 类
  7. }
  8. }

服务端的示例如下:

  1. import io.grpc.Server;
  2. Server server = ServerBuilder.forPort(port)
  3. .addService(new MyServiceImpl()) // 添加自己的服务实现
  4. .intercept(new SentinelGrpcServerInterceptor()) // 在此处注册拦截器

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

Feign

Feign 适配整合在 Spring Cloud Alibaba 中,可以参考 Spring Cloud Alibaba Sentinel 文档 进行接入。

从 1.7.2 版本开始,Sentinel 提供 SOFARPC 的适配模块 ,主要包括针对 Service Provider 和 Service Consumer 实现的 Filter。使用时需引入以下模块(以 Maven 为例):

  1. <dependency>
  2. <groupId>com.alibaba.csp</groupId>
  3. <artifactId>sentinel-sofa-rpc-adapter</artifactId>
  4. <version>x.y.z</version>
  5. </dependency>

引入此依赖后,Sentinel 会自动统计 SOFARPC 的服务接口和方法调用(包括调用端和服务端),在配置了规则后就可以自动享受到 Sentinel 的防护能力。

HTTP Client 适配

Apache HttpClient

Sentinel 提供 Apache HttpClient 的适配模块 sentinel-apache-httpclient-adapter,可以针对 HTTP client 请求进行流控和熔断。使用时需引入以下模块(以 Maven 为例):

  1. <dependency>
  2. <groupId>com.alibaba.csp</groupId>
  3. <artifactId>sentinel-apache-httpclient-adapter</artifactId>
  4. <version>x.y.z</version>
  5. </dependency>

注意目前暂不支持 AsyncHttpClient。

OkHttp

注:从 Sentinel 1.8.0 版本开始支持。

Sentinel 提供 OkHttp 的适配模块 ,可以针对 HTTP client 请求进行流控和熔断。使用时需引入以下模块(以 Maven 为例):

Reactive 适配

Reactor

Sentinel 提供 Reactor 的适配,可以方便地在 reactive 应用中接入 Sentinel。使用时需引入以下模块(以 Maven 为例):

  1. <dependency>
  2. <groupId>com.alibaba.csp</groupId>
  3. <artifactId>sentinel-reactor-adapter</artifactId>
  4. <version>x.y.z</version>
  5. </dependency>

Sentinel Reactor Adapter 分别针对 MonoFlux 实现了对应的 Sentinel Operator,从而在各种事件触发时汇入 Sentinel 的相关逻辑。同时 Sentinel 在上层提供了 SentinelReactorTransformer 用于在组装期装入对应的 operator,用户使用时只需要通过 transform 操作符来进行变换即可。接入示例:

  1. someService.doSomething() // return type: Mono<T> or Flux<T>
  2. .transform(new SentinelReactorTransformer<>(resourceName)) // 在此处进行变换
  3. .subscribe();

Sentinel 支持对 Spring Cloud Gateway、Zuul 等主流的 API Gateway 进行限流。

从 1.6.0 版本开始,Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:

  • route 维度:即在 Spring 配置文件中配置的路由条目,资源名为对应的 routeId
  • 自定义 API 维度:用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组

使用时需引入以下模块(以 Maven 为例):

  1. <dependency>
  2. <groupId>com.alibaba.csp</groupId>
  3. <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
  4. <version>x.y.z</version>
  5. </dependency>

使用时只需注入对应的 SentinelGatewayFilter 实例以及 SentinelGatewayBlockExceptionHandler 实例即可。比如:

  1. @Configuration
  2. public class GatewayConfiguration {
  3. private final List<ViewResolver> viewResolvers;
  4. private final ServerCodecConfigurer serverCodecConfigurer;
  5. public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
  6. ServerCodecConfigurer serverCodecConfigurer) {
  7. this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
  8. this.serverCodecConfigurer = serverCodecConfigurer;
  9. }
  10. @Bean
  11. @Order(Ordered.HIGHEST_PRECEDENCE)
  12. public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
  13. // Register the block exception handler for Spring Cloud Gateway.
  14. return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
  15. }
  16. @Bean
  17. @Order(-1)
  18. public GlobalFilter sentinelGatewayFilter() {
  19. return new SentinelGatewayFilter();
  20. }
  21. }

Demo 示例:

详细文档可以参考 网关限流 - Spring Cloud Gateway 文档

Zuul 1.x

Sentinel 提供了 Zuul 1.x 的适配模块,可以为 Zuul Gateway 提供两种资源维度的限流:

  • route 维度:即在 Spring 配置文件中配置的路由条目,资源名为对应的 route ID(对应 RequestContext 中的 proxy 字段)
  • 自定义 API 维度:用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组

使用时需引入以下模块(以 Maven 为例):

  1. <dependency>
  2. <groupId>com.alibaba.csp</groupId>
  3. <artifactId>sentinel-zuul-adapter</artifactId>
  4. <version>x.y.z</version>
  5. </dependency>

详细文档可以参考 。

如果您正在使用 Spring Cloud Zuul Starter,那么可以通过引入 spring-cloud-alibaba-sentinel-zuul 来更方便地整合 Sentinel。请参考 对应文档

Zuul 2.x

Sentinel 提供了 Zuul 2.x 的适配模块,可以为 Zuul Gateway 提供两种资源维度的限流:

  • route 维度:对应 SessionContext 中的 routeVIP
  • 自定义 API 维度:用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组

使用时需引入以下模块(以 Maven 为例):

  1. <dependency>
  2. <groupId>com.alibaba.csp</groupId>
  3. <artifactId>sentinel-zuul2-adapter</artifactId>
  4. <version>x.y.z</version>

详细文档可以参考 。

在 Apache RocketMQ 中,当消费者去消费消息的时候,无论是通过 pull 的方式还是 push 的方式,都可能会出现大批量的消息突刺。如果此时要处理所有消息,很可能会导致系统负载过高,影响稳定性。但其实可能后面几秒之内都没有消息投递,若直接把多余的消息丢掉则没有充分利用系统处理消息的能力。我们希望可以把消息突刺均摊到一段时间内,让系统负载保持在消息处理水位之下的同时尽可能地处理更多消息,从而起到“削峰填谷”的效果:

上图中红色的部分代表超出消息处理能力的部分。我们可以看到消息突刺往往都是瞬时的、不规律的,其后一段时间系统往往都会有空闲资源。我们希望把红色的那部分消息平摊到后面空闲时去处理,这样既可以保证系统负载处在一个稳定的水位,又可以尽可能地处理更多消息。Sentinel 专门为这种场景提供了匀速器的特性,可以把突然到来的大量请求以匀速的形式均摊,以固定的间隔时间让请求通过,以稳定的速度逐步处理这些请求,起到“削峰填谷”的效果,从而避免流量突刺造成系统负载过高。同时堆积的请求将会排队,逐步进行处理;当请求排队预计超过最大超时时长的时候则直接拒绝,而不是拒绝全部请求。

比如在 RocketMQ 的场景下配置了匀速模式下请求 QPS 为 5,则会每 200 ms 处理一条消息,多余的处理任务将排队;同时设置了超时时间为 5 s,预计排队时长超过 5 s 的处理任务将会直接被拒绝。示意图如下图所示:

Uniform rate

RocketMQ 用户可以根据不同的 group 和不同的 topic 分别设置限流规则,限流控制模式设置为匀速器模式(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER),比如:

结合 RocketMQ Client 使用 Sentinel 时,用户需要在处理消息时手动埋点。详情请见 。相关 Blog 见 Sentinel 为 RocketMQ 保驾护航