Spring Cloud Alibaba Sentinel
上一篇博客我已经用到Sentinel与OpenFeign结合完成服务降级功能, 只是单纯的使用了他的降级供能,并没有介绍Sentinel详细内容,到底还有什么其他功能, 接下来正式介绍Sentinel:
sentinel官方文档
Sentinel 介绍
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。 Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Sentinel 具有以下特征:
-
丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、实时熔断下游不可用应用等。
-
完备的实时监控: Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
-
广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
-
完善的 SPI 扩展点: Sentinel 提供简单易用、完善的 SPI 扩展点。您可以通过实现扩展点,快速的定制逻辑。例如定制规则管理、适配数据源等。
sentinel适配的主流框架:
具体如何适配,请查看sentinel适配的主流框架文档
其他具体介绍请查看sentinel官方文档
接下来我们实现Sentinel 控制台
Sentinel 控制台文档
Sentinel 控制台提供一个轻量级的控制台,它提供机器发现、单机资源实时监控、集群资源汇总,以及规则管理的功能。您只需要对应用进行简单的配置,就可以使用这些功能。
注意: 集群资源汇总仅支持 500 台以下的应用集群,有大概 1 - 2 秒的延时。
获取控制台工程
可以从 release 页面 下载最新版本的控制台 jar 包。
也可以从最新版本的源码自行构建 Sentinel 控制台:
下载 控制台 工程
使用以下命令将代码打包成一个 fat jar: mvn clean package
启动控制台
Sentinel 控制台是一个标准的 Spring Boot 应用,以 Spring Boot 的方式运行 jar 包即可。
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
如若8080端口冲突,可使用 -Dserver.port=新端口 进行设置。
启动后会进行登录用户名和密码都是sentinel,启动后界面如下:
在控制台中接入我们的应用
上一篇博客就sentinel如何使用进行了基本代码实现,接着上一篇博客的demo实现限流功能, 及控制台动态配置流控规则
demo中我们已经引入sentinel依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
在Sentinel 控制台的文档中要求客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信。可以通过 pom.xml 引入 JAR 包, 但是上面的jar包中已经包含了下面这个jar包,
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>x.y.z</version>
</dependency>
所以我们就不用单独引入这个jar包了
这里我们修改payment-service这个模块
修改application.yml
spring:
profiles:
active: dev
cloud:
nacos: #nacos地址
discovery:
server-addr: 127.0.0.1:8848
sentinel: #sentinel地址
transport:
dashboard: localhost:8080
port: 8720 #这里的 spring.cloud.sentinel.transport.port 端口配置会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了1个限流规则,会把规则数据 push 给这个 Http Server 接收,Http Server 再将规则注册到 Sentinel 中。
server:
port: 8082
# 自定义配置
sleep: 0
添加sentinel限流处理类
package com.hc.paymentservice.exception;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.hc.scacommon.pojo.Balance;
public class SentinelExceptionHandler {
public static Balance blockExceptionHandle(Integer id, BlockException exception) {
exception.printStackTrace();
return new Balance(0, 0, 0, "sentinel限流处理");
}
}
修改controller,在接口方法上添加@SentinelResource
这个注解
package com.hc.paymentservice.controller;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.hc.paymentservice.exception.SentinelExceptionHandler;
import com.hc.scacommon.pojo.Balance;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RefreshScope
public class PaymentController {
@Value("${sleep:0}")
private int sleep;
@Value("${server.port:0}")
private int port;
final static Map<Integer, Balance> balanceMap = new HashMap() {{
put(1, new Balance(1, 10, 1000));
put(2, new Balance(2, 0, 10000));
put(3, new Balance(3, 100, 0));
}
};
/**
*
* @param id
* @return
*/
@SentinelResource(value = "getBalance", entryType = EntryType.OUT, blockHandlerClass = SentinelExceptionHandler.class, blockHandler = "blockExceptionHandle")
@RequestMapping("/pay/balance")
public Balance getBalance(Integer id) {
System.out.println("request: " + port + ", /pay/balance?id=" + id + ", sleep: " + sleep);
if(sleep > 0) {
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(id != null && balanceMap.containsKey(id)) {
return balanceMap.get(id);
}
return new Balance(0, 0, 0);
}
}
注解介绍
在具体配置之前介绍一下一个非常重要的注解:@SentinelResource
@SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项。 @SentinelResource 注解包含以下属性:
- value: 资源名称,必需项(不能为空)
- entryType: 入口类型,可选项: EntryType.IN和EntryType.OUT(默认为 EntryType.OUT)
- blockHandler / blockHandlerClass: blockHandler 对应处理 BlockException 的函数名称,可选项。若未配置,则将 BlockException 直接抛出。blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
- fallback: fallback 函数名称,可选项,仅针对降级功能生效(DegradeException)。fallback 函数的访问范围需要是 public,参数类型和返回类型都需要与原方法相匹配,并且需要和原方法在同一个类中。业务异常不会进入 fallback 逻辑。
说明:
- value:定义资源名,该名称将会显示在控制台中,并且在定义流控以及熔断降级规则时,指定资源名
- blockHandler是异常处理的方法,默认需要与原方法在同一个类中,如果需要在另外的类中定义,则需要设置blockHandlerClass,并且噶异常处理的方法应为静态方法。
启动payment-service
这个时候刷新控制台,可能不会出现payment-service这个应用
我们多访问几次http://localhost:8082/pay/balance?id=1 , 再刷新控制台
查看链路如上图
选择链路添加流控规则, 这里我们再代码中已经再资源中指定了getBalance这个资源的限流名称, 刚好value对应得是getBalance,所有我们可以直接再这里点击getBalance这个链路的**+流控**来添加规则
也可以点击左边的菜单 流控规则 添加
这里我配置的是getBalance这个资源一秒中只能通过一次
我们快速刷新几次http://localhost:8082/pay/balance?id=1
看看结果
快速请求一秒钟请求多次
查看控制台
下一篇将实现sentinel熔断处理