为什么使用sentinel
通过流量控制、熔断降级、系统负载保护等多个维度来保障服务之间的稳定性。
服务限流 :当系统资源不够,不足以应对大量请求,对系统按照预设的规则进行流量限制或功能限制
服务熔断:当调用目标服务的请求和调用大量超时或失败,服务调用方为避免造成长时间的阻塞造成影响其他服务,后续对该服务接口的调用不再经过进行请求,直接执行本地的默认方法
服务降级:为了保证核心业务在大量请求下能正常运行,根据实际业务情况及流量,对部分服务降低优先级,有策略的不处理或用简单的方式处理
首先看限流
流量控制(Flow Control),原理是监控应用流量的QPS或并发线程数等指标,当达到指定阈值时对流量进行控制,避免系统被瞬时的流量高峰冲垮,保障应用高可用性。
具体应用
前台通过调用文章展示服务来展示文章列表及浏览文章及做一些操作,当前台流量很大的时候,通过限流来限制调用后台服务,防止超过后台负荷,造成宕机!
现在来做后台服务限流
依赖
pom
添加sentinel jar 包
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
配置
bootstrap
server:
port: 9070
spring:
profiles:
active: dev
application:
name: ap-artical
main:
allow-bean-definition-overriding: true
cloud:
nacos:
discovery:
username: nacos
password: nacos
server-addr: 172.17.169.81:8848
namespace: b561281a-fb95-411e-b75b-cf36bfc90854
group: ATICAL_CLNEWS_DEV_GROUP
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
file-extension: yml
namespace: ${spring.cloud.nacos.discovery.namespace}
group: ${spring.cloud.nacos.discovery.group}
shared-configs[0]:
data-id: user-prompt-info.yml # 配置文件名-Data Id
group: ${spring.cloud.nacos.discovery.group} # 默认为DEFAULT_GROUP
refresh: true # 是否动态刷新,默认为false
sentinel:
transport:
port: 8719 # spring.cloud.sentinel.transport.port 端口配置会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了1个限流规则,会把规则数据 push 给这个 Http Server 接收,Http Server 再将规则注册到 Sentinel 中
dashboard: 127.0.0.1:5003
eager: true
添加这一部分
sentinel:
transport:
port: 8719 # spring.cloud.sentinel.transport.port 端口配置会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了1个限流规则,会把规则数据 push 给这个 Http Server 接收,Http Server 再将规则注册到 Sentinel 中
dashboard: 127.0.0.1:5003
eager: true
代码
在要限制的资源上面添加注解
@SentinelResource(value = “articleList”)
并加一些配置
@SentinelResource注解最主要的两个用法:限流控制和熔断降级。另外,该注解还有一些其他更精细化的配置,比如忽略某些异常的配置、默认降级函数等等,具体可见如下说明:
- value:资源名称,必需项(不能为空)
- entryType:entry类型,可选项(默认为 EntryType.OUT)
- fallback:fallback函数名称,可选项,用于在抛出异常的时候提供 fallback处理逻辑。fallback函数可以针对所有类型的异常(除了exceptionsToIgnore里面排除掉的异常类型)进行处理。
-
- fallback函数签名和位置要求: 返回值类型必须与原函数返回值类型一致;方法参数列表需要和原函数一致,或者可以额外多一个 Throwable类型的参数用于接收对应的异常。
- fallback函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass为对应的类的 Class 对象,注意对应的函数必需为 static函数,否则无法解析。
- defaultFallback(since 1.6.0):默认的 fallback函数名称,可选项,通常用于通用的 fallback逻辑(即可以用于很多服务或方法)。默认 fallback函数可以针对所有类型的异常(除了exceptionsToIgnore里面排除掉的异常类型)进行处理。若同时配置了 fallback和 defaultFallback,则只有 fallback会生效。
- defaultFallback函数签名要求:返回值类型必须与原函数返回值类型一致;
方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。 - defaultFallback函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
- exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。
/**
* 列表查询(非分页)
*
* @return
*/
@RequestMapping("/list")
@SentinelResource(value = "articleList",
blockHandlerClass = ApArticleBlockHandler.class,
blockHandler = "blockHandler",
fallbackClass = ApArticleFallback.class,
fallback = "fallback")
public R list() {
ApArticle model = new ApArticle();
List<ApArticle> list = iApArticleService.list();
// todo 再包装一层
return R.ok(list);
}
import com.alibaba.csp.sentinel.slots.block.BlockException;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ApArticleBlockHandler{
// 要求:
// 1 当前方法的返回值和参数要跟原方法一致
// 2 参数列表的最后,允许添加一个BlockException参数,用来接收原方法中发生的Sentinel异常
// 3 需要用static修饰
public static R blockHandler( BlockException e) {
log.error("BlockException catch. actual exception type={}", e.getClass().getSimpleName());
return R.faile("BlockException ");
}
}
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ApArticleFallback{
// 要求:
// 1 当前方法的返回值和参数要跟原方法一致
// 2 参数列表的最后,允许添加一个Throwable参数,用来接收原方法中发生的异常
// 3 需要用static修饰
public static R fallback(Throwable throwable) {
log.error("业务异常。信息如下:{}", throwable.getMessage());
return R.faile("Throwable");
}
}
运行测试
登陆sentinel控制台配置限流
这里只演示限流异常,这服务有个问题,当服务重启的时候,原来配置的限流操作没有存储,下面我们改造sentinel服务,持久化后再演示其他限流及熔断。