Spring Cloud 阿里哨兵

陈浩
2023-12-01

Spring Cloud 阿里哨兵

哨兵简介

随着微服务的普及,服务调用的稳定性变得越来越重要。Sentinel以“流量”为切入点,在流量控制、断路、负载保护等多个领域开展业务,保障业务可靠性。

哨兵具有以下特点:

  • 丰富场景:Sentinel 支持阿里巴巴双十一重点场景,如秒杀(即控制突发流量,使其在系统容量可接受范围内)、消息负载转移、不可靠的下游应用的断路。
  • 全面的实时监控: Sentinel 提供实时监控能力。您可以看到您的服务器的监控数据,精确到秒级,甚至可以看到少于 500 个节点的集群的整体运行状态。
  • 广泛的开源生态系统: Sentinel 提供开箱即用的模块,可以轻松与其他开源框架/库集成,例如 Spring Cloud、Dubbo 和 gRPC。使用 Sentinel,只需要引入相关依赖并做一些简单的配置即可。
  • Sound SPI Extensions: Sentinel 提供简单易用的声音 SPI 扩展接口。您可以使用 SPI 扩展快速自定义逻辑,例如,您可以定义自己的规则管理,或适应特定的数据源。

如何使用哨兵

如果您想在项目中使用 Sentinel,请使用组 ID 为com.alibaba.cloud和工件 ID 为的启动器spring-cloud-starter-alibaba-sentinel

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

以下是如何使用 Sentinel 的简单示例:

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(ServiceApplication.class, args);
    }

}

@RestController
public class TestController {

    @GetMapping(value = "/hello")
    @SentinelResource("hello")
    public String hello() {
        return "Hello Sentinel";
    }

}

@SentinelResource 注释用于识别资源是速率限制还是降级。在上面的示例中,注解的 ‘hello’ 属性指的是资源名称。

@SentinelResource还提供了属性,例如blockHandlerblockHandlerClass,和fallback,以确定速率限制或降解操作。有关更多详细信息,请参阅 Sentinel 注释支持

上面的例子都是在WebServlet环境中使用的。Sentinel目前支持WebFlux,需要配合spring-boot-starter-webflux依赖在sentinel starter中触发WebFlux相关的自动化配置。

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(ServiceApplication.class, args);
    }

}

@RestController
public class TestController {

    @GetMapping("/mono")
    @SentinelResource("hello")
    public Mono<String> mono() {
	return Mono.just("simple string")
			.transform(new SentinelReactorTransformer<>("otherResourceName"));
    }

}
哨兵仪表板

Sentinel仪表板是一个轻量级控制台,提供机器发现、单机资源监控、集群资源数据概览、规则管理等功能。要使用这些功能,您只需完成几个步骤。

注意:集群的统计概览仅支持节点数少于 500 的集群,延迟大约为 1 到 2 秒。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NGKANDS2-1644989237558)(https://github.com/alibaba/Sentinel/wiki/image/dashboard.png)]

图 3. Sentinel 仪表板

要使用 Sentinel 仪表板,只需完成以下 3 个步骤。

获取仪表板

您可以从Release Page下载最新的仪表板 JAR 文件。

您还可以获得最新的源代码来构建自己的 Sentinel 仪表板:

  • 下载 仪表板项目。
  • 运行以下命令将代码打包成 FatJar:mvn clean package
启动仪表板

Sentinel 仪表板是一个标准的 SpringBoot 应用程序,您可以在 Spring Boot 模式下运行 JAR 文件。

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

如果与 8080 端口有冲突,可以使用-Dserver.port=new port定义一个新的端口。

配置仪表板

应用程序.yml

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

中指定的端口号spring.cloud.sentinel.transport.port将在应用程序的相应服务器上启动一个 HTTP Server,该服务器将与 Sentinel 仪表板交互。例如,如果在 Sentinel 仪表板中添加了限速规则,则规则数据将被 HTTP 服务器推送和接收,然后将规则注册到 Sentinel。

有关 Sentinel 仪表板的更多信息,请参阅Sentinel 仪表板

OpenFeign 支持

Sentinel 与OpenFeign组件兼容。要使用它,除了引入sentinel-starter依赖外,还要完成以下2个步骤:

  • 在属性文件中启用对 feign 的 Sentinel 支持。feign.sentinel.enabled=true
  • 添加openfeign starter依赖以触发和启用sentinel starter
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

这是一个简单的用法FeignClient

@FeignClient(name = "service-provider", fallback = EchoServiceFallback.class, configuration = FeignConfiguration.class)
public interface EchoService {
    @GetMapping(value = "/echo/{str}")
    String echo(@PathVariable("str") String str);
}

class FeignConfiguration {
    @Bean
    public EchoServiceFallback echoServiceFallback() {
        return new EchoServiceFallback();
    }
}

class EchoServiceFallback implements EchoService {
    @Override
    public String echo(@PathVariable("str") String str) {
        return "echo fallback";
    }
}

接口中echo方法对应的资源名称EchoServiceGET:http://service-provider/echo/{str}.

RestTemplate 支持

Spring Cloud Alibaba Sentinel 支持使用 Sentinel 保护RestTemplate服务调用。为此,您需要在构造bean@SentinelRestTemplate时添加注解。RestTemplate

@Bean
@SentinelRestTemplate(blockHandler = "handleException", blockHandlerClass = ExceptionUtil.class)
public RestTemplate restTemplate() {
    return new RestTemplate();
}

@SentinelRestTemplate注解的属性支持流控( blockHandler, blockHandlerClass)和断路(fallback, fallbackClass)。

blockHandlerorfallback是 or 的blockHandlerClass静态方法fallbackClass

方法 in 的参数和返回值与@SentinelRestTemplate相同org.springframework.http.client.ClientHttpRequestInterceptor#interceptor,但多了一个参数BlockException,用于 Sentinel 捕获异常。

上面的方法签名应该handleExceptionExceptionUtil这样的:

public class ExceptionUtil {
    public static ClientHttpResponse handleException(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException exception) {
        ...
    }
}

@SentinelRestTemplate注释的属性是可选的。

RestTemplate request block by sentinel当您使用RestTemplate被 Sentinel 阻止时,它将返回。你可以用你自己的逻辑覆盖它。我们提供SentinelClientHttpResponse处理响应。

Sentinel RestTemplate 为资源速率限制提供了两种粒度:

  • httpmethod:schema://host:port/path: 协议、主机、端口和路径
  • httpmethod:schema://host:port: 协议、主机和端口

动态数据源支持

SentinelProperties提供datasource属性来配置数据源。

例如配置4个数据源:

spring.cloud.sentinel.datasource.ds1.file.file=classpath: degraderule.json
spring.cloud.sentinel.datasource.ds1.file.rule-type=flow

#spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json
#spring.cloud.sentinel.datasource.ds1.file.data-type=custom
#spring.cloud.sentinel.datasource.ds1.file.converter-class=JsonFlowRuleListConverter
#spring.cloud.sentinel.datasource.ds1.file.rule-type=flow

spring.cloud.sentinel.datasource.ds2.nacos.server-addr=localhost:8848
spring.cloud.sentinel.datasource.ds2.nacos.data-id=sentinel
spring.cloud.sentinel.datasource.ds2.nacos.group-id=DEFAULT_GROUP
spring.cloud.sentinel.datasource.ds2.nacos.data-type=json
spring.cloud.sentinel.datasource.ds2.nacos.rule-type=degrade

spring.cloud.sentinel.datasource.ds3.zk.path = /Sentinel-Demo/SYSTEM-CODE-DEMO-FLOW
spring.cloud.sentinel.datasource.ds3.zk.server-addr = localhost:2181
spring.cloud.sentinel.datasource.ds3.zk.rule-type=authority

spring.cloud.sentinel.datasource.ds4.apollo.namespace-name = application
spring.cloud.sentinel.datasource.ds4.apollo.flow-rules-key = sentinel
spring.cloud.sentinel.datasource.ds4.apollo.default-flow-rule-value = test
spring.cloud.sentinel.datasource.ds4.apollo.rule-type=param-flow

该方法遵循 Spring Cloud Stream Binder 的配置。TreeMap用于内部存储,比较器为String.CASE_INSENSITIVE_ORDER.

d1, ds2, ds3, ds4 是 的名称ReadableDataSource,可以任意编码。, file, zk,指的是具体的数据源nacosapollo后面的配置分别是这些数据源的具体配置。

每个数据源都有 3 个常见的配置项data-typeconverter-classrule-type

data-typeConverter. Spring Cloud Alibaba Sentinel 默认提供了两个嵌入值:jsonxml(不指定默认为 json)。如果不想使用内嵌json或者xml Converter,也可以填写,custom表示自己定义Converter,然后配置converter-class。您需要为此配置指定类的完整路径。

rule-type指数据源中的规则类型( flowdegradeauthoritysystem, param-flow, gw-flow, gw-api-group)。

默认情况下不支持 XML 格式。要使其生效,您需要添加 jackson-dataformat-xml依赖项。

要了解有关 Sentinel 中动态数据源如何工作的更多信息,请参阅动态规则扩展

支持zuul

参考API 网关流控

如果要在 Zuul 中使用 Sentinel Starter,需要添加spring-cloud-alibaba-sentinel-gateway依赖,并且需要添加spring-cloud-starter-netflix-zuul依赖才能让网关模块中的 Zuul AutoConfiguration 类生效:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

支持 Spring Cloud 网关

参考API 网关流控

如果要在 Spring Cloud Gateway 中使用 Sentinel Starter,需要添加spring-cloud-alibaba-sentinel-gateway依赖,添加spring-cloud-starter-gateway依赖才能让模块中的 Spring Cloud Gateway AutoConfiguration 类生效:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

断路器:带有 Sentinel 和配置 Sentinel 断路器的 Spring Cloud 断路器

默认配置

要为所有断路器提供默认配置,请创建一个Customizer传递 SentinelCircuitBreakerFactoryReactiveSentinelCircuitBreakerFactory. 该configureDefault方法可用于提供默认配置。

@Bean
public Customizer<SentinelCircuitBreakerFactory> defaultCustomizer() {
	return factory -> factory.configureDefault(id -> new SentinelConfigBuilder(id)
			.build());
}

您可以选择通过 提供默认熔断规则SentinelConfigBuilder#rules(rules)。您还可以选择稍后使用DegradeRuleManager.loadRules(rules)Sentinel 的 API 或通过 Sentinel 仪表板在其他地方加载断路规则 。

反应式示例
@Bean
public Customizer<ReactiveSentinelCircuitBreakerFactory> defaultCustomizer() {
	return factory -> factory.configureDefault(id -> new SentinelConfigBuilder(id)
			.build());
}

特定的断路器配置

与提供默认配置类似,您可以创建一个Customizer传递给 SentinelCircuitBreakerFactory.

@Bean
public Customizer<SentinelCircuitBreakerFactory> slowCustomizer() {
	String slowId = "slow";
	List<DegradeRule> rules = Collections.singletonList(
		new DegradeRule(slowId).setGrade(RuleConstant.DEGRADE_GRADE_RT)
			.setCount(100)
			.setTimeWindow(10)
		);
	return factory -> factory.configure(builder -> builder.rules(rules), slowId);
}
反应式示例
@Bean
public Customizer<ReactiveSentinelCircuitBreakerFactory> customizer() {
	List<DegradeRule> rules = Collections.singletonList(
		new DegradeRule().setGrade(RuleConstant.DEGRADE_GRADE_RT)
			.setCount(100)
			.setTimeWindow(10)
		);
	return factory -> factory.configure(builder -> builder.rules(rules), "foo", "bar");
}

哨兵端点

Sentinel 在内部提供一个 Endpoint,其对应的端点 id 为sentinel.

端点暴露的 json 包含多个属性:

  1. appName:应用程序名称
  2. logDir:日志的目录
  3. logUsePid:没有 pid 的日志名称
  4. blockPage:标记块后重定向页面
  5. metricsFileSize:指标文件的大小
  6. metricsFileCharset:指标文件字符集
  7. totalMetricsFileCount:metrics文件的总文件数
  8. consoleServer:哨兵仪表板地址
  9. 客户端IP:客户端IP
  10. heartbeatIntervalMs:带有仪表板的客户端心跳间隔
  11. clientPort:客户端需要暴露端口才能与仪表板交互
  12. 冷因子:冷因子
  13. filter:CommonFilter 相关属性,例如 order、urlPatterns 和 enable
  14. 数据源:客户端的数据源配置信息
  15. rules:客户端内部生效的规则包含flowRules、degradeRules、systemRules、authorityRule、paramFlowRule

以下显示了服务实例如何访问 Endpoint:

{
	"blockPage": null,
	"appName": "sentinel-example",
	"consoleServer": "localhost:8080",
	"coldFactor": "3",
	"rules": {
		"flowRules": [{
			"resource": "GET:http://www.taobao.com",
			"limitApp": "default",
			"grade": 1,
			"count": 0.0,
			"strategy": 0,
			"refResource": null,
			"controlBehavior": 0,
			"warmUpPeriodSec": 10,
			"maxQueueingTimeMs": 500,
			"clusterMode": false,
			"clusterConfig": null
		}, {
			"resource": "/test",
			"limitApp": "default",
			"grade": 1,
			"count": 0.0,
			"strategy": 0,
			"refResource": null,
			"controlBehavior": 0,
			"warmUpPeriodSec": 10,
			"maxQueueingTimeMs": 500,
			"clusterMode": false,
			"clusterConfig": null
		}, {
			"resource": "/hello",
			"limitApp": "default",
			"grade": 1,
			"count": 1.0,
			"strategy": 0,
			"refResource": null,
			"controlBehavior": 0,
			"warmUpPeriodSec": 10,
			"maxQueueingTimeMs": 500,
			"clusterMode": false,
			"clusterConfig": null
		}]
	},
	"metricsFileCharset": "UTF-8",
	"filter": {
		"order": -2147483648,
		"urlPatterns": ["/*"],
		"enabled": true
	},
	"totalMetricsFileCount": 6,
	"datasource": {
		"ds1": {
			"file": {
				"dataType": "json",
				"ruleType": "FLOW",
				"converterClass": null,
				"file": "...",
				"charset": "utf-8",
				"recommendRefreshMs": 3000,
				"bufSize": 1048576
			},
			"nacos": null,
			"zk": null,
			"apollo": null,
			"redis": null
		}
	},
	"clientIp": "30.5.121.91",
	"clientPort": "8719",
	"logUsePid": false,
	"metricsFileSize": 52428800,
	"logDir": "...",
	"heartbeatIntervalMs": 10000
}

配置

下表显示,当 中存在对应的 bean 类型时ApplicationContext,会采取一些动作:

现有 Bean 类型行动功能
UrlCleanerWebCallbackManager.setUrlCleaner(urlCleaner)资源清理(resource(例如,将/foo/:id的所有URL归类到/foo/*资源))
UrlBlockHandlerWebCallbackManager.setUrlBlockHandler(urlBlockHandler)自定义限速逻辑
RequestOriginParserWebCallbackManager.setRequestOriginParser(requestOriginParser)设置原点

Spring Cloud Alibaba Sentinel 的所有配置如下表所示:

配置描述默认值
spring.application.name 或者 project.name哨兵项目名称
spring.cloud.sentinel.enabledSentinel 自动配置是否生效真的
spring.cloud.sentinel.eager是否提前触发 Sentinel 初始化错误的
spring.cloud.sentinel.transport.port应用程序与 Sentinel 仪表板交互的端口。使用此端口的 HTTP 服务器将在应用程序中启动8719
spring.cloud.sentinel.transport.dashboardSentinel 仪表板地址
spring.cloud.sentinel.transport.heartbeatIntervalMs应用程序和 Sentinel 仪表板之间的检测信号间隔
spring.cloud.sentinel.transport.client-ip此配置的客户端 IP 将注册到 Sentinel Server 端。
spring.cloud.sentinel.filter.orderServlet过滤器的加载顺序。过滤器将在 Starter 中构建整数.MIN_VALUE
spring.cloud.sentinel.filter.url-patterns数据类型为数组。指 Servlet Filter ULR 模式的集合/*
spring.cloud.sentinel.filter.enabled启用实例 CommonFilter真的
spring.cloud.sentinel.metric.charset度量文件字符集UTF-8
spring.cloud.sentinel.metric.fileSingleSizeSentinel metric 单个文件大小
spring.cloud.sentinel.metric.fileTotalCount哨兵指标总文件数
spring.cloud.sentinel.log.dirSentinel 日志文件目录
spring.cloud.sentinel.log.switch-pid如果 Sentinel 日志文件名需要 PID错误的
spring.cloud.sentinel.servlet.blockPage自定义重定向 URL。当速率受限时,请求将被重定向到预定义的 URL
spring.cloud.sentinel.flow.coldFactor冷因子3
spring.cloud.sentinel.zuul.order.preSentinelZuulPreFilter 的顺序10000
spring.cloud.sentinel.zuul.order.postSentinelZuulPostFilter 的顺序1000
spring.cloud.sentinel.zuul.order.errorSentinelZuulErrorFilter 的顺序-1
spring.cloud.sentinel.scg.fallback.modeSpring Cloud Gateway 断路后的响应方式(选择redirectresponse
spring.cloud.sentinel.scg.fallback.redirectSpring Cloud Gateway 响应方式为 ‘redirect’ 方式对应的重定向 URL
spring.cloud.sentinel.scg.fallback.response-bodySpring Cloud Gateway 响应模式为响应模式对应的响应内容
spring.cloud.sentinel.scg.fallback.response-statusSpring Cloud Gateway 响应模式为’response’模式对应的响应码429
spring.cloud.sentinel.scg.fallback.content-typeSpring Cloud Gateway 响应模式是与“响应”模式对应的内容类型。应用程序/json
 类似资料: