10000字,图解分布式系统限流平台Sentinel

时间:2023-04-07 12:20:07

大家好,我是哪吒。

Sentinel是阿里巴巴开源的一款轻量级流量控制、熔断降级工具,它提供了实时的流量控制,熔断降级等功能,能够帮助我们实现服务的高可用性和稳定性。

本文将会介绍Sentinel的作用和优势、快速开始、进阶使用、Spring Cloud Alibaba Sentinel整合以及实践案例,并对Sentinel的局限和不足进行分析

一、前言

1、关于 Sentinel

Sentinel 是阿里巴巴开源的一款针对分布式系统的流量控制、熔断降级的框架。在微服务架构的系统中,请求流量复杂多样,可能会因为某一个服务异常而导致整体服务不可用,这时候需要熔断降级,而 Sentinel 就提供了这样的解决方案。

10000字,图解分布式系统限流平台Sentinel

2、Sentinel 的作用和优势

Sentinel 可以针对服务方法调用、HTTP 请求、Dubbo 服务等,进行实时的流量控制、熔断降级,确保服务高可用,同时还可以提供实时的监控和报警功能

Sentinel 有以下一些优势:

  1. 丰富的应用场景和细粒度的控制: Sentinel 支持多种应用场景,包括熔断降级、流量控制、系统保护、热点参数限流等,而且可以实现细粒度的控制;
  2. 强大的实时监测机制: Sentinel 提供了实时的监测、报警机制,能够对系统运行情况进行实时检测和通知,发现问题更加及时;
  3. 易于扩展: Sentinel 为开发者提供了简单易用的扩展接口,开发者可以方便的实现自定义的控制和监测逻辑;
  4. 易于集成: Sentinel 支持多种开发框架,包括 Spring Cloud、Dubbo、Feign 等,开发者可以很方便的将 Sentinel 集成到自己的应用中;

3、本文目的和内容概述

本文将为读者介绍 Sentinel 的基础和进阶使用方法,包括

  1. 如何配置 Sentinel 控制台;
  2. 如何编写并测试 Sentinel 规则、如何使用自定义 Sentinel 规则扩展开发;
  3. 介绍 Sentinel 和 Spring Cloud Alibaba 的整合方法,并且给出了一些 Sentinel 实践案例供读者参考。

本文的目的是帮助读者快速上手使用 Sentinel,并且深入理解其基本原理和使用方法。同时,也希望能够对读者们的日常工作有所帮助。

二、快速开始

1、环境准备

在开始使用 Sentinel 之前,我们需要准备好以下环境:

  1. JDK 1.8 或更高版本
  2. Maven 3.0 或更高版本
  3. Sentinel-dashboard

2、引入 Sentinel 依赖

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

3、配置 Sentinel 控制台

在Sentinel的官网下载最新的控制台jar包,然后在控制台目录下执行以下命令启动控制台:

java -jar sentinel-dashboard-1.8.2.jar

启动成功后,可以通过浏览器访问查看控制台页面。

4、注册应用到 Sentinel 控制台

在应用启动类上添加注解@EnableSentinel注解,然后在配置文件中配置应用名称和Sentinel控制台的地址:

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: sentinel
            groupId: DEFAULT_GROUP
            data-type: json

5、编写并测试 Sentinel 规则

Sentinel提供了多种限流降级策略,本文以流控规则为例进行演示。

在需要限流的方法上添加@SentinelResource注解,然后配置流控规则:

@GetMapping("/hello")
@SentinelResource(value = "hello", blockHandler = "blockHandler")
public String hello() {
    return "Hello, World!";
}

public String blockHandler(BlockException e) {
    return "请求过于频繁,请稍后重试!";
}

在控制台的流控规则页面添加对应的规则,设置好阈值和统计窗口等参数,然后测试该接口。

三、进阶使用

1、Sentinel Dashboard 使用详解

Sentinel Dashboard是Sentinel的可视化监控平台,可以用于实时监控应用的流量、延迟、异常等指标,并对应用进行限流降级等操作

10000字,图解分布式系统限流平台Sentinel

Sentinel客户端首先向Sentinel Dashboard注册。Sentinel Dashboard返回一个token给客户端,客户端将使用该token连接Sentinel。

应用程序将使用token连接Sentinel,Sentinel客户端将返回连接成功信息。Sentinel客户端将实时推送metrics数据到Sentinel Dashboard,Sentinel Dashboard将监控和管理应用程序。

2、入门级规则配置详解(流控规则、降级规则、热点参数限流)

Sentinel是一款开源的流量控制和降级框架,提供多种限流降级策略,包括流控规则、降级规则、热点参数限流等。

下面将逐一介绍这些规则。

(1)流控规则

流控规则用于限制系统的流量,可以通过设置QPS流量控制和线程数流量控制等方式来控制系统的访问速度。

在Sentinel Dashboard中,可以通过以下步骤来配置和管理流控规则:

  • 设置流控模式:可以选择直接拒绝、Warm Up、匀速排队等模式。
  • 设置阈值:可以设置QPS、线程数等阈值来限制流量。
  • 设置流控策略:可以选择按照调用关系、链路入口等策略来限制流量。
  • 查看已有规则:可以查看已经存在的流控规则,并进行管理和修改。
(2)降级规则

降级规则用于应对系统的异常情况,可以通过设置异常比例降级、异常数降级和慢调用降级等方式来降低系统的负载。

在Sentinel Dashboard中,可以通过以下步骤来配置和管理降级规则:

  • 设置降级模式:可以选择异常比例、异常数和慢调用三种模式。
  • 设置阈值:可以设置异常比例、异常数和慢调用时间等阈值来触发降级。
  • 设置降级策略:可以选择返回特定的错误信息、调用备用服务等策略来处理降级情况。
  • 查看已有规则:可以查看已经存在的降级规则,并进行管理和修改。
(3)热点参数限流

热点参数限流用于对热点参数进行限流,可以有效避免某些参数被过多地请求。在Sentinel Dashboard中,可以通过以下步骤来配置和管理热点参数限流规则:

  • 设置参数:可以选择需要进行限流的参数。
  • 设置阈值:可以设置QPS、线程数等阈值来限制热点参数的访问速度。
  • 设置限流策略:可以选择直接拒绝、匀速排队等策略来处理热点参数限流。
  • 查看已有规则:可以查看已经存在的热点参数限流规则,并进行管理和修改。

在使用这些规则时,需要注意参数设置和阈值设置等细节,以避免规则的误判或限流不准确等问题。

通过Sentinel Dashboard的可视化界面,可以方便地进行规则的配置和管理,提高系统的稳定性和可靠性

3、资源名与 URL 匹配规则

Sentinel的资源名和URL匹配规则是限流降级策略的重要组成部分,可以根据业务需求定义合适的匹配规则。

  • 资源名:可以是一个具体的业务方法、一个接口URL或者一个Dubbo服务等。
  • URL 匹配规则:支持Ant匹配和正则匹配两种方式,可以根据具体需求进行选择。
  • Dubbo服务:Sentinel支持对Dubbo服务进行限流降级操作,需要在Dubbo配置文件中添加Sentinel的拦截器配置。
  • 在定义资源名和URL匹配规则时,需要注意合理性和精确性,以避免出现误判或限流不准确等问题。
10000字,图解分布式系统限流平台Sentinel

上图展示了应用程序代码中定义资源名和 URL 匹配规则时的交互过程。

应用程序通过 Sentinel 客户端向 Sentinel 发送配置请求,Sentinel 返回配置结果。应用程序根据配置结果使用 Sentinel 进行限流降级。

在这个过程中,应用程序需要注意合理性和精确性,以避免出现误判或限流不准确等问题。

4、自定义 Sentinel 规则扩展开发

10000字,图解分布式系统限流平台Sentinel

上图是自定义规则扩展的关系图示。

自定义规则扩展包括数据源扩展、限流降级规则扩展、规则统计扩展等,可以使用多种语言进行开发。

在进行规则扩展时,需要注意代码质量和性能,以保证扩展的准确性和有效性。

以下是一个自定义规则类型的示例:

public class CustomFlowRule implements FlowRule {
    
    private String resourceName;
    private int count;
    private int interval;
    
    public CustomFlowRule(String resourceName, int count, int interval) {
        this.resourceName = resourceName;
        this.count = count;
        this.interval = interval;
    }

    @Override
    public String getResource() {
        return resourceName;
    }

    @Override
    public int getCount() {
        return count;
    }

    @Override
    public void setCount(int count) {
        this.count = count;
    }

    @Override
    public int getInterval() {
        return interval;
    }

    @Override
    public void setInterval(int interval) {
        this.interval = interval;
    }
}

在这个示例中,我们自定义了一个 CustomFlowRule 类型,它包含了 resourceName、count 和 interval 三个属性。同时,我们实现了 FlowRule 接口,并实现了其中的各个方法,以满足 Sentinel 对规则类型的要求。

使用这个自定义规则类型时,我们需要在代码中添加相关的配置,例如:

List<CustomFlowRule> rules = new ArrayList<>();
CustomFlowRule rule = new CustomFlowRule("custom_resource"101);
rules.add(rule);
FlowRuleManager.loadRules(rules);

在这个示例中,我们通过 CustomFlowRule 类型创建了一个规则,它的资源名称为 custom_resource,限流阈值为 10,时间间隔为 1 秒。然后我们将这个规则添加到 Sentinel 的规则管理器中,从而让 Sentinel 能够自动识别和使用这个规则。

四、Spring Cloud Alibaba Sentinel 整合

1、Sentinel Starter 简介

Sentinel Starter是Spring Cloud Alibaba Sentinel的快速入门依赖,提供了自动化配置和默认规则等能力,可以简化Sentinel在Spring Cloud中的使用。

在使用Sentinel Starter时,只需要添加依赖并在配置文件中配置相应的参数,即可快速实现Sentinel的限流降级功能。

2、使用 Sentinel Starter 整合 Spring Cloud 微服务

(1)在Spring Boot项目中添加以下依赖:
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
(2)在application.yml配置文件中添加以下配置:
spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080 # Sentinel控制台地址
        port: 8719
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848 # Nacos配置中心地址
            dataId: ${spring.application.name}-sentinel # Sentinel配置数据ID
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow,degrade # Sentinel规则类型
(3)在代码中添加注解 @EnableSentinel ,开启 Sentinel 功能。
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableCircuitBreaker
@EnableSentinel // 开启 Sentinel 功能
public class ProductServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductServiceApplication.classargs);
    }
}
(4)使用注解 @SentinelResource 对需要进行限流和降级的接口进行配置。
@RestController
public class ProductController {

    @Autowired
    private ProductService productService;

    @GetMapping("/products/{id}")
    @SentinelResource(value = "products/{id}", blockHandlerClass = ProductControllerBlockHandler.classblockHandler "handleBlock")
    public Product getProduct(@PathVariable Long id) {
        return productService.getProduct(id);
    }
}

其中,@SentinelResource 注解中的 value 参数为资源名称,blockHandlerClass 和 blockHandler 分别指定了限流或降级时的处理类和方法。

3、限流和降级策略在微服务中的应用场景

10000字,图解分布式系统限流平台Sentinel

在上图中,我们可以看到当服务请求量过大时,API Gateway 可以对服务进行限流,避免服务过载。同时,当某个服务出现故障或负载过高时,可以对该服务进行降级,避免影响其他服务的正常运行。

4、示例代码

(1)添加 @SentinelResource 注解
@RestController
public class OrderController {

    @PostMapping("/createOrder")
    @SentinelResource(value = "createOrder", blockHandlerClass = OrderBlockHandler.classblockHandler "handleBlock")
    public Result createOrder(@RequestBody OrderRequest orderRequest) {
        // ...
    }
}
(2)添加 @Idempotent 注解
@RestController
public class OrderController {

    @PostMapping("/createOrder")
    @SentinelResource(value = "createOrder", blockHandlerClass = OrderBlockHandler.classblockHandler "handleBlock")
    @Idempotent(key = "#orderRequest.userId + ':' + #orderRequest.productId")
    public Result createOrder(@RequestBody OrderRequest orderRequest) {
        // ...
    }
}
(3)实现幂等性校验逻辑
@Component
public class OrderService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public boolean checkIdempotency(String key) {
        Boolean result = redisTemplate.opsForValue().setIfAbsent(key, "1");
        if (result != null && result) {
            redisTemplate.expire(key, 60, TimeUnit.SECONDS);
            return true;
        }
        return false;
    }
}

五、基于 Sentinel 的分布式锁实现

1、场景描述

假设我们有一个高并发的秒杀系统,我们需要实现分布式锁来控制同一时间只能有一个用户参与秒杀活动。为了防止死锁和死节点,我们使用 Sentinel 的分布式锁实现来保证系统的可用性和稳定性。

10000字,图解分布式系统限流平台Sentinel

2、实现步骤

(1)添加 Sentinel 的依赖到项目中:
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
(2)在配置文件中添加 Sentinel 的配置:
spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719
(3)在代码中使用 Sentinel 的分布式锁实现:
@RestController
public class SeckillController {

    @Autowired
    private DistributedLock distributedLock;

    @GetMapping("/seckill")
    public String seckill(@RequestParam("userId") Long userId,
                          @RequestParam("itemId") Long itemId) 
{
        // 获取锁
        String lockKey = "seckill:" + itemId;
        boolean locked = distributedLock.tryLock(lockKey);
        if (!locked) {
            return "Failed to get lock";
        }
        try {
            // 执行秒杀逻辑
            return "Success";
        } finally {
            // 释放锁
            distributedLock.unlock(lockKey);
        }
    }
}

在 Sentinel 控制台中创建流控规则,限制流量:

  • 在 Dashboard 中创建应用
  • 在 Flow 中创建规则,设置限制流量的策略,例如:QPS 为 1000。

示例代码:

@Component
public class DistributedLock {

    private static final String LOCK_PREFIX = "distributed-lock:";

    @Autowired
    private CuratorFramework curatorFramework;

    public boolean tryLock(String key) {
        String lockPath = LOCK_PREFIX + key;
        InterProcessMutex lock = new InterProcessMutex(curatorFramework, lockPath);
        try {
            return lock.acquire(1, TimeUnit.SECONDS);
        } catch (Exception ex) {
            throw new RuntimeException("Failed to acquire lock", ex);
        }
    }

    public void unlock(String key) {
        String lockPath = LOCK_PREFIX + key;
        InterProcessMutex lock = new InterProcessMutex(curatorFramework, lockPath);
        try {
            lock.release();
        } catch (Exception ex) {
            throw new RuntimeException("Failed to release lock", ex);
        }
    }
}

六、基于 Sentinel 的 A/B 测试实现

1、场景描述

假设我们有一个电商网站,想要测试一个新的促销活动页面对用户购买行为的影响。我们希望将用户随机分为两个组,其中一个组将看到新的促销页面,另一个组将看到旧的促销页面。我们希望通过分析两组用户的购买转化率来确定新页面是否对提高购买转化率有帮助。

2、实现步骤

  1. 根据用户的请求特征将请求分组,例如使用 @SentinelResource 的 blockHandlerClass 和 blockHandler 指定请求被限流或降级时的处理类和方法,处理类中可以根据请求的特征将请求分组。
  2. 在新的促销页面和旧的促销页面中分别添加上报代码,将用户的购买行为和分组信息上报到 Sentinel。
  3. 在 Sentinel 控制台中创建一个流控规则,将两个组的流量分别限制在一定的范围内,确保两组之间的请求量基本相等。
  4. 分析两组用户的购买转化率,确定新页面是否对提高购买转化率有帮助。
10000字,图解分布式系统限流平台Sentinel

3、示例代码

(1)根据请求特征将请求分组
@RestController
public class PromotionController {
    
    @GetMapping("/promotion")
    @SentinelResource(value = "promotion", blockHandlerClass = PromotionBlockHandler.classblockHandler "handle")
    public String promotion(@RequestParam("userId") Long userId) {
        // 根据用户 id 判断用户应该分到哪个组
        int groupId = userId % 2;
        return "Group " + groupId;
    }
}

@Component
public class PromotionBlockHandler {
    
    public String handle(Long userId, BlockException ex) {
        // 处理限流或降级情况下的逻辑
        int groupId = userId % 2;
        return "Blocked Group " + groupId;
    }
}
(2)将用户的购买行为和分组信息上报到 Sentinel
@RestController
public class PromotionController {
    
    @GetMapping("/promotion")
    @SentinelResource(value = "promotion", blockHandlerClass = PromotionBlockHandler.classblockHandler "handle")
    public String promotion(@RequestParam("userId") Long userId, @RequestParam("itemId") Long itemId) {
        // 根据用户 id 判断用户应该分到哪个组
        int groupId = userId % 2;
        
        // 上报用户购买行为和分组信息
        String resourceName = "promotion_" + itemId;
        Entry entry = null;
        try {
            entry = SphU.entry(resourceName);
            Tracer.traceEntry("group_id=" + groupId);
            // 执行业务逻辑
            return "Success";
        } catch (BlockException ex) {
            // 处理限流或降级情况下的逻辑
            return "Blocked Group " + groupId;
        } finally {
            if (entry != null) {
                entry.exit();
            }
        }
    }
}
(3)在 Sentinel 控制台中创建流控规则

在 Sentinel 控制台中创建两个流控规则,将两个组的流量分别限制在一定的范围内,可以通过配置在限流规则中添加特定的参数,如 group_id=0 和 group_id=1,来将不同组的请求进行区分。

示例代码:

  1. 在 Sentinel 控制台中创建流控规则
  2. 打开 Sentinel 控制台,进入流控规则页面;
  3. 点击 “新建” 按钮,填写如下信息:
规则名称:promotion_flow_control;

资源名:promotion_*;

限流阈值:100

流控模式:QPS;

应用名称:default

参数:group_id=0

点击 "提交" 按钮,创建一个限制组 0 的流控规则;

点击 "新建" 按钮,填写如下信息:

规则名称:promotion_flow_control;

资源名:promotion_*;

限流阈值:100

流控模式:QPS;

应用名称:default

参数:group_id=1

点击 “提交” 按钮,创建一个限制组 1 的流控规则;

注意事项:

在使用 Sentinel 进行 A/B 测试时,需要注意以下几个方面:

  1. 将请求进行随机分组,确保两个组之间的请求量基本相等;
  2. 在 Sentinel 控制台中创建流控规则,限制每个组的流量,确保流量控制的精度和正确性;
  3. 在上报数据时,需要将用户的分组信息和购买行为一并上报,以便后续的数据分析;
  4. 在分析数据时,需要根据不同组的数据进行对比,确保分析结果的准确性。

七、总结

1、Sentinel 的局限和不足

Sentinel虽然具有很多优点和优势,但也存在一些局限和不足。

例如,Sentinel对业务代码的侵入性较大,需要在代码中添加相关的注解或者拦截器等;同时,Sentinel的配置较为复杂,需要进行多种规则的配置和参数的调整等。

此外,Sentinel还存在一些性能问题和安全问题,需要注意规避和解决。

2、Sentinel 的发展前景

尽管Sentinel存在一些不足和局限,但随着微服务和云原生技术的普及和发展,Sentinel在限流降级等方面的需求和重要性将会越来越大

同时,Sentinel也在不断地进行优化和改进,例如在性能和安全方面进行了多项优化和加强,同时还提供了更加方便和高效的规则扩展开发能力,可以满足不同业务场景的需求。

因此,Sentinel在未来的发展中将会发挥越来越重要的作用,成为云原生技术生态圈中的一颗明珠。