Sentinel基础入门
Sentinel基础入门
前置知识
在开始本教程之前,建议您具备以下基础知识:
- Java基础和Spring Boot基础
- Spring Cloud基本概念
- 微服务架构基础知识
- Maven或Gradle构建工具使用经验
什么是Sentinel?
Sentinel(哨兵)是阿里巴巴开源的一款面向分布式服务架构的流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来保障微服务的稳定性。
Sentinel的核心特性

Sentinel具有以下核心特性:
丰富的应用场景:Sentinel承接了阿里巴巴近10年的双十一大促流量的核心场景,例如秒杀(突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
完备的实时监控:Sentinel提供了实时的监控功能,可以看到接入应用的单台机器秒级数据,甚至500台以下规模的集群的汇总运行情况。
广泛的开源生态:Sentinel提供开箱即用的与其它开源框架/库的整合模块,例如与Spring Cloud、Dubbo、gRPC的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入Sentinel。
完善的SPI扩展点:Sentinel提供简单易用、完善的SPI扩展接口。您可以通过实现扩展点,快速的定制逻辑。例如定制规则管理、适配数据源等。
Sentinel与Hystrix的对比
作为微服务流量控制和熔断降级的两大主流框架,Sentinel和Hystrix各有特点:
对比项 | Sentinel | Hystrix |
---|---|---|
隔离策略 | 信号量隔离 | 线程池隔离/信号量隔离 |
熔断降级策略 | 基于响应时间或失败比率 | 基于失败比率 |
实时指标实现 | 滑动窗口 | 滑动窗口(基于RxJava) |
规则配置 | 支持多种数据源 | 支持多种数据源 |
扩展性 | 多个扩展点 | 插件的形式 |
基于注解的支持 | 支持 | 支持 |
限流 | 基于QPS,支持基于调用关系的限流 | 有限的支持 |
流量整形 | 支持慢启动、匀速器模式 | 不支持 |
系统自适应保护 | 支持 | 不支持 |
控制台 | 开箱即用,可配置规则、查看秒级监控、机器发现等 | 需要整合其它组件 |
Sentinel的基本概念
资源
资源是Sentinel的关键概念。它可以是Java应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。
只要通过Sentinel API定义的代码,就是资源,能够被Sentinel保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标识资源。
规则
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。
环境准备
1. 添加依赖
在您的Spring Boot项目的pom.xml
中添加以下依赖:
<!-- Spring Cloud Alibaba Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>${spring-cloud-alibaba.version}</version>
</dependency>
<!-- Sentinel控制台 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>${sentinel.version}</version>
</dependency>
在properties
标签中添加版本信息:
<properties>
<spring-cloud-alibaba.version>2021.0.5.0</spring-cloud-alibaba.version>
<sentinel.version>1.8.6</sentinel.version>
</properties>
2. 配置Sentinel控制台
Sentinel提供了一个轻量级的开源控制台,它提供机器发现、单机资源实时监控、集群资源汇总,以及规则管理的功能。
下载并启动控制台
- 从GitHub Release页面下载最新版本的控制台jar包
- 使用以下命令启动控制台:
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
启动成功后,可以通过访问http://localhost:8080
来访问控制台,默认用户名和密码都是sentinel
。
配置应用连接到控制台
在application.yml
或application.properties
中添加以下配置:
spring:
cloud:
sentinel:
transport:
# 控制台地址
dashboard: localhost:8080
# 客户端监控API的端口,默认8719
port: 8719
# 取消Sentinel控制台懒加载
eager: true
快速入门
创建一个简单的Spring Boot应用
首先,让我们创建一个简单的Spring Boot应用,并集成Sentinel。
1. 创建项目结构
src/main/java/com/example/sentinel/
├── SentinelDemoApplication.java
├── controller/
│ └── HelloController.java
└── service/
└── HelloService.java
2. 编写启动类
package com.example.sentinel;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SentinelDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SentinelDemoApplication.class, args);
}
}
3. 编写服务类
package com.example.sentinel.service;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.stereotype.Service;
@Service
public class HelloService {
@SentinelResource(value = "sayHello", blockHandler = "sayHelloBlockHandler")
public String sayHello(String name) {
return "Hello, " + name;
}
// 注意:blockHandler方法的参数和返回值必须与原方法一致,最后加一个BlockException参数
public String sayHelloBlockHandler(String name, BlockException ex) {
return "Sorry, " + name + ", you are blocked by Sentinel: " + ex.getClass().getSimpleName();
}
}
4. 编写控制器
package com.example.sentinel.controller;
import com.example.sentinel.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@Autowired
private HelloService helloService;
@GetMapping("/hello/{name}")
public String hello(@PathVariable String name) {
return helloService.sayHello(name);
}
}
5. 配置Sentinel注解支持
为了使@SentinelResource
注解生效,我们需要添加以下配置类:
package com.example.sentinel;
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SentinelConfig {
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
测试应用
- 启动Sentinel控制台
- 启动应用程序
- 访问
http://localhost:8080/hello/world
多次 - 登录Sentinel控制台,可以看到应用已经注册,并且可以看到
sayHello
资源
Sentinel核心原理
工作流程
Sentinel的工作流程如下图所示:

Sentinel的核心骨架如下:
- 资源定义:通过
SphU.entry()
或@SentinelResource
定义资源 - 规则配置:通过控制台或代码配置规则
- 检验请求:根据规则检验请求是否允许通过
- 统计数据:统计请求的通过和拒绝情况
- 规则判断:根据统计数据和规则进行判断
Sentinel的主要模块
Sentinel主要分为以下几个模块:
- 核心模块(sentinel-core):提供了基本的资源定义、规则配置、统计数据等功能
- 传输模块(sentinel-transport):提供了与控制台通信的功能
- 扩展模块(sentinel-extension):提供了与其他框架集成的功能
- 适配器模块(sentinel-adapter):提供了与其他框架适配的功能
- 控制台模块(sentinel-dashboard):提供了可视化的控制台
与Spring Cloud的集成
Sentinel与Spring Cloud的集成非常简单,只需要添加相应的依赖并进行简单的配置即可。
1. 添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2. 配置
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080
# 取消Sentinel控制台懒加载
eager: true
# 配置Sentinel的日志目录
log:
dir: logs/sentinel
3. 使用@SentinelResource注解
@SentinelResource
注解用于定义资源,并提供了blockHandler
和fallback
等属性来处理不同的异常情况。
@SentinelResource(
value = "resourceName",
blockHandler = "blockHandlerMethod",
fallback = "fallbackMethod"
)
public String method(String param) {
return "Hello " + param;
}
// 处理BlockException的方法
public String blockHandlerMethod(String param, BlockException ex) {
return "Block by Sentinel: " + ex.getClass().getSimpleName();
}
// 处理所有异常的方法
public String fallbackMethod(String param, Throwable throwable) {
return "Fallback: " + throwable.getMessage();
}
实战案例:电商订单服务
下面我们通过一个简单的电商订单服务来演示Sentinel的使用。
项目结构
src/main/java/com/example/sentinel/
├── SentinelDemoApplication.java
├── config/
│ └── SentinelConfig.java
├── controller/
│ └── OrderController.java
├── service/
│ ├── OrderService.java
│ └── PaymentService.java
└── model/
├── Order.java
└── Payment.java
模型类
package com.example.sentinel.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Order {
private Long id;
private String productName;
private Integer quantity;
private Double amount;
private String status;
}
package com.example.sentinel.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Payment {
private Long id;
private Long orderId;
private Double amount;
private String status;
}
服务类
package com.example.sentinel.service;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.sentinel.model.Order;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Service
public class OrderService {
private final Map<Long, Order> orders = new ConcurrentHashMap<>();
@SentinelResource(value = "createOrder", blockHandler = "createOrderBlockHandler")
public Order createOrder(String productName, Integer quantity, Double amount) {
// 模拟订单创建
long orderId = System.currentTimeMillis();
Order order = new Order(orderId, productName, quantity, amount, "CREATED");
orders.put(orderId, order);
return order;
}
public Order createOrderBlockHandler(String productName, Integer quantity, Double amount, BlockException ex) {
// 被限流或降级时的处理逻辑
return new Order(0L, productName, quantity, amount, "BLOCKED");
}
@SentinelResource(value = "getOrders", blockHandler = "getOrdersBlockHandler")
public List<Order> getOrders() {
// 模拟查询所有订单
return new ArrayList<>(orders.values());
}
public List<Order> getOrdersBlockHandler(BlockException ex) {
// 被限流或降级时的处理逻辑
return new ArrayList<>();
}
@SentinelResource(value = "getOrderById", blockHandler = "getOrderByIdBlockHandler")
public Order getOrderById(Long id) {
// 模拟根据ID查询订单
return orders.getOrDefault(id, new Order(id, "Unknown", 0, 0.0, "NOT_FOUND"));
}
public Order getOrderByIdBlockHandler(Long id, BlockException ex) {
// 被限流或降级时的处理逻辑
return new Order(id, "Blocked", 0, 0.0, "BLOCKED");
}
}
package com.example.sentinel.service;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.sentinel.model.Payment;
import org.springframework.stereotype.Service;
@Service
public class PaymentService {
@SentinelResource(value = "processPayment", blockHandler = "processPaymentBlockHandler")
public Payment processPayment(Long orderId, Double amount) {
// 模拟支付处理
try {
// 模拟处理延迟
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return new Payment(System.currentTimeMillis(), orderId, amount, "SUCCESS");
}
public Payment processPaymentBlockHandler(Long orderId, Double amount, BlockException ex) {
// 被限流或降级时的处理逻辑
return new Payment(0L, orderId, amount, "PAYMENT_BLOCKED");
}
}
控制器
package com.example.sentinel.controller;
import com.example.sentinel.model.Order;
import com.example.sentinel.model.Payment;
import com.example.sentinel.service.OrderService;
import com.example.sentinel.service.PaymentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/orders")
public class OrderController {
@Autowired
private OrderService orderService;
@Autowired
private PaymentService paymentService;
@PostMapping
public Order createOrder(@RequestParam String productName,
@RequestParam Integer quantity,
@RequestParam Double amount) {
return orderService.createOrder(productName, quantity, amount);
}
@GetMapping
public List<Order> getOrders() {
return orderService.getOrders();
}
@GetMapping("/{id}")
public Order getOrderById(@PathVariable Long id) {
return orderService.getOrderById(id);
}
@PostMapping("/{orderId}/payment")
public Payment processPayment(@PathVariable Long orderId, @RequestParam Double amount) {
return paymentService.processPayment(orderId, amount);
}
}
配置类
package com.example.sentinel.config;
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SentinelConfig {
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
应用配置
server:
port: 8081
spring:
application:
name: sentinel-demo
cloud:
sentinel:
transport:
dashboard: localhost:8080
eager: true
management:
endpoints:
web:
exposure:
include: '*'
测试应用
- 启动Sentinel控制台
- 启动应用程序
- 使用以下命令测试API:
# 创建订单
curl -X POST "http://localhost:8081/orders?productName=iPhone&quantity=1&amount=999.99"
# 获取所有订单
curl "http://localhost:8081/orders"
# 获取指定订单
curl "http://localhost:8081/orders/123456789"
# 处理支付
curl -X POST "http://localhost:8081/orders/123456789/payment?amount=999.99"
- 登录Sentinel控制台,配置流控规则
常见问题
注意事项
- 控制台与应用连接问题:确保应用正确配置了控制台地址,并且网络连接正常
- 规则持久化:默认情况下,规则存储在内存中,应用重启后会丢失,建议配置规则持久化
- @SentinelResource注解不生效:确保已经配置了
SentinelResourceAspect
的Bean
1. 如何解决Sentinel控制台无法显示应用的问题?
可能的原因和解决方案:
- 检查应用是否正确配置了控制台地址
- 确保应用和控制台之间的网络连接正常
- 检查应用是否有足够的流量触发Sentinel的初始化
- 尝试设置
spring.cloud.sentinel.eager=true
取消懒加载 - 检查应用日志中是否有Sentinel相关的错误信息
2. Sentinel规则如何持久化?
Sentinel支持多种数据源进行规则持久化,包括:
- 文件数据源
- Nacos数据源
- ZooKeeper数据源
- Apollo数据源
- Redis数据源
具体配置方法将在后续文章中详细介绍。
总结
本文介绍了Sentinel的基本概念、核心特性和环境搭建,并通过一个简单的电商订单服务演示了Sentinel的使用。Sentinel作为一款强大的流量控制组件,可以帮助我们保障微服务的稳定性。
在下一篇文章中,我们将深入探讨Sentinel的流量控制和熔断降级功能,敬请期待!
下一步学习
- 学习Sentinel的流量控制详解
- 了解Sentinel的熔断降级机制
- 探索Sentinel的热点参数限流
- 掌握Sentinel的系统自适应保护