关注微信公众号 “程序员小胖” 每日技术干货,第一时间送达!
引言
在微服务架构中,流量治理是确保系统稳定性和高可用性的关键。Sentinel作为一项强大的流量控制组件,为我们提供了完善的解决方案。本文将带您走进Sentinel的世界,通过实战案例,展示如何利用Sentinel进行流量控制、熔断降级和系统自适应保护,让您的微服务架构更加健壮。
Sentinel的简介
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。
Sentinel的实现原理
在 Sentinel 里面,所有的资源都对应一个资源名称以及一个 Entry。Entry 可以通过对主流框架的适
配自动创建,也可以通过注解的方式或调用 API 显式创建;每一个 Entry 创建的时候,同时也会创建
一系列功能插槽(slot chain)。这些插槽有不同的职责。
Sentinel的核心概念
资源(Resource)
资源(Resource) 是指需要受到流量控制或者熔断保护的代码逻辑单元,它可以是服务调用、数据库连接、甚至一段特定的代码。Sentinel 对资源的保护是通过定义资源及其相关的规则来实现的。
资源的作用
- 流量控制:限制资源的访问频率,防止系统过载。
- 熔断降级:当资源(如服务调用)失败率达到一定阈值时,触发熔断,避免连锁故障。
- 实时监控:监控资源的访问情况,包括调用次数和响应时间等。
资源的分类
- 普通资源:通常是一段代码块,如一个服务的调用过程。
- 入口资源:在框架层面自动定义的资源,如 MVC 框架中的一个 URL 路径。
资源入口类型(EntryType)
- IN:进入型资源,这是最常见的资源入口类型。当一个请求或者调用进入你的服务时,通常会使用进入型资源。例如,一个 RESTful API 调用,一个数据库查询,或者任何其他由外部触发的事件。
- OUT:出去型资源,通常用于异步处理或者需要显式地将流量流出到下一个逻辑的场合。出去型资源允许你在调用链中嵌入一个显式的出口点。
- COMMON:通用型资源,用于那些既不是明确进入型也不是明确出去型的资源。在某些情况下,如果你不想明确区分资源的进入或出去方向,可以使用通用型。
- ASYNC:异步资源,用于处理异步调用场景。当资源的调用是在一个独立的线程或者在响应式编程模型中进行时,使用异步资源可以更准确地控制和监控这些异步操作。
- TRY_PREPARE:用于能够提前进行热点参数提取的异步调用链路。 进入型资源,这是最常见的资源入口类型。当一个请求或者调用进入你的服务时,通常会使用进入型资源。例如,一个 RESTful API 调用,一个数据库查询,或者任何其他由外部触发的事件。
String resource = "resourceA";
// 通过 Sentinel 的入口方法进行资源访问
Entry entry = null;
try {
entry = SphU.entry(resource,EntryType.ASYNC);
// 执行业务逻辑
} catch (BlockException ex) {
// 处理被限流的情况
} finally {
if (entry != null) {
entry.exit();
}
}
注解方式定义资源
@SentinelResource 是 Sentinel 提供的一个用于Java Spring框架的注解,它允许开发者在代码中声明式地定义资源及其流量控制规则。这个注解通常用在Spring的Bean方法上,以便于对这些方法进行流量控制和熔断降级处理。
核心属性解析:
- value:资源名称。这是必需的属性,Sentinel会根据这个名称来匹配和应用相应的流量规则。
- entryType:资源的入口类型。可以是IN(进入)或OUT(出去),默认为IN。这决定了流量是从外部进入系统,还是从系统出去。
- blockHandler:当资源被限流时调用的方法名。该方法必须与被注解的方法处于同一类中,并且返回类型必须与被注解的方法一致。
- fallback:当资源被熔断时调用的方法名。这类似于Spring的@Fallback机制,用于提供备选方案。
- exceptionsToTrace:指定在哪些异常下,该资源会被当作异常资源来统计。
代码示例:
@RestController
public class YourController {
@GetMapping("/test")
@SentinelResource(value = "testResource", blockHandler = "handleBlock", fallback = "handleFallback")
public String test() {
// 业务逻辑
return "Hello, Sentinel";
}
public String handleBlock(String resource, BlockException ex) {
// 限流处理逻辑
return "Blocked by Sentinel";
}
public String handleFallback(String resource, Throwable cause) {
// 熔断处理逻辑
return "Fallback for " + resource;
}
}
规则(Rule)
规则(Rule) 是用于定义流量控制、熔断降级等行为的具体条件。规则是 Sentinel 系统中非常核心的概念,它允许开发者根据实际的业务需求来定制流量管理策略。
Sentinel 支持的规则类型:
- 流量控制规则(FlowRule):用于限制资源的访问流量,如限制 QPS 或并发数。
FlowRule flowRule = new FlowRule("resourceA");
flowRule.setCount(10); // 限流阈值,如 QPS 为 10
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
flowRule.setLimitApp("default");
flowRule.setStrategy(RuleConstant.DIRECT);
// 加载规则
FlowRuleManager.loadRules(Collections.singletonList(flowRule));
- 熔断降级规则(DegradeRule):用于在资源访问失败或响应时间过长时触发熔断,以保护系统稳定性。
DegradeRule degradeRule = new DegradeRule("resourceB");
degradeRule.setResource("resourceB");
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
degradeRule.setCount(10); // 秒级失败次数阈值
degradeRule.setTimeWindow(10); // 熔断窗口时间
// 加载规则
DegradeRuleManager.loadRules(Collections.singletonList(degradeRule));
- 系统保护规则(SystemRule):用于根据系统的负载情况(如 CPU、内存使用率)来控制流量。
SystemRule systemRule = new SystemRule();
systemRule.setHighestSystemLoad(75); // 系统负载达到 75% 时触发规则
// 加载规则
SystemRuleManager.loadRules(Collections.singletonList(systemRule));
- 热点参数规则(ParamFlowRule):用于对指定参数的不同值进行流量控制。
ParamFlowRule paramFlowRule = new ParamFlowRule("resourceC");
paramFlowRule.setResource("resourceC");
paramFlowRule.setGrade(RuleConstant.FLOW_GRADE_PARAM_QPS);
paramFlowRule.setCount(5); // 参数级别的 QPS 阈值
paramFlowRule.setParamIdx(0); // 参数索引
paramFlowRule.setParamFlowItemList(
Collections.singletonList(
new ParamFlowItem("arg0", 5) // 当参数值为 "arg0" 时的阈值
)
);
// 加载规则
ParamFlowRuleManager.loadRules(Collections.singletonList(paramFlowRule));
规则的基本属性:
- resource:资源名,用于指定规则适用的资源。
- limitApp:来源应用名,用于指定规则适用的调用来源。
- grade:规则等级,如 QPS 或并发数。
- count:阈值,超过该阈值时规则生效。
- strategy:流量控制策略,如直接拒绝或平滑过渡。
- controlBehavior:控制行为,如直接拒绝、排队等待、慢启动等。
规则是 Sentinel 进行流量管理的基础,通过灵活地定义和应用规则,可以有效地保护系统不受异常流量的冲击,保障系统的高可用性。
流量控制(Flow Control)
流量控制(Flow Control) 是一种用于限制资源访问速率的机制,以防止系统过载。流量控制主要通过限制每秒通过的请求数(QPS)或并发数来实现。
核心概念解析:
- QPS (Queries Per Second):每秒查询率,用于衡量流量控制的速率。
- 并发数:同时处理请求的最大线程数。
- 热 Key:当一个资源与一个或多个参数(如用户 ID、商品 ID)关联时,如果某个参数的访问量特别高,这个参数被称为热 Key。
- 阈值模式:流量控制的两种模式,包括直接阈值模式和关联阈值模式。直接阈值模式只考虑请求总数,而关联阈值模式考虑参数级别的请求总数。
- 流量整形:对流量曲线进行整形,使流量以更平滑的方式通过。
- 熔断机制:当系统处于异常状态时,通过断开或降级某些服务来保护系统。
代码示例:
// 1、确认配置流量控制规则
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
FlowRule rule = new FlowRule();
rule.setResource("resourceA"); // 资源名
rule.setCount(10); // 限流阈值,如每秒 10 个请求
rule.setGrade(1); // 1 表示 QPS
rule.setLimitApp("default"); // 来源应用名
// 加载规则
FlowRuleManager.loadRules(Collections.singletonList(rule));
//2、代码中使用流量控制
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
public void doSomething() {
String resource = "resourceA";
Entry entry = null;
try {
entry = SphU.entry(resource);
// 业务逻辑处理
} catch (Exception e) {
// 处理被限流的情况
} finally {
if (entry != null) {
entry.exit();
}
}
}
//在上述示例中,我们首先定义了一个流量控制规则,限制名为 resourceA 的资源每秒只能处理 10 个请求。
//然后,在业务逻辑中,我们通过 Sentinel 的 SphU.entry 方法对资源进行保护。如果请求超过了定义的阈值,将抛出异常,我们可以通过 catch 块来处理这种情况。
流量控制是 Sentinel 中非常重要的一个特性,它可以帮助开发者在微服务架构中更好地管理流量,保护系统不受过载的影响。通过合理设置流量控制规则,可以提高系统的稳定性和可用性。
熔断降级(Circuit Breaking)
熔断降级(Circuit Breaking) 是一种提高系统稳定性和可用性的机制。当某个服务不可用或者响应时间过长时,熔断机制可以防止系统雪崩效应,通过临时切断或降级对该服务的调用,从而保护整个系统的稳定运行。
核心概念解析:
- 熔断(Circuit Tripping):当服务连续失败达到一定阈值时,熔断器会“跳闸”,此时所有对该服务的调用都会立即失败,而不是等待服务超时。
- 降级(Falling Back):在服务熔断后,可以提供一个备选的行为或返回值,以维持系统的可用性。
- 半开状态(Half-Open State):在熔断器打开一段时间后,会进入半开状态,允许一部分流量尝试调用服务,以检测服务是否已经恢复正常。
- 冷却时间(Cool Down Time):熔断器打开后,会等待一段冷却时间,然后才进入半开状态。
- 失败判定:可以基于异常比例、响应时间等条件来判断服务是否失败。
代码示例:
配置熔断降级规则:
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
DegradeRule rule = new DegradeRule();
rule.setResource("resourceB"); // 资源名
rule.setGrade(RuleConstant.DEGRADE_GRADE_RT); // 响应时间降级
rule.setCount(10); // 秒级失败次数阈值
rule.setTimeWindow(10); // 熔断窗口时间,单位为秒
rule.setMinRequestAmount(5); // 最小请求量
// 加载规则
DegradeRuleManager.loadRules(Collections.singletonList(rule));
//在上述示例中,我们定义了一个基于响应时间的熔断降级规则。如果资源 resourceB 在 10 秒内失败次数超过 10 次,并且请求量大于等于 5 次,那么熔断器将会被触发。
在代码中使用熔断降级:
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
public void doSomething() {
String resource = "resourceB";
Entry entry = null;
try {
entry = SphU.entry(resource);
// 业务逻辑处理
} catch (Exception e) {
// 处理熔断降级的情况
// 可以进行重试、返回默认值或执行其他逻辑
System.out.println("资源暂时不可用,已触发降级逻辑");
} finally {
if (entry != null) {
entry.exit();
}
}
}
//在上述示例中,我们通过 Sentinel 的 SphU.entry 方法对资源进行保护。如果资源触发了熔断降级规则,将会抛出异常,我们可以通过 catch 块来处理这种情况,例如返回默认值或执行其他逻辑。
熔断降级是 Sentinel 中非常重要的一个特性,它可以帮助开发者在微服务架构中更好地处理服务不稳定的情况,保护系统不受单点故障的影响。通过合理设置熔断降级规则,可以提高系统的容错性。
系统保护(System Protection)
系统保护(System Protection) 是一种基于系统负载的流量控制机制,其目的是防止由于系统负载过高导致服务不可用或响应延迟增加。系统保护通过限制流入系统的总体流量来实现,确保系统资源(如 CPU、内存、线程等)不会超过预设的安全阈值。
核心概念解析:
- 负载指标:系统保护规则基于不同的系统负载指标,如 CPU 使用率、内存使用量、线程数等。
- 阈值:每种负载指标都有一个阈值,当系统运行的实际负载超过这些阈值时,系统保护规则将被触发。
- 流量控制:系统保护通过限制流量来降低系统的负载,防止系统过载。
- 模式:系统保护可以配置为单机模式或集群模式。单机模式下,只考虑单个实例的负载情况;集群模式下,会考虑整个集群的负载情况。
代码示例:
import com.alibaba.csp.sentinel.config.SystemRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
SystemRule rule = new SystemRule();
rule.setHighestSystemLoad(75); // 设置系统负载的最高阈值为 75%
rule.setAverageRt(300); // 设置平均响应时间的阈值为 300 毫秒
// 加载规则
SystemRuleManager.loadRules(Collections.singletonList(rule));
//我们定义了一个系统保护规则,设置了系统负载的最高阈值为 75%,并且设置了平均响应时间的阈值为 300 毫秒。
//当系统负载超过规则中定义的阈值时,Sentinel 会开始拒绝一些请求,直到系统负载降低到安全水平。
系统保护是 Sentinel 中用于保障整个系统稳定性的重要特性,特别适合于那些对系统资源使用有严格要求的场景。通过系统保护,可以在不牺牲用户体验的前提下,最大化地利用系统资源,同时避免因资源耗尽而导致的系统崩溃。
总结
Sentinel 在流量控制、熔断降级、系统保护等方面表现出色,尤其适合微服务架构中需要精细化控制流量和保护系统稳定性的场景。其劣势主要体现在学习成本、定制化需求、依赖控制台以及跨语言支持等方面,需要根据具体项目需求、团队技术栈和运维能力进行权衡选择。总之,Sentinel 凭借其全面的流量控制与保护能力,已成为微服务架构中不可或缺的稳定基石。尽管存在一定的学习成本和特定场景下的定制化需求,但瑕不掩瑜,对于寻求提升服务稳定性和应对复杂流量场景的企业而言,Sentinel 无疑是值得考虑的选择。随着社区的持续发展和功能完善,Sentinel 有望进一步优化其劣势,更好地服务于全球范围内的开发者与企业用户。
参考文档:
https://sentinelguard.io/zh-cn/docs/introduction.html
https://developer.aliyun.com/article/1140971
http://www.manongjc.com/detail/8-hbvpbollqobpzev.html
https://m.blog.csdn.net/weixin_38308374/article/details/114951452
https://zhuanlan.zhihu.com/p/439887978