编程语言
首页 > 编程语言> > SpringCloudAlibaba分布式流量控制组件Sentinel实战与源码分析(上)

SpringCloudAlibaba分布式流量控制组件Sentinel实战与源码分析(上)

作者:互联网

概述

定义

Sentinel官网地址 https://sentinelguard.io/zh-cn/index.html 最新版本v1.8.4

Sentinel官网文档地址 https://sentinelguard.io/zh-cn/docs/introduction.html

Sentinel GitHub源码地址 https://www.github.com/alibaba/Sentinel

Sentinel是面向分布式服务架构的高可用防护组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助用户保障微服务的稳定性。

背景

分布式系统遇到常见棘手问题就是如何保障系统高可用性的场景,严重则会导致整个系统服务雪崩。

image-20220605121156566

在微服务架构中,出现服务交叉调用是很常见的情况,如电商秒杀商品、商品详情、购物车等都会访问库存服务。如果其中下单服务不可用,就会出现线程池里的所有线程都因等待而被阻塞,进而导致整个系统的服务雪崩。服务雪崩效应是因服务提供者的不可用导致服务调用者的不可用,并将不可用逐步放大的过程。特别如果被一些非核心业务如积分服务而导致整个服务不可用那就非常不值得,假如积分服务有一些容错处理机制,到时在事后加一些补偿的机制加回来也是可以接收的。

image-20220605121619870

常见容错机制

特性

image-20220605124452211

基本概念

功能和设计理念

同类组件功能对比Sentinel VS Hystrix VS resilience4j

image-20220605231820322

主要工作机制

工作主流程

在 Sentinel 里面,所有的资源都对应一个资源名称以及一个 Entry。Entry 可以通过对主流框架的适配自动创建,也可以通过注解的方式或调用 API 显式创建;每一个 Entry 创建的时候,同时也会创建一系列功能插槽(slot chain)。这些插槽有不同的职责,例如:

总体框架如下:

image-20220605194255184

Sentinel 将 ProcessorSlot 作为 SPI 接口进行扩展(1.7.2 版本以前 SlotChainBuilder 作为 SPI),使得 Slot Chain 具备了扩展的能力。您可以自行加入自定义的 slot 并编排 slot 间的顺序,从而可以给 Sentinel 添加自定义的功能。

开源框架适配和多语言支持

为了减少开发的复杂程度,对大部分的主流框架例如 Web Servlet、Dubbo、Spring Cloud、gRPC、Spring WebFlux、Reactor 等都做了适配。只需要引入对应的依赖即可方便地整合 Sentinel。

image-20220605195114815

Sentinel 目前提供 Java、Go、C++ 、RUST等语言的原生支持。

实战

组成部分

Sentinel 可以简单的分为 Sentinel 核心库和 Dashboard,核心库不依赖 Dashboard,但是结合 Dashboard 可以取得最好的效果。

三步构建

我们说的资源,可以是任何东西,服务,服务里的方法,甚至是一段代码。使用 Sentinel 来进行资源保护,主要分为几个步骤:

使用之前得先引入依赖

    <dependency>
      <groupId>com.alibaba.csp</groupId>
      <artifactId>sentinel-core</artifactId>
      <version>1.8.4</version>
    </dependency>

入门初体验

package cn.itxs.ecom.storage.controller;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/sentinel")
public class SentinelHelloControoler {

    private static final String RESOURCE_NAME = "hello";

    @RequestMapping("/hello")
    public String hello(){
        // 1.5.0 版本开始可以利用 try-with-resources 特性(使用有限制)
        // 资源名可使用任意有业务语义的字符串,比如方法名、接口名或其它可唯一标识的字符串。
        try (Entry entry = SphU.entry(RESOURCE_NAME)) {
            // 被保护的业务逻辑
            return "hello itxs";
        } catch (BlockException ex) {
            // 资源访问阻止,被限流或被降级
            // 在此处进行相应的处理操作
            return "hello itxs block!";
        }
    }

    @PostConstruct
    private void initFlowRules(){
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource(RESOURCE_NAME);
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // Set limit QPS to 2.
        rule.setCount(2);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }
}

连续访问访问测试http://localhost:4081/sentinel/hello,可以看到被流控了。

image-20220607234322885

@SentinelResource使用

使用提供的@SentinelResource注解,getAccount() 方法就成了一个资源。注意注解支持模块需要配合 Spring AOP 或者 AspectJ 一起使用。

    @RequestMapping("/account")
    @SentinelResource(value = ACCOUNT_RESOURCE_NAME,blockHandler = "blockHandlerForGetAccount")
    public Account getAccount(Integer id){
        return new Account(1,"1001",100);
    }

    public Account blockHandlerForGetAccount(Integer id,BlockException ex){
        ex.printStackTrace();
        return new Account(1,"被流控了",100);
    }

image-20220608000156131

连续访问测试http://localhost:4081/sentinel/account,可以看到也被流控了。

image-20220608000113564

异常处理fallback机制

    @RequestMapping("/account_exception")
    @SentinelResource(value = ACCOUNT_RESOURCE_NAME,fallback = "fallbackHandlerForGetAccount")
    public Account getAccountException(Integer id){
        int i = 1/0;
        return new Account(1,"1001",100);
    }

    public Account fallbackHandlerForGetAccount(Integer id,Throwable ex){
        ex.printStackTrace();
        return new Account(1,"异常处理",100);
    }

image-20220608001640055

访问测试http://localhost:4081/sentinel/account_exception,可以看到走fallback方法处理了。

image-20220608001526306

熔断降级

    @PostConstruct
    private void initDegradeRules(){
        List<DegradeRule> rules = new ArrayList<>();
        DegradeRule rule = new DegradeRule();
        rule.setResource(DEGRADE_RESOURCE_NAME);
        rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
        rule.setCount(2);
        rule.setMinRequestAmount(2);
        rule.setStatIntervalMs(60*1000);
        rule.setTimeWindow(10);
        rules.add(rule);
        DegradeRuleManager.loadRules(rules);
    }

    @RequestMapping("/degrade")
    @SentinelResource(value = DEGRADE_RESOURCE_NAME,entryType = EntryType.IN,blockHandler = "blockHandlerForDegrade")
    public Account degrade(Integer id){
        throw new RuntimeException("异常");
    }

    public Account blockHandlerForDegrade(Integer id,BlockException ex){
        ex.printStackTrace();
        return new Account(1,"熔断降级",100);
    }

连续访问两次访问异常http://localhost:4081/sentinel/account_exception,之后十秒内访问都直接熔断降级,10秒后再访问两次显示异常

image-20220608235225659

Sentinel 控制台

功能

Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。通过整合 Sentinel 核心库和 Dashboard。Sentinel 控制台包含如下功能:

注意:Sentinel 控制台目前仅支持单机部署。Sentinel 控制台项目提供 Sentinel 功能全集示例,不作为开箱即用的生产环境控制台,若希望在生产环境使用请根据文档自行进行定制和改造。

docker部署

# 下载 docker pull bladex/sentinel-dashboard:tagname,没有tag默认下载最新版本latest,本次使用1.8.4版本bladex/sentinel-dashboard:1.8.4
docker pull bladex/sentinel-dashboard
# 运行,访问http 8858端口进入dashboard,用户名和密码sentinel/sentinel
docker run --name sentinel  -d -p 8858:8858 -d  bladex/sentinel-dashboard

二进制包部署

可以从其GitHub项目的 release 页面 下载最新版本的控制台 jar 包。目前最新版本为v1.8.4,也可以从最新版本的源码自行构建 Sentinel 控制台的jar包。由于下载源码1.8.4版本,那这里我们执行编译控制台源码得到二进制包。

image-20220610000842516

# 启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本。其中 -Dserver.port=8858 用于指定 Sentinel 控制台端口为 8858,没有指定为8080。从 Sentinel 1.6.0 起,Sentinel 控制台引入基本的登录功能,默认用户名和密码都是 sentinel
java -Dserver.port=8858 -Dsentinel.dashboard.auth.username=itxs -Dsentinel.dashboard.auth.password=123456 -jar sentinel-dashboard.jar

如果程序是Spring Boot 或 Spring Cloud 应用,则可以通过 Spring 配置文件来指定配置。

image-20220610001144479

访问http://localhost:8858/

image-20220610001237572

输入上面启动命令中的用户密码,进入控制台主页面

image-20220610001331388

客户端接入控制台

控制台启动后,客户端需要按照以下步骤接入到控制台。

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-transport-simple-http</artifactId>
    <version>1.8.4</version>
</dependency>

如果是整合SpringCloud Alibaba加入

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>2021.0.1.0</version>
        </dependency>

**本人博客网站 **IT小神 www.itxiaoshen.com

标签:rule,sentinel,源码,线程,Sentinel,控制台,SpringCloudAlibaba,资源
来源: https://www.cnblogs.com/itxiaoshen/p/16361720.html