Sentinel概述
基本介绍
Sentinel是阿里巴巴开源的一款微服务流量控制组件。官网地址:home | Sentinel
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。
Sentinel 具有以下特征:
•丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
•完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
•广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
•完善的SPI扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等
早期比较流行的是Hystrix框架,但目前国内实用最广泛的还是阿里巴巴的Sentinel框架,这里我们做下对比:
Sentinel | Hystrix | |
隔离策略 | 信号量隔离 | 线程池隔离/信号量隔离 |
熔断降级策略 | 基于慢调用比例或异常比例 | 基于失败比率 |
实时指标实现 | 滑动窗口 | 滑动窗口(基于 RxJava) |
规则配置 | 支持多种数据源 | 支持多种数据源 |
扩展性 | 多个扩展点 | 插件的形式 |
基于注解的支持 | 支持 | 支持 |
限流 | 基于 QPS,支持基于调用关系的限流 | 有限的支持 |
流量整形 | 支持慢启动、匀速排队模式 | 不支持 |
系统自适应保护 | 支持 | 不支持 |
控制台 | 开箱即用,可配置规则、查看秒级监控、机器发现等 | 不完善 |
常见框架的适配 | Servlet、Spring Cloud、Dubbo、gRPC 等 | Servlet、Spring Cloud Netflix |
Sentinel 基本核心概念
资源
资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。
只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。
规则
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。
Sentinel安装
简单安装启动
sentinel官方提供了UI控制台,方便我们对系统做限流设置。可以在GitHub下载。
Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。这里,我们将会详细讲述如何通过简单的步骤就可以使用这些功能。
Sentinel 控制台包含如下功能:
- 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。
- 监控 (单机和集群聚合):通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。
- 规则管理和推送:统一管理推送规则。
- 鉴权:生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。
下载地址: https://github.com/alibaba/Sentinel/releases
将jar包放到任意非中文目录
启动jar包:
java -jar sentinel-dashboard-1.8.1.jar
指定端口:
java -jar sentinel-dashboard-1.8.1.jar -Dserver.port=8090
修改其他配置看官网: https://sentinelguard.io/zh-cn/
访问 localhost:8080 默认账号密码都是:sentinel
可以看到现在是一片空白的,稍后整合服务以后就可以出现信息的。
启动配置项
Sentinel 提供如下的配置方式:
- JVM -D 参数方式
- properties 文件方式(1.7.0 版本开始支持)
其中,project.name
参数只能通过 JVM -D 参数方式配置(since 1.8.0 取消该限制),其它参数支持所有的配置方式。
优先级顺序:JVM -D 参数的优先级最高。若 properties 和 JVM 参数中有相同项的配置,以 JVM 参数配置的为准。
用户可以通过 -Dcsp.sentinel.config.file
参数配置 properties 文件的路径,支持 classpath 路径配置(如 classpath:sentinel.properties
)。默认 Sentinel 会尝试从 classpath:sentinel.properties
文件读取配置,读取编码默认为 UTF-8。
如果要修改Sentinel的默认端口、账户、密码,可以通过下列配置:
配置项 | 默认值 | 说明 |
server.port | 8080 | 服务端口 |
sentinel.dashboard.auth.username | sentinel | 默认用户名 |
sentinel.dashboard.auth.password | sentinel | 默认密码 |
SpringCloud简单整合
实战架构
我们进行整合的时候,先搭建一个简单的微服务项目架构。
俩个为俩个不同的端口的service端,客户端向8002端口的studentservice发送一个请求(/getInfo/{id})以后,8002端口的studentservice需要往teacherservice发送一个请求(/getTeacher/{id})返回数据。
父工程pom文件
统一管理版本信息
<groupId>org.example</groupId> <artifactId>eurek-test</artifactId> <version>1.0-SNAPSHOT</version> <modules> <module>eurek-serve</module> <module>student-service</module> <module>teacher-service</module> </modules> <packaging>pom</packaging> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.12.RELEASE</version> <relativePath/> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR10</spring-cloud.version> <mysql.version>5.1.47</mysql.version> <mybatis.version>2.1.1</mybatis.version> </properties> <dependencyManagement> <dependencies> <!-- springCloud --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!--nacos的管理依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.5.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies>
teacher-service服务
pom文件
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- nacos客户端依赖包 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> </dependencies>
启动类
@SpringBootApplication public class TeacherApplication { public static void main(String[] args) { SpringApplication.run(TeacherApplication.class,args); } }
yml配置文件
server: port: 8002 spring: application: name: teacherservice cloud: nacos: server-addr: localhost:8848
Teacher类
@Data @AllArgsConstructor @NoArgsConstructor public class Teacher implements Serializable { private String name; private String sex; }
TeachertController
@RestController public class TeacherController { @GetMapping("/getTeacher/{id}") public Teacher getInfo(@PathVariable("id") String id){ return new Teacher("张三-"+id,"男"); } }
student-service服务
pom文件
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- nacos客户端依赖包 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies>
yml配置文件
server: port: 8002 spring: application: name: studentservice cloud: nacos: server-addr: localhost:8848
启动类
@SpringBootApplication @EnableFeignClients public class StudentApplication { public static void main(String[] args) { SpringApplication.run(StudentApplication.class,args); } }
Teacher类
@Data @AllArgsConstructor @NoArgsConstructor public class Teacher implements Serializable { private String name; private String sex; }
TeacherServiceFeign
@FeignClient("teacherservice") public interface TeacherServiceFeign { @GetMapping("/getTeacher/{id}") Teacher getInfo(@PathVariable("id") String id); }
个客户端主要是基于SpringMVC的注解来声明远程调用的信息,比如:
- 服务名称:teacherservice
- 请求方式:GET
- 请求路径:/getTeacher/{id}
- 请求参数:String id
- 返回值类型:Teacher
这样,Feign就可以帮助我们发送http请求,无需自己使用RestTemplate来发送了。
StudentController
@RestController public class StudentController implements Serializable { @Autowired TeacherServiceFeign teacherServiceFeign; @GetMapping("/getInfo") public Teacher getInfo(){ Teacher teacher = teacherServiceFeign.getInfo("111"); return teacher; } }
测试
GET http://localhost:8002/getInfo HTTP/1.1 200 Content-Type: application/json Transfer-Encoding: chunked Date: Tue, 17 Oct 2023 02:46:43 GMT Keep-Alive: timeout=60 Connection: keep-alive { "name": "张三-111", "sex": "男" }
整合Sentinel
我们在student-service服务的pom文件中添加以下依赖:
<!--sentinel--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
修改application.yaml文件,添加下面内容:
server: port: 8088 spring: cloud: sentinel: transport: dashboard: localhost:8080
重新启动student-service。
GET http://localhost:8002/getInfo HTTP/1.1 200 Content-Type: application/json Transfer-Encoding: chunked Date: Thu, 26 Oct 2023 02:58:44 GMT Keep-Alive: timeout=60 Connection: keep-alive { "name": "张三-111", "sex": "男" }
查看sentinel控制台:
但注意默认只有controller中的方法会被监控,Service层的方法没有被监控,也就不能配置限流规则,要标记其它方法,需要利用@SentinelResource注解。
链路模式中,是对不同来源的两个链路做监控。但是sentinel默认会给进入SpringMVC的所有请求设置同一个root资源,会导致链路模式失效。
我们需要关闭这种对SpringMVC的资源聚合,修改服务的application.yml文件:
spring: cloud: sentinel: web-context-unify: false # 关闭context整合