Sentinel高级特性与最佳实践
Sentinel高级特性与最佳实践
导读
本文将深入探讨Sentinel的高级特性和最佳实践,包括规则持久化、集群流量控制、网关限流、与其他组件的集成等内容,帮助你更好地使用Sentinel保障微服务的稳定性。
规则持久化
规则持久化的必要性
Sentinel的规则默认存储在内存中,这意味着当应用重启后,规则将会丢失。在生产环境中,我们需要将规则持久化,以便在应用重启后能够自动加载规则。
Sentinel支持多种规则持久化的方式:
- 文件配置:将规则保存到本地文件中
- 数据库存储:将规则保存到数据库中
- 配置中心:将规则保存到配置中心(如Nacos、Apollo、Zookeeper等)
规则持久化的实现方式
基于文件的规则持久化
基于文件的规则持久化是最简单的方式,但在分布式环境中不太适用。以下是一个简单的实现:
public class FileDataSourceInit implements InitFunc {
@Override
public void init() throws Exception {
// 规则读取
ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new FileRefreshableDataSource<>(
"sentinel-flow-rules.json",
source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {})
);
// 注册数据源
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
// 规则写入
WritableDataSource<List<FlowRule>> writableDataSource = new FileWritableDataSource<>(
"sentinel-flow-rules.json",
this::encodeJson
);
// 注册写数据源
WritableDataSourceRegistry.registerFlowDataSource(writableDataSource);
}
private <T> String encodeJson(T t) {
return JSON.toJSONString(t);
}
}
然后在resources/META-INF/services/
目录下创建文件com.alibaba.csp.sentinel.init.InitFunc
,内容为:
com.example.sentinel.config.FileDataSourceInit
基于Nacos的规则持久化
Nacos是一个更适合分布式环境的配置中心,下面是基于Nacos的规则持久化实现:
- 添加依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
- 配置Nacos数据源
spring:
cloud:
sentinel:
datasource:
flow:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-flow-rules
groupId: SENTINEL_GROUP
rule-type: flow
degrade:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-degrade-rules
groupId: SENTINEL_GROUP
rule-type: degrade
system:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-system-rules
groupId: SENTINEL_GROUP
rule-type: system
authority:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-authority-rules
groupId: SENTINEL_GROUP
rule-type: authority
param-flow:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-param-flow-rules
groupId: SENTINEL_GROUP
rule-type: param-flow
- 在Nacos中创建配置
在Nacos控制台创建对应的配置,例如流控规则的配置:
[
{
"resource": "getProducts",
"limitApp": "default",
"grade": 1,
"count": 10,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
},
{
"resource": "getProductById",
"limitApp": "default",
"grade": 1,
"count": 50,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
基于Apollo的规则持久化
Apollo也是一个优秀的配置中心,下面是基于Apollo的规则持久化实现:
- 添加依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-apollo</artifactId>
</dependency>
- 配置Apollo数据源
spring:
cloud:
sentinel:
datasource:
flow:
apollo:
namespace-name: application
flow-rules-key: sentinel.flow.rules
rule-type: flow
degrade:
apollo:
namespace-name: application
flow-rules-key: sentinel.degrade.rules
rule-type: degrade
- 在Apollo中创建配置
在Apollo控制台创建对应的配置,格式与Nacos类似。
规则持久化的最佳实践
选择合适的持久化方式:在生产环境中,推荐使用配置中心(如Nacos、Apollo)进行规则持久化,这样可以实现规则的集中管理和动态更新。
规则变更的审计:对规则的变更进行审计,记录谁在什么时间修改了什么规则,以便追溯问题。
规则的版本控制:对规则进行版本控制,以便在规则出现问题时能够快速回滚。
规则的分环境管理:不同环境(开发、测试、生产)的规则应该分开管理,避免互相影响。
规则的备份:定期备份规则,以防配置中心出现问题。
集群流量控制
集群流量控制的概念
在分布式环境中,单机的流量控制可能无法满足需求,例如:
- 需要对整个集群的某个资源做统一的流量控制
- 需要根据集群的负载情况动态调整流量分配
Sentinel提供了集群流量控制的功能,可以实现:
- 集群总体流量控制:限制整个集群对某个资源的访问总量
- 集群均匀流量控制:将流量均匀分配到集群中的每个节点
- 集群自适应流量控制:根据节点的负载情况动态调整流量分配
集群流量控制的架构
Sentinel的集群流量控制分为两种模式:
- 独立模式(Alone):不依赖任何第三方组件,但需要在集群中选择一个节点作为Token Server,其他节点作为Token Client。
- 嵌入模式(Embedded):将Token Server嵌入到应用中,每个应用既是Token Server又是Token Client。

集群流量控制的实现
独立模式的实现
- 启动Token Server
public class SentinelTokenServer {
public static void main(String[] args) throws Exception {
// 创建一个ClusterTokenServer的实例
ClusterTokenServer tokenServer = new SentinelClusterTokenServer();
// 设置传输配置
ClusterServerTransportConfig transportConfig = new ClusterServerTransportConfig()
.setIdleSeconds(600)
.setPort(11111);
// 设置集群服务配置
ClusterServerConfigManager.loadGlobalTransportConfig(transportConfig);
// 设置命名空间
ClusterServerConfigManager.loadServerNamespaceSet(Collections.singleton("app-a"));
// 设置集群规则
ClusterFlowRuleManager.loadRules(Collections.singleton(new FlowRule("resource-a")
.setCount(10)
.setGrade(RuleConstant.FLOW_GRADE_QPS)
.setClusterMode(true)
.setClusterConfig(new ClusterFlowConfig()
.setFlowId("resource-a-flow-id")
.setThresholdType(ClusterRuleConstant.FLOW_THRESHOLD_GLOBAL)
)));
// 启动服务器
tokenServer.start();
}
}
- 配置Token Client
public class SentinelTokenClient {
public static void main(String[] args) throws Exception {
// 创建一个ClusterTokenClient的实例
ClusterTokenClient tokenClient = new SentinelClusterTokenClient();
// 设置传输配置
ClusterClientTransportConfig transportConfig = new ClusterClientTransportConfig()
.setServerHost("localhost")
.setServerPort(11111);
// 设置集群客户端配置
ClusterClientConfigManager.applyNewConfig(transportConfig);
// 设置命名空间
ClusterClientConfigManager.loadServerNamespaceSet(Collections.singleton("app-a"));
// 启动客户端
tokenClient.start();
// 注册客户端到TokenService
TokenServiceProvider.setInstance(tokenClient);
}
}
嵌入模式的实现
在嵌入模式下,每个应用既是Token Server又是Token Client,需要通过配置来指定哪些节点作为Server,哪些节点作为Client。
public class SentinelEmbeddedCluster {
public static void main(String[] args) throws Exception {
// 创建一个ClusterStateManager的实例
ClusterStateManager stateManager = new ClusterStateManager();
// 设置当前节点的角色
stateManager.applyState(ClusterStateManager.CLUSTER_SERVER);
// 设置传输配置
ClusterServerTransportConfig transportConfig = new ClusterServerTransportConfig()
.setIdleSeconds(600)
.setPort(11111);
// 设置集群服务配置
ClusterServerConfigManager.loadGlobalTransportConfig(transportConfig);
// 设置命名空间
ClusterServerConfigManager.loadServerNamespaceSet(Collections.singleton("app-a"));
// 设置集群规则
ClusterFlowRuleManager.loadRules(Collections.singleton(new FlowRule("resource-a")
.setCount(10)
.setGrade(RuleConstant.FLOW_GRADE_QPS)
.setClusterMode(true)
.setClusterConfig(new ClusterFlowConfig()
.setFlowId("resource-a-flow-id")
.setThresholdType(ClusterRuleConstant.FLOW_THRESHOLD_GLOBAL)
)));
}
}
集群流量控制的最佳实践
选择合适的模式:根据实际需求选择独立模式或嵌入模式。如果集群规模较大,建议使用独立模式,将Token Server部署在专门的机器上。
高可用部署:Token Server应该进行高可用部署,避免单点故障。
监控和告警:对Token Server进行监控,及时发现和处理异常情况。
合理设置超时时间:设置合理的请求超时时间,避免因网络问题导致请求堆积。
定期检查集群状态:定期检查集群中各节点的状态,确保集群正常运行。
网关限流
网关限流的概念
在微服务架构中,API网关是所有请求的入口,对网关进行限流可以有效保护后端服务。Sentinel支持与Spring Cloud Gateway和Zuul等网关进行集成,实现网关层的限流。
与Spring Cloud Gateway集成
- 添加依赖
<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>
- 配置网关路由
spring:
cloud:
gateway:
routes:
- id: product-service
uri: lb://product-service
predicates:
- Path=/products/**
- id: order-service
uri: lb://order-service
predicates:
- Path=/orders/**
- 配置网关限流规则
@Configuration
public class GatewayConfiguration {
@PostConstruct
public void initGatewayRules() {
Set<GatewayFlowRule> rules = new HashSet<>();
// 针对路由ID限流
rules.add(new GatewayFlowRule("product-service")
.setCount(10)
.setIntervalSec(1)
);
// 针对API分组限流
rules.add(new GatewayFlowRule("product_api_group")
.setCount(20)
.setIntervalSec(1)
);
GatewayRuleManager.loadRules(rules);
// 配置API分组
Set<ApiDefinition> apis = new HashSet<>();
ApiDefinition api = new ApiDefinition("product_api_group")
.setPredicateItems(new HashSet<ApiPredicateItem>() {{
add(new ApiPathPredicateItem().setPattern("/products/**")
.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
apis.add(api);
GatewayApiDefinitionManager.loadApiDefinitions(apis);
}
}
- 自定义异常处理
@Configuration
public class GatewayConfiguration {
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
@Bean
@Order(-1)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
@Resource
private List<ViewResolver> viewResolvers;
@Resource
private ServerCodecConfigurer serverCodecConfigurer;
}
与Zuul集成
- 添加依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-zuul-adapter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
- 配置Zuul路由
zuul:
routes:
product-service:
path: /products/**
serviceId: product-service
order-service:
path: /orders/**
serviceId: order-service
- 配置Zuul限流规则
@Configuration
public class ZuulConfiguration {
@PostConstruct
public void initZuulRules() {
Set<ZuulGatewayFlowRule> rules = new HashSet<>();
// 针对路由ID限流
rules.add(new ZuulGatewayFlowRule("product-service")
.setCount(10)
.setIntervalSec(1)
);
// 针对API分组限流
rules.add(new ZuulGatewayFlowRule("product_api_group")
.setCount(20)
.setIntervalSec(1)
);
ZuulGatewayRuleManager.loadRules(rules);
// 配置API分组
Set<ApiDefinition> apis = new HashSet<>();
ApiDefinition api = new ApiDefinition("product_api_group")
.setPredicateItems(new HashSet<ApiPredicateItem>() {{
add(new ApiPathPredicateItem().setPattern("/products/**")
.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
apis.add(api);
ZuulGatewayApiDefinitionManager.loadApiDefinitions(apis);
}
@Bean
public ZuulFilter sentinelZuulPreFilter() {
return new SentinelZuulPreFilter();
}
@Bean
public ZuulFilter sentinelZuulPostFilter() {
return new SentinelZuulPostFilter();
}
@Bean
public ZuulFilter sentinelZuulErrorFilter() {
return new SentinelZuulErrorFilter();
}
}
网关限流的最佳实践
分层限流:在网关层和服务层都进行限流,形成多层防护。
根据业务场景设置限流规则:不同的业务场景需要不同的限流规则,例如登录接口和查询接口的限流规则应该不同。
结合熔断降级:限流和熔断降级结合使用,形成更完善的保护机制。
监控和告警:对限流情况进行监控,及时发现和处理异常情况。
动态调整限流规则:根据实际情况动态调整限流规则,例如在促销活动期间适当放宽限流。
与其他组件的集成
与Spring Cloud的集成
Sentinel可以与Spring Cloud的多个组件进行集成,实现更全面的微服务保护。
与Spring Cloud OpenFeign集成
- 添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
- 配置Feign支持Sentinel
feign:
sentinel:
enabled: true
- 创建Feign接口和Fallback类
@FeignClient(name = "product-service", fallback = ProductServiceFallback.class)
public interface ProductService {
@GetMapping("/products")
List<Product> getProducts();
@GetMapping("/products/{id}")
Product getProductById(@PathVariable("id") Long id);
}
@Component
public class ProductServiceFallback implements ProductService {
@Override
public List<Product> getProducts() {
return Collections.emptyList();
}
@Override
public Product getProductById(Long id) {
return new Product();
}
}
与Spring Cloud LoadBalancer集成
- 添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
- 配置LoadBalancer
@Configuration
public class LoadBalancerConfiguration {
@Bean
public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(
Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new SentinelLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class));
}
}
与Dubbo的集成
Sentinel也可以与Dubbo进行集成,实现对Dubbo服务的保护。
- 添加依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-apache-dubbo-adapter</artifactId>
</dependency>
- 配置Dubbo Filter
在resources/META-INF/dubbo/
目录下创建文件org.apache.dubbo.rpc.Filter
,内容为:
sentinel.dubbo.provider.filter=com.alibaba.csp.sentinel.adapter.dubbo.SentinelDubboProviderFilter
sentinel.dubbo.consumer.filter=com.alibaba.csp.sentinel.adapter.dubbo.SentinelDubboConsumerFilter
- 配置Dubbo服务的限流规则
public class DubboConfiguration {
@PostConstruct
public void initDubboRules() {
FlowRule rule = new FlowRule();
rule.setResource("org.apache.dubbo.demo.DemoService:sayHello(java.lang.String)");
rule.setCount(10);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
FlowRuleManager.loadRules(Collections.singletonList(rule));
}
}
与gRPC的集成
Sentinel也支持与gRPC进行集成,实现对gRPC服务的保护。
- 添加依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-grpc-adapter</artifactId>
</dependency>
- 配置gRPC拦截器
public class GrpcConfiguration {
@Bean
public ServerInterceptor sentinelGrpcServerInterceptor() {
return new SentinelGrpcServerInterceptor();
}
@Bean
public ClientInterceptor sentinelGrpcClientInterceptor() {
return new SentinelGrpcClientInterceptor();
}
}
- 配置gRPC服务的限流规则
public class GrpcConfiguration {
@PostConstruct
public void initGrpcRules() {
FlowRule rule = new FlowRule();
rule.setResource("grpc:org.example.grpc.HelloService:sayHello");
rule.setCount(10);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
FlowRuleManager.loadRules(Collections.singletonList(rule));
}
}
最佳实践
资源命名规范
资源是Sentinel的核心概念,合理的资源命名可以使规则更加清晰和易于管理。
使用有意义的名称:资源名称应该能够清晰地表达资源的含义,例如
user-service:getUserById
。使用层次结构:使用层次结构来组织资源,例如
service:method
或module:service:method
。保持一致性:在整个项目中保持资源命名的一致性,避免混淆。
避免特殊字符:资源名称应该避免使用特殊字符,以免造成解析错误。
规则配置策略
合理的规则配置可以使系统更加稳定和高效。
根据业务场景设置规则:不同的业务场景需要不同的规则,例如核心接口和非核心接口的规则应该不同。
逐步调整规则:规则的设置应该是一个逐步调整的过程,根据实际情况不断优化。
考虑系统容量:规则的设置应该考虑系统的实际容量,避免过度限流或过度放行。
结合监控数据:根据监控数据来调整规则,使规则更加符合实际情况。
异常处理策略
合理的异常处理可以提高系统的用户体验。
提供友好的错误信息:当请求被限流或降级时,应该提供友好的错误信息,告诉用户发生了什么以及如何处理。
记录异常日志:对限流和降级的情况进行日志记录,以便后续分析和优化。
设置合理的超时时间:设置合理的请求超时时间,避免因网络问题导致请求堆积。
实现优雅降级:当系统负载过高时,应该实现优雅降级,保证核心功能的可用性。
监控和告警
监控和告警是保障系统稳定运行的重要手段。
实时监控:对系统的各项指标进行实时监控,及时发现异常情况。
设置合理的告警阈值:设置合理的告警阈值,避免过多的误报或漏报。
分级告警:根据异常的严重程度进行分级告警,不同级别的异常采取不同的处理方式。
定期分析:定期分析监控数据,发现潜在的问题并进行优化。
性能优化
性能优化是提高系统吞吐量和响应时间的重要手段。
减少不必要的资源定义:只对需要保护的资源进行定义,避免过多的资源定义导致性能下降。
使用异步处理:对于非核心操作,可以使用异步处理,减少主流程的响应时间。
合理设置线程池:根据系统的实际情况合理设置线程池的大小,避免线程池过大或过小。
使用缓存:对于频繁访问的数据,可以使用缓存来减少对后端服务的访问。
常见问题
注意事项
- 规则持久化:默认情况下,规则存储在内存中,应用重启后会丢失,建议配置规则持久化
- 集群流量控制:集群流量控制需要额外的配置和部署,确保正确设置
- 网关限流:网关限流需要与特定的网关组件集成,确保依赖和配置正确
1. 如何解决规则持久化的问题?
可能的原因和解决方案:
- 确保正确配置了数据源
- 检查配置中心(如Nacos、Apollo)是否正常运行
- 检查配置格式是否正确
- 检查应用日志中是否有相关的错误信息
2. 如何解决集群流量控制不生效的问题?
可能的原因和解决方案:
- 检查Token Server是否正常运行
- 检查Token Client是否正确配置
- 检查网络连接是否正常
- 检查集群规则是否正确配置
- 检查应用日志中是否有相关的错误信息
3. 如何解决网关限流不生效的问题?
可能的原因和解决方案:
- 检查网关组件(如Spring Cloud Gateway、Zuul)是否正确配置
- 检查Sentinel适配器是否正确配置
- 检查网关限流规则是否正确配置
- 检查应用日志中是否有相关的错误信息
总结
本文深入讲解了Sentinel的高级特性和最佳实践,包括规则持久化、集群流量控制、网关限流、与其他组件的集成等内容。通过这些特性和实践,我们可以更好地使用Sentinel保障微服务的稳定性。
Sentinel作为一个功能强大的流量控制和熔断降级框架,可以帮助我们构建更加健壮和可靠的微服务系统。希望本文能够帮助你更好地理解和使用Sentinel。