跳到主要内容

故障排查

本章汇总了 Sentinel 使用过程中的常见问题及其排查方法,帮助你快速定位和解决问题。

常见问题

1. 控制台看不到应用

问题描述:应用已启动并接入控制台,但在控制台的机器列表中看不到应用。

排查步骤

1)检查依赖是否完整

确保项目中包含了传输模块依赖:

<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.8</version>
</dependency>

2)检查启动参数

确认 JVM 参数配置正确:

-Dcsp.sentinel.dashboard.server=localhost:8080

如果是 Spring Cloud 应用,检查配置文件:

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

3)检查端口冲突

查看客户端 API 端口是否被占用:

# Windows
netstat -ano | findstr 8719

# Linux/Mac
netstat -tlnp | grep 8719

如果端口被占用,指定其他端口:

-Dcsp.sentinel.api.port=8720

4)检查是否有访问量

Sentinel 是懒加载机制,需要有流量才会初始化。确保应用有请求进入。

5)检查日志

查看 Sentinel 日志文件:

# 日志位置
~/logs/csp/sentinel-record.log
~/logs/csp/sentinel-block.log

检查是否有连接错误:

# 正常日志示例
[Sentinel] INFO: Begin heartbeat to server localhost:8080
[Sentinel] INFO: [Heartbeat] Send heartbeat to localhost:8080 success

2. 规则配置后不生效

问题描述:在控制台配置规则后,规则没有生效。

排查步骤

1)检查资源名称是否匹配

确认规则配置的资源名称与代码中定义的一致:

// 代码中定义的资源名
@SentinelResource(value = "getUser")
public User getUser(String id) { ... }

// 规则配置的资源名必须完全一致
rule.setResource("getUser"); // 不是 "getuser" 或 "GET:/getUser"

2)检查 Web 接口资源名

Web 接口的资源名默认包含 HTTP 方法前缀:

GET:/api/users
POST:/api/users

确保规则配置时使用了完整的资源名。

3)检查规则是否加载成功

通过 API 查看当前加载的规则:

# 查看流控规则
curl http://localhost:8719/getRules?type=flow

# 查看熔断规则
curl http://localhost:8719/getRules?type=degrade

4)检查规则配置正确性

// 检查阈值是否合理
rule.setCount(100); // 不是 0

// 检查限流模式
rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // 1=QPS, 0=线程数

5)检查版本兼容性

确保控制台版本与客户端版本兼容:

<!-- 客户端版本 -->
<sentinel.version>1.8.8</sentinel.version>

<!-- 控制台版本也应该使用 1.8.8 -->

3. 限流不生效

问题描述:配置了限流规则,但请求没有被限流。

排查步骤

1)确认请求量是否超过阈值

确认实际的 QPS 是否真的超过了配置的阈值:

# 查看资源实时统计
curl http://localhost:8719/cnode?id=getUser

输出示例:

idx id      thread pass blocked success total rt  1m-pass 1m-block 1m-all exception
1 getUser 5 100 0 100 100 10 6000 0 6000 0

blocked 列显示被限流的请求数。

2)检查是否正确捕获异常

// 错误:没有捕获 BlockException
Entry entry = SphU.entry("resource");
// 业务逻辑
entry.exit();

// 正确:捕获 BlockException
try {
Entry entry = SphU.entry("resource");
try {
// 业务逻辑
} finally {
entry.exit();
}
} catch (BlockException e) {
// 限流处理
System.out.println("被限流");
}

3)检查 Context 是否正确

// 错误:Context 使用不当
ContextUtil.enter("context1");
Entry entry1 = SphU.entry("resourceA");
ContextUtil.enter("context2"); // 无效,Context 只在入口设置有效
Entry entry2 = SphU.entry("resourceB");

4)检查链路限流配置

如果使用链路限流,确认入口资源名正确:

rule.setStrategy(RuleConstant.STRATEGY_CHAIN);
rule.setRefResource("entrance1"); // 入口资源名

4. 熔断器不工作

问题描述:配置了熔断规则,但熔断器没有触发。

排查步骤

1)检查最小请求数

确保统计时长内的请求数达到最小请求数:

rule.setMinRequestAmount(10);  // 至少 10 个请求
rule.setStatIntervalMs(10000); // 统计时长 10 秒

2)检查异常是否正确记录

手动埋点时需要调用 Tracer.trace() 记录异常:

try {
entry = SphU.entry("resource");
// 业务逻辑
} catch (BusinessException e) {
Tracer.trace(e); // 必须调用,否则异常不会被统计
throw e;
} finally {
entry.exit();
}

3)检查慢调用阈值

慢调用比例模式需要设置慢调用临界 RT:

rule.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType());
rule.setCount(500); // 慢调用临界 RT,单位 ms
rule.setSlowRatioThreshold(0.5); // 慢调用比例阈值

4)查看熔断器状态

注册状态监听器观察熔断器状态变化:

EventObserverRegistry.getInstance().addStateChangeObserver("debug",
(prevState, newState, rule, snapshotValue) -> {
System.out.println("熔断器状态: " + prevState + " -> " + newState);
System.out.println("触发值: " + snapshotValue);
});

5. 热点参数限流不生效

问题描述:配置了热点参数规则,但限流没有生效。

排查步骤

1)检查参数传递

确保在 entry 和 exit 时都传入了参数:

Entry entry = null;
try {
entry = SphU.entry("resource", EntryType.IN, 1, param1, param2);
// 业务逻辑
} finally {
if (entry != null) {
entry.exit(1, param1, param2); // 必须传入相同的参数
}
}

2)检查参数索引

参数索引从 0 开始:

rule.setParamIdx(0);  // 第一个参数

3)检查参数类型

参数例外项只支持基本类型和字符串:

ParamFlowItem item = new ParamFlowItem();
item.setObject("vip_user"); // 字符串值
item.setClassType(String.class.getName()); // 类型
item.setCount(100);

4)检查依赖

确保引入了热点参数限流依赖:

<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-parameter-flow-control</artifactId>
<version>1.8.8</version>
</dependency>

6. 内存占用过高

问题描述:应用内存占用异常升高。

排查步骤

1)检查资源数量

资源数量过多会增加内存占用:

# 查看所有资源
curl http://localhost:8719/tree?type=root

2)检查热点参数基数

热点参数的不同值过多会占用大量内存:

// 如果参数值太多(如用户ID),考虑是否需要热点参数限流
rule.setParamIdx(0);

3)调整滑动窗口配置

// 减少滑动窗口格子数
SampleCountProperty.updateGlobalSampleCount(2); // 默认值

4)检查是否有资源泄漏

确保每个 entry 都正确 exit:

try {
entry = SphU.entry("resource");
// 业务逻辑
} finally {
if (entry != null) {
entry.exit(); // 必须在 finally 中执行
}
}

7. 性能问题

问题描述:接入 Sentinel 后应用响应变慢。

排查步骤

1)检查规则数量

规则数量过多会影响性能:

// 查看规则数量
FlowRuleManager.getRules().size();

2)检查资源埋点粒度

过度细粒度的埋点会增加开销:

// 不推荐:每个小方法都埋点
@SentinelResource(value = "helper1")
public void helperMethod1() { ... }

// 推荐:只对关键接口埋点
@SentinelResource(value = "api:process")
public void process() {
helperMethod1();
helperMethod2();
}

3)检查滑动窗口精度

高精度滑动窗口会增加开销:

// 降低精度
SampleCountProperty.updateGlobalSampleCount(2); // 不是 10 或更高

4)检查集群限流延迟

如果使用集群限流,网络延迟可能影响性能:

// 检查请求超时配置
ClusterClientConfig config = new ClusterClientConfig();
config.setRequestTimeout(20); // 默认 20ms

8. 规则持久化问题

问题描述:应用重启后规则丢失。

排查步骤

1)检查动态数据源配置

确保配置了动态规则源:

spring:
cloud:
sentinel:
datasource:
flow:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-flow-rules
rule-type: flow

2)检查配置中心连通性

确保能够连接到配置中心:

# 检查 Nacos 连接
curl http://localhost:8848/nacos/v1/cs/configs?dataId=app-flow-rules&group=SENTINEL_GROUP

3)检查规则格式

确保规则的 JSON 格式正确:

[
{
"resource": "test",
"grade": 1,
"count": 10
}
]

日志分析

日志文件位置

Sentinel 日志默认存放在用户目录下:

~/logs/csp/
├── sentinel-record.log # 主日志
├── sentinel-block.log # 限流日志
├── ${app}-metrics.log.${date} # 指标日志
└── command.log # 命令日志

常见日志信息

正常启动

[Sentinel] INFO: Sentinel log output to ...
[Sentinel] INFO: Application name: my-app
[Sentinel] INFO: Begin heartbeat to server localhost:8080

连接控制台失败

[Sentinel] ERROR: [Heartbeat] Send heartbeat to localhost:8080 failed

规则加载

[Sentinel] INFO: [FlowRuleManager] Flow rules loaded: 5
[Sentinel] INFO: [DegradeRuleManager] Degrade rules loaded: 3

限流触发

[Sentinel] INFO: Block: resource=getUser, origin=appA, count=1

日志配置

可以通过 JVM 参数自定义日志配置:

# 日志目录
-Dcsp.sentinel.log.dir=/var/log/sentinel

# 日志文件名
-Dcsp.sentinel.log.filename.pid=true

# 是否输出到控制台
-Dcsp.sentinel.log.output.to.console=true

HTTP API 调试

Sentinel 提供了丰富的 HTTP API 用于调试:

查看实时状态

# 查看所有资源
curl http://localhost:8719/tree?type=root

# 查看特定资源
curl http://localhost:8719/cnode?id=getUser

# 查看调用来源统计
curl http://localhost:8719/origin?id=getUser

查看规则

# 查看流控规则
curl http://localhost:8719/getRules?type=flow

# 查看熔断规则
curl http://localhost:8719/getRules?type=degrade

# 查看系统规则
curl http://localhost:8719/getRules?type=system

# 查看热点规则
curl http://localhost:8719/getParamRules

动态修改规则

# 设置流控规则
curl -X POST "http://localhost:8719/setRules?type=flow" -d '[{"resource":"test","grade":1,"count":10}]'

# 设置熔断规则
curl -X POST "http://localhost:8719/setRules?type=degrade" -d '[{"resource":"test","grade":0,"count":500,"timeWindow":30}]'

其他调试接口

# 健康检查
curl http://localhost:8719/health

# 版本信息
curl http://localhost:8719/version

# 查看集群模式
curl http://localhost:8719/cluster/server/transportInfo

调试技巧

1. 开启调试日志

// 注册状态变化监听器
EventObserverRegistry.getInstance().addStateChangeObserver("debug",
(prevState, newState, rule, snapshotValue) -> {
log.debug("熔断器状态变化: {} -> {}, 规则={}, 触发值={}",
prevState, newState, rule.getResource(), snapshotValue);
});

2. 打印当前规则

// 打印当前所有规则
log.info("流控规则: {}", FlowRuleManager.getRules());
log.info("熔断规则: {}", DegradeRuleManager.getRules());
log.info("系统规则: {}", SystemRuleManager.getRules());

3. 监控资源调用

// 注册回调
StatisticSlotCallbackRegistry.addEntryCallback("debug", new ProcessorSlotEntryCallback<DefaultNode>() {
@Override
public void onPass(Context context, ResourceWrapper resource, DefaultNode param, int count, Object... args) {
log.debug("资源通过: {}", resource.getName());
}

@Override
public void onBlocked(BlockException ex, Context context, ResourceWrapper resource, DefaultNode param, int count, Object... args) {
log.warn("资源被阻止: {}, 异常: {}", resource.getName(), ex.getClass().getSimpleName());
}
});

4. 检查上下文

// 打印当前上下文信息
Context context = ContextUtil.getContext();
if (context != null) {
log.debug("上下文名称: {}", context.getName());
log.debug("调用来源: {}", context.getOrigin());
log.debug("入口节点: {}", context.getEntranceNode());
}

问题排查流程

当遇到问题时,建议按以下流程排查:

1. 确认问题现象

2. 查看日志文件

3. 使用 HTTP API 检查状态

4. 检查配置是否正确

5. 检查代码实现

6. 查看官方文档和 FAQ

7. 搜索 GitHub Issues

8. 提交 Issue

参考资源

下一步