谷粒商城のsentinel&zipkin

文章目录


前言

本篇介绍Spring Cloud Ali的sentinel组件,用于对微服务的熔断降级,以及链路追踪zipkin的使用,对应视频P326-P338。本篇为谷粒商城分布式高级部分的最后一篇,重点在于sentinel和zipkin在项目中的运用。后续更新集群部署篇


一、Sentinel

1、什么是Sentinel

Sentinel是Spring Cloud Ali的组件,主要用于分布式系统中的流量控制、熔断降级和系统监控。在原生Spring Cloud中,是Hystrix承担着同样的作用。Sentinel 的主要概念和功能:

  1. 流量控制:Sentinel 通过限流策略控制请求的数量,其中常见的限流策略有:QPS(每秒请求数),并发线程数,令牌桶和漏斗算法。
  2. 熔断与降级:在系统出现异常(如请求超时或错误率过高)时,Sentinel 可以自动触发熔断机制,拒绝后续请求以保护系统。降级功能允许你在系统负载过高时,自动将某些服务的请求转向较简单的处理,保障系统的整体可用性。

其中限流策略,QPS是通过控制台设定某个资源每秒允许的最大请求数量,超出这个数量的请求会被拒绝或延迟。而并发线程数则是通过限制同一时刻可以处理的请求数量来实现流量控制。令牌桶算法则是请求的到来需要从桶中获取令牌。令牌以固定的速率生成,当请求到来时,需要消耗一个令牌才能通过。如果没有可用的令牌,请求会被拒绝或延迟。漏斗算法通过维护一个"漏斗"来控制请求的流入速率。请求以恒定的速率流入漏斗,当请求超过漏斗容量时,多余的请求会被拒绝。

熔断主要体现在,A服务调用B服务,如果B服务长时间没有返回响应,或者直接出现错误,则会直接返回失败,后续A也不会再调用B服务了。在熔断状态持续一段时间后,熔断器会进入"半开"状态。在这个状态下,系统会允许一部分请求(例如,1%或2%的请求)尝试访问该服务,以检查服务是否已恢复。如果这些请求成功,则熔断器会完全恢复,重新允许所有请求。如果请求仍然失败,熔断器将保持熔断状态,继续拒绝请求。降级主要体现在,例如双11电商系统访问量激增,而主要的业务可能体现在下单,秒杀,后端服务可能无法承受大量请求。此时可以选择对一些非核心功能进行降级,将用户的某些请求引导到默认的页面(实现服务的基本可用)。

2、项目配置

需要在项目中运用Sentinel,首先引入依赖(我是直接加入到了common模块下,注意,common模块中加入了某项依赖,除了需要刷新common模块,还需要刷新所有引用了common模块的微服务maven,否则可能不会生效):

java 复制代码
			<!--        开启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>

并且配置文件中加入:

shell 复制代码
# 控制台的端口号
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只能访问一次:
  同时可以自定义配置降级页面;

java 复制代码
@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定义受保护资源的用法:

java 复制代码
    public SecKillSkuRedisTO getCurrentSeckillSkuById(Long skuId) {
        //定义受保护的资源方式一
        try(Entry entry = SphU.entry("getCurrentSeckillSkuById")) {
 					//自己的业务逻辑
        } catch (BlockException e) {
            log.info("{}:流控规则生效","getCurrentSeckillSkuById");
        }
        return null;
    }

@SentinelResource注解定义受保护资源的用法:

java 复制代码
    /**
     * 创建流控规则方式二
     * @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:
  对于被保护的资源,手动抛出一个异常:

java 复制代码
    @GetMapping("/currentSeckillSkus")
    public R getCurrentSeckillSkus(){
        int i = 1/0;
        List<SecKillSkuRedisTO> secKillSkuRedisTOS =  secKillSkuService.getCurrentSeckillSkus();
        return R.ok().put("data",secKillSkuRedisTOS);
    }

由于出现了异常,第一次访问就出现了自定义的降级提示,也就是降级的操作生效了

3.3、黑白名单设置

sentinel也支持对于访问受保护资源的权限进行控制,例如假设我访问的路径中包含currentSeckillSkus,则不允许访问,直接返回失败,则需要进行配置:

java 复制代码
@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有:

  1. cs (Client Send):表示客户端发送请求的时间。
  2. cr (Client Receive):表示客户端接收到响应的时间。
  3. ss (Server Send):表示服务器发送响应的时间。
  4. sr (Server Receive):表示服务器接收到请求的时间。

通过sr-cs,可以计算出发送请求所消耗的时间,通过ss-cr,可以计算出服务端处理业务消耗的时间,通过cr-ss,可以计算出响应请求消耗的时间。

在Zipkin中如何自定义一个Annotations?下面是一个简单的案例:

java 复制代码
@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服务器,实现页面可视化监控

shell 复制代码
docker run -d -p 9411:9411 openzipkin/zipkin

引入依赖:

bash 复制代码
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

配置文件中添加:

shell 复制代码
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

相关推荐
ProtonBase12 分钟前
如何从 0 到 1 ,打造全新一代分布式数据架构
java·网络·数据库·数据仓库·分布式·云原生·架构
乐之者v19 分钟前
leetCode43.字符串相乘
java·数据结构·算法
suweijie7683 小时前
SpringCloudAlibaba | Sentinel从基础到进阶
java·大数据·sentinel
公贵买其鹿4 小时前
List深拷贝后,数据还是被串改
java
xlsw_7 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹8 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭9 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫9 小时前
泛型(2)
java
超爱吃士力架9 小时前
邀请逻辑
java·linux·后端
南宫生9 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论