引言

在微服务架构中,服务间的调用关系复杂,一个服务的异常可能会影响整个系统的稳定性。流量控制、熔断降级是保障微服务系统稳定性的重要手段。SpringCloudAlibaba Sentinel作为阿里巴巴开源的流量控制和熔断降级组件,提供了完整的微服务保护解决方案。

Sentinel以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性,具有实时监控、规则配置、动态推送等特性,是微服务架构中不可或缺的组件。

本文将深入讲解Sentinel的核心概念、配置方式、规则管理以及实际应用场景,帮助开发者掌握微服务流量控制和熔断降级的设计与实现。

Sentinel核心概念

1. 什么是流量控制

流量控制是微服务保护的重要手段,通过限制请求的速率和数量,防止系统因流量过大而崩溃。Sentinel的流量控制具有以下特点:

  • 实时监控:实时统计请求的QPS、响应时间等指标
  • 动态规则:支持动态配置和推送流量控制规则
  • 多种策略:支持QPS限流、并发线程数限流、系统负载限流
  • 精确控制:支持基于调用来源、接口、参数等维度的精确限流

2. 什么是熔断降级

熔断降级是当服务出现异常时,快速失败并返回预设的降级结果,避免级联故障。Sentinel的熔断降级具有以下特点:

  • 异常检测:自动检测服务异常和响应时间
  • 快速失败:异常时立即返回降级结果
  • 自动恢复:异常恢复后自动恢复正常调用
  • 多种策略:支持异常比例、异常数量、响应时间等熔断策略

3. Sentinel架构特点

1
2
3
4
5
6
7
8
9
10
11
12
13
graph TB
A[客户端请求] --> B[Sentinel Core]
B --> C{流量控制}
C -->|通过| D[业务逻辑]
C -->|限流| E[限流处理]

D --> F{熔断检测}
F -->|正常| G[正常响应]
F -->|异常| H[熔断降级]

I[Sentinel Dashboard] --> B
J[规则配置] --> I
K[监控数据] --> I

核心特性:

  • 轻量级:核心库无额外依赖
  • 实时监控:提供实时监控和告警
  • 规则管理:支持动态规则配置和推送
  • 多种场景:支持Web、RPC、消息等多种场景
  • 生态集成:与Spring Cloud、Dubbo等框架深度集成

Sentinel Dashboard安装与配置

1. 环境准备

系统要求:

  • JDK 1.8+
  • 内存:1GB+
  • 网络:需要访问Nacos等注册中心

下载Sentinel Dashboard:

1
2
3
4
5
# 下载Sentinel Dashboard
wget https://github.com/alibaba/Sentinel/releases/download/1.8.6/sentinel-dashboard-1.8.6.jar

# 或者使用Docker
docker pull bladex/sentinel-dashboard:latest

2. 启动Sentinel Dashboard

方式1:直接启动

1
2
3
4
5
6
7
8
9
# 使用默认配置启动
java -jar sentinel-dashboard-1.8.6.jar

# 自定义配置启动
java -jar sentinel-dashboard-1.8.6.jar \
--server.port=8080 \
--nacos.server-addr=localhost:8848 \
--nacos.namespace=sentinel \
--nacos.group-id=SENTINEL_GROUP

方式2:Docker启动

1
2
3
4
5
6
7
8
9
# 基础启动
docker run -d -p 8080:8080 bladex/sentinel-dashboard:latest

# 使用Nacos配置启动
docker run -d -p 8080:8080 \
-e NACOS_SERVER_ADDR=localhost:8848 \
-e NACOS_NAMESPACE=sentinel \
-e NACOS_GROUP_ID=SENTINEL_GROUP \
bladex/sentinel-dashboard:latest

3. 访问控制台

访问地址:

主要功能:

  • 实时监控:查看应用实时QPS、响应时间等指标
  • 规则管理:配置流量控制、熔断降级规则
  • 集群管理:管理集群限流规则
  • 系统保护:配置系统负载保护规则

Spring Boot集成Sentinel

1. 项目依赖配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<dependencies>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

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

<!-- Sentinel Dashboard -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
</dependency>

<!-- Nacos Discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<!-- Spring Boot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2022.0.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

2. 配置文件设置

application.yml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
server:
port: 8080

spring:
application:
name: sentinel-demo-service

cloud:
nacos:
discovery:
server-addr: localhost:8848
namespace: dev
group: DEFAULT_GROUP
sentinel:
transport:
dashboard: localhost:8080 # Sentinel Dashboard地址
port: 8719 # 客户端监控API端口
datasource:
# 使用Nacos作为规则数据源
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
param-flow:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-param-flow-rules
groupId: SENTINEL_GROUP
rule-type: param-flow
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

# 日志配置
logging:
level:
com.alibaba.csp.sentinel: DEBUG

3. 启动类配置

1
2
3
4
5
6
7
@SpringBootApplication
@EnableDiscoveryClient
public class SentinelDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SentinelDemoApplication.class, args);
}
}

流量控制功能

1. QPS限流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@RestController
@RequestMapping("/api")
@Slf4j
public class UserController {

@Autowired
private UserService userService;

@GetMapping("/user/{id}")
@SentinelResource(
value = "getUserById",
blockHandler = "handleBlock",
fallback = "handleFallback"
)
public ResponseEntity<User> getUser(@PathVariable Long id) {
log.info("获取用户信息,用户ID: {}", id);

User user = userService.findById(id);
return ResponseEntity.ok(user);
}

/**
* 限流处理
*/
public ResponseEntity<User> handleBlock(Long id, BlockException ex) {
log.warn("用户服务限流,用户ID: {}, 异常: {}", id, ex.getMessage());

User fallbackUser = new User();
fallbackUser.setId(id);
fallbackUser.setName("限流用户");
fallbackUser.setMessage("服务繁忙,请稍后重试");

return ResponseEntity.ok(fallbackUser);
}

/**
* 降级处理
*/
public ResponseEntity<User> handleFallback(Long id, Throwable ex) {
log.error("用户服务异常,用户ID: {}, 异常: {}", id, ex.getMessage());

User fallbackUser = new User();
fallbackUser.setId(id);
fallbackUser.setName("降级用户");
fallbackUser.setMessage("服务暂时不可用");

return ResponseEntity.ok(fallbackUser);
}
}

2. 并发线程数限流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@Service
@Slf4j
public class OrderService {

@SentinelResource(
value = "createOrder",
blockHandler = "handleCreateOrderBlock",
fallback = "handleCreateOrderFallback"
)
public Order createOrder(Order order) {
log.info("创建订单: {}", order.getOrderNo());

// 模拟业务处理
try {
Thread.sleep(1000); // 模拟耗时操作
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}

order.setId(System.currentTimeMillis());
order.setStatus("CREATED");

return order;
}

public Order handleCreateOrderBlock(Order order, BlockException ex) {
log.warn("创建订单限流: {}, 异常: {}", order.getOrderNo(), ex.getMessage());

Order fallbackOrder = new Order();
fallbackOrder.setOrderNo(order.getOrderNo());
fallbackOrder.setStatus("BLOCKED");
fallbackOrder.setMessage("系统繁忙,请稍后重试");

return fallbackOrder;
}

public Order handleCreateOrderFallback(Order order, Throwable ex) {
log.error("创建订单异常: {}, 异常: {}", order.getOrderNo(), ex.getMessage());

Order fallbackOrder = new Order();
fallbackOrder.setOrderNo(order.getOrderNo());
fallbackOrder.setStatus("FAILED");
fallbackOrder.setMessage("订单创建失败");

return fallbackOrder;
}
}

3. 热点参数限流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
@RestController
@RequestMapping("/api/product")
@Slf4j
public class ProductController {

@Autowired
private ProductService productService;

@GetMapping("/detail/{productId}")
@SentinelResource(
value = "getProductDetail",
blockHandler = "handleGetProductDetailBlock",
fallback = "handleGetProductDetailFallback"
)
public ResponseEntity<Product> getProductDetail(
@PathVariable Long productId,
@RequestParam(required = false) String userId) {

log.info("获取商品详情,商品ID: {}, 用户ID: {}", productId, userId);

Product product = productService.getProductDetail(productId, userId);
return ResponseEntity.ok(product);
}

public ResponseEntity<Product> handleGetProductDetailBlock(
Long productId,
String userId,
BlockException ex) {

log.warn("商品详情限流,商品ID: {}, 用户ID: {}, 异常: {}",
productId, userId, ex.getMessage());

Product fallbackProduct = new Product();
fallbackProduct.setId(productId);
fallbackProduct.setName("限流商品");
fallbackProduct.setMessage("商品详情服务繁忙,请稍后重试");

return ResponseEntity.ok(fallbackProduct);
}

public ResponseEntity<Product> handleGetProductDetailFallback(
Long productId,
String userId,
Throwable ex) {

log.error("商品详情异常,商品ID: {}, 用户ID: {}, 异常: {}",
productId, userId, ex.getMessage());

Product fallbackProduct = new Product();
fallbackProduct.setId(productId);
fallbackProduct.setName("降级商品");
fallbackProduct.setMessage("商品详情服务暂时不可用");

return ResponseEntity.ok(fallbackProduct);
}
}

熔断降级功能

1. 异常比例熔断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@Service
@Slf4j
public class PaymentService {

@SentinelResource(
value = "processPayment",
blockHandler = "handleProcessPaymentBlock",
fallback = "handleProcessPaymentFallback"
)
public PaymentResult processPayment(PaymentRequest request) {
log.info("处理支付请求: {}", request.getOrderNo());

// 模拟支付处理
if (Math.random() < 0.3) { // 30%概率异常
throw new RuntimeException("支付处理失败");
}

PaymentResult result = new PaymentResult();
result.setOrderNo(request.getOrderNo());
result.setStatus("SUCCESS");
result.setAmount(request.getAmount());
result.setTransactionId("TXN" + System.currentTimeMillis());

return result;
}

public PaymentResult handleProcessPaymentBlock(
PaymentRequest request,
BlockException ex) {

log.warn("支付处理限流: {}, 异常: {}", request.getOrderNo(), ex.getMessage());

PaymentResult result = new PaymentResult();
result.setOrderNo(request.getOrderNo());
result.setStatus("BLOCKED");
result.setMessage("支付服务繁忙,请稍后重试");

return result;
}

public PaymentResult handleProcessPaymentFallback(
PaymentRequest request,
Throwable ex) {

log.error("支付处理异常: {}, 异常: {}", request.getOrderNo(), ex.getMessage());

PaymentResult result = new PaymentResult();
result.setOrderNo(request.getOrderNo());
result.setStatus("FAILED");
result.setMessage("支付处理失败");

return result;
}
}

2. 异常数量熔断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
@Service
@Slf4j
public class InventoryService {

@SentinelResource(
value = "checkInventory",
blockHandler = "handleCheckInventoryBlock",
fallback = "handleCheckInventoryFallback"
)
public InventoryResult checkInventory(Long productId, Integer quantity) {
log.info("检查库存,商品ID: {}, 数量: {}", productId, quantity);

// 模拟库存检查
if (Math.random() < 0.2) { // 20%概率异常
throw new RuntimeException("库存检查失败");
}

InventoryResult result = new InventoryResult();
result.setProductId(productId);
result.setRequestedQuantity(quantity);
result.setAvailableQuantity(100); // 模拟库存数量
result.setSufficient(quantity <= 100);

return result;
}

public InventoryResult handleCheckInventoryBlock(
Long productId,
Integer quantity,
BlockException ex) {

log.warn("库存检查限流,商品ID: {}, 数量: {}, 异常: {}",
productId, quantity, ex.getMessage());

InventoryResult result = new InventoryResult();
result.setProductId(productId);
result.setRequestedQuantity(quantity);
result.setSufficient(false);
result.setMessage("库存服务繁忙,请稍后重试");

return result;
}

public InventoryResult handleCheckInventoryFallback(
Long productId,
Integer quantity,
Throwable ex) {

log.error("库存检查异常,商品ID: {}, 数量: {}, 异常: {}",
productId, quantity, ex.getMessage());

InventoryResult result = new InventoryResult();
result.setProductId(productId);
result.setRequestedQuantity(quantity);
result.setSufficient(false);
result.setMessage("库存服务暂时不可用");

return result;
}
}

3. 响应时间熔断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
@Service
@Slf4j
public class NotificationService {

@SentinelResource(
value = "sendNotification",
blockHandler = "handleSendNotificationBlock",
fallback = "handleSendNotificationFallback"
)
public NotificationResult sendNotification(NotificationRequest request) {
log.info("发送通知: {}", request.getType());

// 模拟通知发送,随机延迟
try {
int delay = (int) (Math.random() * 3000) + 500; // 500-3500ms
Thread.sleep(delay);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}

NotificationResult result = new NotificationResult();
result.setRequestId(request.getRequestId());
result.setType(request.getType());
result.setStatus("SENT");
result.setMessage("通知发送成功");

return result;
}

public NotificationResult handleSendNotificationBlock(
NotificationRequest request,
BlockException ex) {

log.warn("通知发送限流: {}, 异常: {}", request.getType(), ex.getMessage());

NotificationResult result = new NotificationResult();
result.setRequestId(request.getRequestId());
result.setType(request.getType());
result.setStatus("BLOCKED");
result.setMessage("通知服务繁忙,请稍后重试");

return result;
}

public NotificationResult handleSendNotificationFallback(
NotificationRequest request,
Throwable ex) {

log.error("通知发送异常: {}, 异常: {}", request.getType(), ex.getMessage());

NotificationResult result = new NotificationResult();
result.setRequestId(request.getRequestId());
result.setType(request.getType());
result.setStatus("FAILED");
result.setMessage("通知发送失败");

return result;
}
}

系统负载保护

1. 系统规则配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@Configuration
public class SentinelSystemConfig {

@PostConstruct
public void initSystemRules() {
List<SystemRule> rules = new ArrayList<>();

// CPU使用率保护
SystemRule cpuRule = new SystemRule();
cpuRule.setMetricType(SystemRule.CPU_USAGE);
cpuRule.setCount(0.8); // CPU使用率超过80%时触发
rules.add(cpuRule);

// 平均响应时间保护
SystemRule rtRule = new SystemRule();
rtRule.setMetricType(SystemRule.AVG_RT);
rtRule.setCount(200); // 平均响应时间超过200ms时触发
rules.add(rtRule);

// 并发线程数保护
SystemRule threadRule = new SystemRule();
threadRule.setMetricType(SystemRule.CONCURRENT_THREAD);
threadRule.setCount(100); // 并发线程数超过100时触发
rules.add(threadRule);

// 系统QPS保护
SystemRule qpsRule = new SystemRule();
qpsRule.setMetricType(SystemRule.QPS);
qpsRule.setCount(1000); // 系统QPS超过1000时触发
rules.add(qpsRule);

// 系统负载保护
SystemRule loadRule = new SystemRule();
loadRule.setMetricType(SystemRule.SYSTEM_LOAD);
loadRule.setCount(2.0); // 系统负载超过2.0时触发
rules.add(loadRule);

SystemRuleManager.loadRules(rules);
}
}

2. 系统保护处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Component
@Slf4j
public class SystemProtectionHandler {

@EventListener
public void handleSystemBlock(SystemBlockException ex) {
log.warn("系统保护触发: {}", ex.getMessage());

// 记录系统保护事件
recordSystemProtectionEvent(ex);

// 发送告警通知
sendSystemProtectionAlert(ex);
}

private void recordSystemProtectionEvent(SystemBlockException ex) {
// 记录系统保护事件到数据库或日志
log.info("系统保护事件记录: {}", ex.getRule());
}

private void sendSystemProtectionAlert(SystemBlockException ex) {
// 发送系统保护告警
log.warn("发送系统保护告警: {}", ex.getMessage());
}
}

规则管理

1. 动态规则配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
@RestController
@RequestMapping("/api/sentinel")
@Slf4j
public class SentinelRuleController {

@Autowired
private FlowRuleManager flowRuleManager;

@Autowired
private DegradeRuleManager degradeRuleManager;

/**
* 配置流量控制规则
*/
@PostMapping("/flow-rule")
public ResponseEntity<String> addFlowRule(@RequestBody FlowRuleRequest request) {
try {
FlowRule rule = new FlowRule();
rule.setResource(request.getResource());
rule.setGrade(request.getGrade());
rule.setCount(request.getCount());
rule.setStrategy(request.getStrategy());
rule.setControlBehavior(request.getControlBehavior());
rule.setWarmUpPeriodSec(request.getWarmUpPeriodSec());
rule.setMaxQueueingTimeMs(request.getMaxQueueingTimeMs());

List<FlowRule> rules = new ArrayList<>();
rules.add(rule);

FlowRuleManager.loadRules(rules);

log.info("流量控制规则配置成功: {}", rule);
return ResponseEntity.ok("流量控制规则配置成功");
} catch (Exception e) {
log.error("流量控制规则配置失败", e);
return ResponseEntity.status(500).body("配置失败: " + e.getMessage());
}
}

/**
* 配置熔断降级规则
*/
@PostMapping("/degrade-rule")
public ResponseEntity<String> addDegradeRule(@RequestBody DegradeRuleRequest request) {
try {
DegradeRule rule = new DegradeRule();
rule.setResource(request.getResource());
rule.setGrade(request.getGrade());
rule.setCount(request.getCount());
rule.setTimeWindow(request.getTimeWindow());
rule.setMinRequestAmount(request.getMinRequestAmount());
rule.setSlowRatioThreshold(request.getSlowRatioThreshold());

List<DegradeRule> rules = new ArrayList<>();
rules.add(rule);

DegradeRuleManager.loadRules(rules);

log.info("熔断降级规则配置成功: {}", rule);
return ResponseEntity.ok("熔断降级规则配置成功");
} catch (Exception e) {
log.error("熔断降级规则配置失败", e);
return ResponseEntity.status(500).body("配置失败: " + e.getMessage());
}
}

/**
* 获取当前规则
*/
@GetMapping("/rules")
public ResponseEntity<Map<String, Object>> getRules() {
Map<String, Object> rules = new HashMap<>();
rules.put("flowRules", FlowRuleManager.getRules());
rules.put("degradeRules", DegradeRuleManager.getRules());
rules.put("systemRules", SystemRuleManager.getRules());

return ResponseEntity.ok(rules);
}
}

2. 规则数据源配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Configuration
public class SentinelDataSourceConfig {

@Autowired
private NacosConfigService nacosConfigService;

@PostConstruct
public void initDataSource() {
// 流量控制规则数据源
ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(
nacosConfigService,
"sentinel-demo-service-flow-rules",
"SENTINEL_GROUP",
source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {})
);
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());

// 熔断降级规则数据源
ReadableDataSource<String, List<DegradeRule>> degradeRuleDataSource = new NacosDataSource<>(
nacosConfigService,
"sentinel-demo-service-degrade-rules",
"SENTINEL_GROUP",
source -> JSON.parseObject(source, new TypeReference<List<DegradeRule>>() {})
);
DegradeRuleManager.register2Property(degradeRuleDataSource.getProperty());
}
}

监控与告警

1. 实时监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Component
@Slf4j
public class SentinelMonitor {

private final MeterRegistry meterRegistry;
private final Counter blockCounter;
private final Timer responseTimer;

public SentinelMonitor(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.blockCounter = Counter.builder("sentinel.blocks.total")
.description("Total number of blocked requests")
.register(meterRegistry);
this.responseTimer = Timer.builder("sentinel.response.duration")
.description("Response duration")
.register(meterRegistry);
}

@EventListener
public void handleBlockEvent(BlockException ex) {
blockCounter.increment(
Tags.of(
"resource", ex.getRule().getResource(),
"rule", ex.getRule().getClass().getSimpleName()
)
);
}

public void recordResponseTime(String resource, Duration duration) {
responseTimer.record(duration, Tags.of("resource", resource));
}
}

2. 健康检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Component
public class SentinelHealthIndicator implements HealthIndicator {

@Override
public Health health() {
try {
// 检查Sentinel状态
boolean isEnabled = SentinelConfig.getConfig().isEnabled();

if (isEnabled) {
return Health.up()
.withDetail("sentinel", "enabled")
.withDetail("flowRules", FlowRuleManager.getRules().size())
.withDetail("degradeRules", DegradeRuleManager.getRules().size())
.build();
} else {
return Health.down()
.withDetail("sentinel", "disabled")
.build();
}
} catch (Exception e) {
return Health.down()
.withDetail("sentinel", "error")
.withDetail("error", e.getMessage())
.build();
}
}
}

3. 告警配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
@Component
@Slf4j
public class SentinelAlertService {

@EventListener
public void handleBlockEvent(BlockException ex) {
// 限流告警
if (ex.getRule() instanceof FlowRule) {
sendFlowBlockAlert((FlowRule) ex.getRule());
}

// 熔断告警
if (ex.getRule() instanceof DegradeRule) {
sendDegradeBlockAlert((DegradeRule) ex.getRule());
}

// 系统保护告警
if (ex.getRule() instanceof SystemRule) {
sendSystemBlockAlert((SystemRule) ex.getRule());
}
}

private void sendFlowBlockAlert(FlowRule rule) {
log.warn("流量控制告警: 资源 {} 触发限流,QPS: {}",
rule.getResource(), rule.getCount());

// 发送告警通知
sendAlert("流量控制告警",
String.format("资源 %s 触发限流,QPS: %d",
rule.getResource(), rule.getCount()));
}

private void sendDegradeBlockAlert(DegradeRule rule) {
log.warn("熔断降级告警: 资源 {} 触发熔断", rule.getResource());

// 发送告警通知
sendAlert("熔断降级告警",
String.format("资源 %s 触发熔断", rule.getResource()));
}

private void sendSystemBlockAlert(SystemRule rule) {
log.warn("系统保护告警: 系统负载过高,指标: {}", rule.getMetricType());

// 发送告警通知
sendAlert("系统保护告警",
String.format("系统负载过高,指标: %d", rule.getMetricType()));
}

private void sendAlert(String title, String message) {
// 实现告警发送逻辑
log.info("发送告警: {} - {}", title, message);
}
}

常见问题与解决方案

1. 规则不生效

问题描述: 配置的Sentinel规则没有生效

解决方案:

1
2
3
4
5
6
7
8
# 检查配置
spring:
cloud:
sentinel:
enabled: true # 确保启用Sentinel
transport:
dashboard: localhost:8080
port: 8719
1
2
3
4
5
// 检查资源名称
@SentinelResource(value = "getUserById") // 确保资源名称正确
public User getUser(Long id) {
// 业务逻辑
}

2. 降级不生效

问题描述: 配置的降级规则没有生效

解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 确保fallback方法签名正确
@SentinelResource(
value = "getUserById",
fallback = "handleFallback" // 方法名要正确
)
public User getUser(Long id) {
// 业务逻辑
}

// fallback方法签名必须包含原方法参数和Throwable
public User handleFallback(Long id, Throwable ex) {
// 降级逻辑
}

3. 规则配置丢失

问题描述: 重启后规则配置丢失

解决方案:

1
2
3
4
5
6
7
8
9
10
11
# 使用Nacos作为规则数据源
spring:
cloud:
sentinel:
datasource:
flow:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-flow-rules
groupId: SENTINEL_GROUP
rule-type: flow

4. 性能影响

问题描述: 启用Sentinel后系统性能下降

解决方案:

1
2
3
4
5
6
7
# 调整采样率
spring:
cloud:
sentinel:
sampler:
type: adaptive # 使用自适应采样
count: 1000 # 每秒最多采样1000个请求

最佳实践总结

1. 规则设计原则

  • 合理阈值:根据系统实际能力设置合理的限流阈值
  • 分级保护:对不同重要性的接口设置不同的保护策略
  • 动态调整:根据系统负载动态调整规则参数
  • 监控告警:建立完善的监控和告警机制

2. 降级策略

  • 快速失败:异常时快速返回降级结果
  • 用户体验:降级结果要保证良好的用户体验
  • 数据一致性:降级操作要保证数据的一致性
  • 自动恢复:系统恢复后要能自动恢复正常调用

3. 监控运维

  • 实时监控:监控关键指标和异常情况
  • 趋势分析:分析系统性能趋势和瓶颈
  • 告警机制:建立完善的告警体系
  • 容量规划:基于监控数据进行容量规划

总结

SpringCloudAlibaba Sentinel为微服务架构提供了完整的流量控制和熔断降级解决方案。通过本文的详细讲解,我们了解了:

  1. 核心概念:流量控制、熔断降级的基本原理和作用
  2. 安装配置:Sentinel Dashboard的安装和配置方法
  3. 集成使用:Spring Boot与Sentinel的集成配置
  4. 流量控制:QPS限流、并发线程数限流、热点参数限流
  5. 熔断降级:异常比例、异常数量、响应时间熔断
  6. 系统保护:系统负载保护规则和配置
  7. 规则管理:动态规则配置和数据源管理
  8. 监控告警:实时监控、健康检查、告警配置
  9. 问题解决:常见问题的排查和解决方案
  10. 最佳实践:规则设计、降级策略、监控运维

在实际应用中,建议:

  • 根据系统特点合理设计流量控制和熔断降级规则
  • 建立完善的监控和告警机制
  • 定期分析监控数据,优化系统性能
  • 注意规则配置的持久化和动态更新

通过掌握这些知识和技能,开发者可以构建稳定、可靠的微服务系统,有效应对高并发和异常情况。

参考资料

  1. Sentinel官方文档
  2. SpringCloudAlibaba官方文档
  3. Sentinel Dashboard使用指南
  4. 微服务流量控制最佳实践
  5. Sentinel示例代码