文章目录
- 前言
- 一、Sentinel
- 1、什么是Sentinel
- 2、项目配置
- 3、使用案例
- 3.1、流控
- 3.2、降级
- 3.3、黑白名单设置
- 二、Zipkin
- 1、什么是Zipkin
- 2、项目配置
- 3、整合案例
前言
本篇介绍Spring Cloud Ali的sentinel组件,用于对微服务的熔断降级,以及链路追踪zipkin的使用,对应视频P326-P338
。本篇为谷粒商城分布式高级部分的最后一篇,重点在于sentinel和zipkin在项目中的运用。后续更新集群部署篇
。
一、Sentinel
1、什么是Sentinel
Sentinel是Spring Cloud Ali的组件,主要用于分布式系统中的流量控制、熔断降级和系统监控。在原生Spring Cloud中,是Hystrix
承担着同样的作用。Sentinel 的主要概念和功能:
- 流量控制:Sentinel 通过
限流策略
控制请求的数量,其中常见的限流策略有:QPS(每秒请求数),并发线程数,令牌桶和漏斗算法。 - 熔断与降级:在系统出现异常(如请求超时或错误率过高)时,Sentinel 可以自动触发熔断机制,拒绝后续请求以保护系统。降级功能允许你在系统负载过高时,自动将某些服务的请求转向较简单的处理,保障系统的整体可用性。
其中限流策略,QPS
是通过控制台设定某个资源每秒允许的最大请求数量,超出这个数量的请求会被拒绝或延迟。而并发线程数
则是通过限制同一时刻可以处理的请求数量来实现流量控制。令牌桶算法
则是请求的到来需要从桶中获取令牌。令牌以固定的速率生成,当请求到来时,需要消耗一个令牌才能通过。如果没有可用的令牌,请求会被拒绝或延迟。漏斗算法
通过维护一个“漏斗”来控制请求的流入速率。请求以恒定的速率流入漏斗,当请求超过漏斗容量时,多余的请求会被拒绝。
而熔断
主要体现在,A服务调用B服务,如果B服务长时间没有返回响应,或者直接出现错误,则会直接返回失败,后续A也不会再调用B服务了。在熔断状态持续一段时间后,熔断器会进入“半开”
状态。在这个状态下,系统会允许一部分请求(例如,1%或2%的请求)尝试访问该服务,以检查服务是否已恢复。如果这些请求成功,则熔断器会完全恢复,重新允许所有请求。如果请求仍然失败,熔断器将保持熔断状态,继续拒绝请求。降级
主要体现在,例如双11电商系统访问量激增,而主要的业务可能体现在下单,秒杀,后端服务可能无法承受大量请求。此时可以选择对一些非核心功能进行降级,将用户的某些请求引导到默认的页面(实现服务的基本可用)。
2、项目配置
需要在项目中运用Sentinel,首先引入依赖(我是直接加入到了common模块下,注意,common模块中加入了某项依赖,除了需要刷新common模块,还需要刷新所有引用了common模块的微服务maven,否则可能不会生效):
<!-- 开启sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- sentinel的图表统计-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.1.8.RELEASE</version>
</dependency>
并且配置文件中加入:
# 控制台的端口号
spring.cloud.sentinel.transport.dashboard=localhost:8080
spring.cloud.sentinel.transport.port=8719
#使用 * 表示允许所有管理端点都被暴露。即所有可用的 Actuator 端点都将通过 web 访问。
management.endpoints.web.exposure.include=*
## 开启远程调用支持
feign.sentinel.enabled=true
如果需要在网页上通过可视化界面进行操作,则需要下载sentinel的dashboard,使用java -jar 运行,默认是8080端口。如果有冲突可以自行修改:
访问localhost:8080
进入控制台
3、使用案例
3.1、流控
启动服务,在浏览器中直接访问某个链接:
在控制台配置流控规则:
设置1s只能访问一次:
同时可以自定义配置降级页面;
@Configuration
public class SeckillSentinelConfig {
public SeckillSentinelConfig() {
WebCallbackManager.setUrlBlockHandler((httpServletRequest, httpServletResponse, e) -> {
R error = R.error(ExceptionEnum.TOO_MANY_REQUEST_EXCEPTION.getCode(), ExceptionEnum.TOO_MANY_REQUEST_EXCEPTION.getValue());
httpServletResponse.setContentType("application/json;charset=utf-8");
httpServletResponse.getWriter().write(JSON.toJSONString(error));
});
}
}
1s内多次刷新页面,说明流控规则生效:
sentinel也提供了多种定义受保护资源
的方式,包括jdk8的新特性try-with-resource,以及@SentinelResource
注解:
try-with-resource
定义受保护资源的用法:
public SecKillSkuRedisTO getCurrentSeckillSkuById(Long skuId) {
//定义受保护的资源方式一
try(Entry entry = SphU.entry("getCurrentSeckillSkuById")) {
//自己的业务逻辑
} catch (BlockException e) {
log.info("{}:流控规则生效","getCurrentSeckillSkuById");
}
return null;
}
@SentinelResource
注解定义受保护资源的用法:
/**
* 创建流控规则方式二
* @param ex
* @return
*/
public List<SecKillSkuRedisTO> CurrentSeckillSkusHandler(BlockException ex) {
log.info("{}:流控规则生效","getCurrentSeckillSkus");
return null;
}
@Override
@SentinelResource(value = "getCurrentSeckillSkus",blockHandler = "CurrentSeckillSkusHandler")
public List<SecKillSkuRedisTO> getCurrentSeckillSkus() {
//自己的业务逻辑
}
3.2、降级
可基于响应时间,异常数,异常比例设定降级策略:
例如基于异常数,如图所示,只要出现1个异常,就触发降级,降级持续时间为1000ms:
对于被保护的资源,手动抛出一个异常:
@GetMapping("/currentSeckillSkus")
public R getCurrentSeckillSkus(){
int i = 1/0;
List<SecKillSkuRedisTO> secKillSkuRedisTOS = secKillSkuService.getCurrentSeckillSkus();
return R.ok().put("data",secKillSkuRedisTOS);
}
由于出现了异常,第一次访问就出现了自定义的降级提示,也就是降级的操作生效了
3.3、黑白名单设置
sentinel也支持对于访问受保护资源的权限进行控制,例如假设我访问的路径中包含currentSeckillSkus
,则不允许访问,直接返回失败,则需要进行配置:
@Component
public class RequestOriginParserImpl implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest httpServletRequest) {
String requestURI = httpServletRequest.getRequestURI();
if (requestURI.contains("/currentSeckillSkus")) {
return "blackList";
}
return "whiteList";
}
}
控制台加入流控应用
再次访问被拦截,直接进入失败页面
以上就是关于sentinel的简单用法的案例演示,同时需要提醒注意的是,在 Sentinel 中,默认情况下流控规则和配置是在内存
中存储的,因此每次应用重启后,原有的流控规则会丢失。所以我们需要配置持久化策略,常见的有持久化入数据库,或是Redis。
而对于feign远程调用的熔断,个人理解通常应该是在调用方进行设置。如果设置在被调用方,可能会存在一种情况,即A和B两个服务同时调用C,而A对于C的访问频率大于B对于C的访问频率,如果是在C进行熔断设置,则有可能导致B无法正常访问C。
二、Zipkin
1、什么是Zipkin
Zipkin是一个用于链路追踪的组件,可以追踪一个请求在微服务架构中的整个生命周期,包括其经过的服务、调用时间和执行顺序,并且提供了详细的执行时间信息以及错误记录。
下面介绍几个Zipkin 中的概念:
Span
是 Zipkin 中的基本概念,表示一次请求的执行过程。每个 Span 包含信息,如开始时间、结束时间、执行状态和标签等。一个请求通常由多个 Span 组成,每个服务调用都生成一个 Span。Trace
是由一系列相关的 Span 组成的完整请求路径。一个 Trace 描述了请求在微服务中的完整执行过程。- 在 Span 中,开发者可以添加不同的注解(Annotations),用于记录特定事件(如请求开始、结束、错误等)。这些注解可以帮助更好地理解请求的执行过程。
Span中的Annotations有:
- cs (Client Send):表示客户端发送请求的时间。
- cr (Client Receive):表示客户端接收到响应的时间。
- ss (Server Send):表示服务器发送响应的时间。
- sr (Server Receive):表示服务器接收到请求的时间。
通过sr-cs
,可以计算出发送请求所消耗的时间,通过ss-cr
,可以计算出服务端处理业务消耗的时间,通过cr-ss
,可以计算出响应请求消耗的时间。
在Zipkin中如何自定义一个Annotations?下面是一个简单的案例:
@Service
public class MyService {
@Autowired
private Tracer tracer;
public void myMethod() {
// 获取 Span,并开始一个新的 Span
Span span = tracer.nextSpan().name("myMethod").start();
try {
// 添加自定义 Annotation
span.annotate("Starting processing"); // 自定义开始处理的注解
// 模拟处理逻辑
processBusinessLogic();
span.annotate("Processing completed"); // 自定义处理完成的注解
} catch (Exception e) {
span.error(e); // 记录异常
} finally {
span.finish(); // 结束 Span
}
}
private void processBusinessLogic() {
// 业务处理逻辑
}
}
2、项目配置
在docker或本地安装Zipkin服务器,实现页面可视化监控
docker run -d -p 9411:9411 openzipkin/zipkin
引入依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
配置文件中添加:
logging.level.org.springframework.cloud.openfeign: debug
logging.level.org.springframework.cloud.sleuth: debug
spring.zipkin.base-url= http://自己的虚拟机地址:9411/
#不将zipkin自身进行注册
spring.zipkin.discovery-client-enabled=false
spring.zipkin.sender.type=web
#抽样统计因子,1为全部统计
spring.sleuth.sampler.probability=1
3、整合案例
整合完成后重启项目,执行业务,登录控制台页面,即可查看对应业务调用的链路信息,包括开始时间,结束时间,远程调用,异步调用信息,都会有所体现。
下一篇:k8s