概念

1. 资源:Sentinel通过定义资源,定义资源之后,还需要根据资源来定义规则

2. 规则:规则就是要配置限流的规则,例如这个资源通过的QPS有多少,以及这个资源的名称等等。通过规则,Sentinel能够把资源进行保护,避免突发请求过高导致压垮服务器。

定义资源

通过Sentinel提供的API,SphU.entry,我们可以定义要被保护的资源,示例代码如下:

try(Entry entry = SphU.entry("资源名")){
   log.info("✅ 集群限流接口调用成功");
}catch (Exception e){
   log.error("阻塞");
}

定义规则

规则是为了用来定义资源的限制配置的,例如,限流的阈值,限流的类型等等

重要规则:

Field 说明 描述
resource 资源名,资源名是限流规则的作用对象 上述代码SphU.entry("资源名"),中的资源名就是这里定义的这个资源名称
grade 限流阈值类型,QPS 或线程数模式 QPS指的是所定义的资源,要根据每秒可以通过的请求进行限制
count 限流阈值 如果阈值类型配置的是QPS,那么这里就代表是每秒通过请求数量
strategy 调用关系限流策略:直接、链路、关联 默认根据资源本身(直接)
controlBehavior 流控效果(直接拒绝 / 排队等待 / 慢启动模式),不支持按调用关系限流 默认直接拒绝

示例代码:

理解上面规则的定义之后,我们可以通过调用 FlowRuleManager.loadRules() 方法加载定义的规则

private static void initFlowQpsRule() {
    List<FlowRule> rules = new ArrayList<>();
    FlowRule rule1 = new FlowRule();
    rule1.setResource(resource);
    // Set max qps to 20
    rule1.setCount(20);
    rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule1.setLimitApp("default");
    rules.add(rule1);
    FlowRuleManager.loadRules(rules);
}

Sentinel Dashboard

概念

Sentinel 提供一个控制台,通过控制台可以看到集群通过请求的情况,以及集群中的机器健康状态、集群的限流规则等等。

安装

1. 下载安装包:下载地址

2. 启动指令

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

注意:Sentinel Dashboard安装的话要求jdk1.8版本以上

使用

1. 首页登录

默认账号和密码都是sentinel

2.  查看集群服务器健康状态

3. 查看Token Server和Token Client列表

4. 查看流控规则,通过dashboard也可以手动修改流控规则

5. 在实时监控中心页面上,可以查看到资源的通过QPS数和拒绝的QPS数

集群流量控制

1. 集群限流的方式:

    1.1. 单机均摊限流,就是每台服务器都分配同样的QPS数量

    1.2. 集群总体限流:集群所有的服务器加起来的总QPS

2. 使用集群流量控制的目的:

    2.1 Sentinel可以通过单机阈值的方式,来限制QPS,例如某个接口最大QPS是100,有10台服务器,这10台服务器都会调用这个接口,那么我们可以给每台服务器都分配10个QPS,这样可以保证10台服务器加起来的总QPS不会超过100QPS。

    2.2 但是这个模式有一个缺陷,实际情况下流量到每台机器可能会不均匀,会导致总量没有到的情况下某些机器就开始限流。例如,我有五台机器,每台分配了10个QOS,其中两台都只用了5个QPS,其他服务器可能都用满了,但是两台服务器的5个QPS,也没有办法给其他的服务器使用,因此仅靠单机维度去限制的话会无法精确地限制总体流量。而集群流控可以精确地控制整个集群的调用总量,结合单机限流兜底,可以更好地发挥流量控制的效果。

3. 大致原理(不细究底层算法):

     3.1 集群流控中服务器有两种身份:

          Token Client:集群流控客户端,用于向所属 Token Server 通信请求 token。集群限流服务端会返回给客户端结果,决定是否限流。

          Token Server:即集群流控服务端,处理来自 Token Client 的请求,根据配置的集群规则判断是否应该发放 token(是否允许通过)。

4. 前置配置工作

     4.1 Sentinel从1.4.0版本开始引入集群流控模块,分为以下几个部分

  4.1.1 sentinel-cluster-common-default: 公共模块,包含公共接口和实体

  4.1.2 sentinel-cluster-client-default: 默认集群流控 client 模块,如果集群要作为Token Client的话,就需要引入这个模块

  4.1.3 sentinel-cluster-server-default: 默认集群流控 server 模块,如果集群要作为Token Server的话,就需要引入这个模块

5. 集群启动模式

  • 独立模式:即作为独立的 token server 进程启动,独立部署,隔离性好,但是需要额外的部署操作。独立模式适合作为 Global Rate Limiter 给集群提供流控服务。
  • 嵌入模式:在此模式下,集群中各个实例都是对等的,token server 和 client 可以随时进行转变,因此无需单独部署。Token Server既可以作为服务端,也可以作为客户端同时接受外部请求,以及进行发放令牌。

集群启动参数

通过以下虚拟机参数,我们可以配置服务器的信息

-Dsentinel.server.mode=false                         -- 是否主服务器
-Dproject.name=baobanserver                          -- 项目名称
-Dcsp.sentinel.cluster.client.server.host=127.0.0.1  -- Token Server地址
-Dcsp.sentinel.cluster.client.server.port=18730      -- Token Server的端口号
-Dcsp.sentinel.dashboard.server=127.0.0.1:8080       -- Sentinel Dashboard的地址
-Dcsp.sentinel.log.dir=./logs/client-2               -- 当前服务器日志记录位置

上述虚拟机参数是要在初始化集群配置的时候使用的,示例:

@Configuration
public class SimpleSentinelConfig {

    // ======== 核心配置:从启动参数/配置文件读取集群通信参数 ========
    // Token Server 通信端口(Server 用,默认18970,需与启动参数一致)
    @Value("${csp.sentinel.cluster.server.port:18970}")
    private Integer clusterServerPort;

    // Token Server 地址(Client 用,需指向 Server 实例的IP)
    @Value("${csp.sentinel.cluster.client.server.host:192.168.10.107}")
    private String clusterServerHost;

    // Token Server 通信端口(Client 用,需与 Server 的 clusterServerPort 一致)
    @Value("${csp.sentinel.cluster.client.server.port:18970}")
    private Integer clusterServerClientPort;

    /**
     * Token Server 模式初始化(仅 Server 实例执行,通过虚拟机参数sentinel.server.mode来控制服务器是Token Server还是Token Client)
     */
    @Bean
    @ConditionalOnProperty(name = "sentinel.server.mode", havingValue = "true")
    public CommandLineRunner initTokenServer() {
        return args -> {
            System.out.println("=== Token Server 模式 - 初始化集群配置 ===");

            // 1. 设置当前实例为 CLUSTER_SERVER 模式
            ClusterStateManager.applyState(CLUSTER_SERVER);

            // 2. 加载集群限流规则到集群规则管理器(关键!)
            FlowRule clusterRule = buildClusterFlowRule();

            // 2.1 加载到集群规则管理器(Token Server用)
            ClusterFlowRuleManager.loadRules("baobanserver",
                    Collections.singletonList(clusterRule));

            // 2.2 也加载到本地规则管理器(Token Server如果不加载本地规则管理器的话,会导致Token Server限流失败)
            FlowRuleManager.loadRules(Collections.singletonList(clusterRule));

            System.out.println("✅ Token Server 初始化完成:端口=" + clusterServerPort + ",规则已加载");
        };
    }

    /**
     * Token Client 模式初始化(仅 Client 实例执行)
     */
    @Bean
    @ConditionalOnProperty(name = "sentinel.server.mode", havingValue = "false", matchIfMissing = true)
    public CommandLineRunner initTokenClient() {
        return args -> {
            System.out.println("=== Token Client 模式 - 初始化集群配置 ===");

            // 1. 关键:设置当前实例为 CLUSTER_CLIENT 模式(核心!否则降级本地限流)
            ClusterStateManager.applyState(ClusterStateManager.CLUSTER_CLIENT);

            // 2. 配置 Token Server 连接信息(Client 必须指定 Server 的 IP+通信端口)
            ClusterClientAssignConfig assignConfig = new ClusterClientAssignConfig();
            assignConfig.setServerHost(clusterServerHost);
            assignConfig.setServerPort(clusterServerClientPort);
            ClusterClientConfigManager.applyNewAssignConfig(assignConfig);

            // 3. 配置 Client 通信参数(超时、重试等)
            ClusterClientConfig clientConfig = new ClusterClientConfig();
            clientConfig.setRequestTimeout(1000); // 请求超时1s
            ClusterClientConfigManager.applyNewConfig(clientConfig);

            // 4. 加载集群限流规则(Client 侧仅标记集群模式,阈值以 Server 为准)
            FlowRule clusterRule = buildClusterFlowRule();
            FlowRuleManager.loadRules(Collections.singletonList(clusterRule));

            System.out.println("✅ Token Client 初始化完成:连接 Server=" + clusterServerHost + ":" + clusterServerClientPort + ",规则已加载");
        };
    }

    /**
     * 构建集群限流规则
     */
    private FlowRule buildClusterFlowRule() {
        FlowRule clusterRule = new FlowRule();
        clusterRule.setResource("clusterApi"); // 资源名
        clusterRule.setGrade(RuleConstant.FLOW_GRADE_QPS); // QPS 限流
        clusterRule.setCount(100); // 阈值大小
        clusterRule.setClusterMode(true); // 开启集群模式(核心)

        // 集群规则配置(关键:thresholdType=1 表示集群总阈值)
        ClusterFlowConfig clusterConfig = new ClusterFlowConfig();
        clusterConfig.setFlowId(1L); // 规则ID,需全局唯一
        clusterConfig.setThresholdType(1); // 1=集群总阈值,0=单机阈值
        clusterConfig.setFallbackToLocalWhenFail(true); // 被限流的话是否降级
        clusterRule.setClusterConfig(clusterConfig);
        return clusterRule;
    }
}

常见问题排查

服务器失连

1. 检查Sentinel Dashboard连接信息配置是否有配置,或者配置是否正确

2. 检查服务器启动是否成功,可以在 sentinel-record.log 日志文件中,查看服务器在初始化限流配置的时候是否有抛出异常,或者是否正确连接到了Token Server,如果有正确连接到Token Server会打印连接成功

2026-01-13 23:04:03.875 INFO [NettyTransportClient] Successfully connect to server <127.0.0.1:18730>

3. 检查 command-center.log 日志文件中,是否有在不断的打印连接Sentinel Dashboard的信息:

2026-01-13 23:04:35.009 INFO [SimpleHttpCommandCenter] Socket income: GET /metric?startTime=1768316667000&endTime=1768316673000&refetch=false HTTP/1.1, addr: /192.168.232.121

限流不精准

1. 检查Token Server是否只有一台,如果一个集群中有多台Token Server,那么就会导致有多个Server同时在发放令牌,就会导致限流不正确

2. 检查 sentinel-block.log 日志文件中,是否有限流阻塞日志,如果有限流的话,那么限流的日志就会记录在这个文件当中

3. 可以在Sentinel Dashboard中的流控规则是否与配置的QPS阈值一致

4. 如果是集群限流的话,还要保证在初始化限流配置的时候,FlowId是否全局唯一,如果有多个资源对应同一个FlowId的话,可能会导致限流混乱。

5. 滑动窗口配置,这个比较复杂,需要根据项目调整,可以通过配置来调整

clusterConfig.setWindowIntervalMs(1000);
clusterConfig.setSampleCount(5);

windowIntervalMs指的是,一个滑动窗口的长度,默认是1s,sampleCount指的是,一个滑动窗口要分为多少个格子,官网说细粒度越细,精度越高,但是实际测试下来也不一定。

完整示例代码

1. 依赖配置(pom.xml文件)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>


    <groupId>com.maimeng.baobanq</groupId>
    <artifactId>baobanserver</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>baobanserver</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <!-- 升级Spring Boot和Spring Cloud版本 -->
        <spring-boot.version>2.3.12.RELEASE</spring-boot.version>
        <spring-cloud.version>Hoxton.SR12</spring-cloud.version>
        <sentinel.version>1.8.6</sentinel.version>
        <spring-cloud-alibaba.version>2.2.7.RELEASE</spring-cloud-alibaba.version>
    </properties>

    <!-- 替换parent的Spring Boot版本 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.12.RELEASE</version>
        <relativePath/>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!-- 保留集群依赖 -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-cluster-client-default</artifactId>
            <version>${sentinel.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-cluster-server-default</artifactId>
            <version>${sentinel.version}</version>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- 升级Spring Cloud Alibaba版本 -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2. 定义资源,下面代码通过定义一个接口,用来限制这个接口的请求QPS数量

package org.example.controller;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("/api")
public class ClusterLimitController {


    @GetMapping("/cluster/limit")
    public String clusterLimit(@RequestParam(defaultValue = "test") String param) {
        try(Entry entry = SphU.entry("clusterApi")){
            log.info("✅ 集群限流接口调用成功");
        }catch (Exception e){
            log.error("阻塞");
        }
        return String.format("成功! 序号: , 参数: %s", param);
    }

}

3. 规则定义:

package org.example.config;

import com.alibaba.csp.sentinel.cluster.ClusterStateManager;
import com.alibaba.csp.sentinel.cluster.client.config.ClusterClientAssignConfig;
import com.alibaba.csp.sentinel.cluster.client.config.ClusterClientConfig;
import com.alibaba.csp.sentinel.cluster.client.config.ClusterClientConfigManager;
import com.alibaba.csp.sentinel.cluster.flow.rule.ClusterFlowRuleManager;
import com.alibaba.csp.sentinel.cluster.server.config.ClusterServerConfigManager;
import com.alibaba.csp.sentinel.cluster.server.config.ServerTransportConfig;
import com.alibaba.csp.sentinel.datasource.AutoRefreshDataSource;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.ClusterFlowConfig;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;
import java.util.HashSet;

import static com.alibaba.csp.sentinel.cluster.ClusterStateManager.CLUSTER_SERVER;


@Configuration
public class SimpleSentinelConfig {

    // ======== 核心配置:从启动参数/配置文件读取集群通信参数 ========
    // Token Server 通信端口(Server 用,默认18970,需与启动参数一致)
    @Value("${csp.sentinel.cluster.server.port:18970}")
    private Integer clusterServerPort;

    // Token Server 地址(Client 用,需指向 Server 实例的IP)
    @Value("${csp.sentinel.cluster.client.server.host:192.168.10.107}")
    private String clusterServerHost;

    // Token Server 通信端口(Client 用,需与 Server 的 clusterServerPort 一致)
    @Value("${csp.sentinel.cluster.client.server.port:18970}")
    private Integer clusterServerClientPort;

    /**
     * Token Server 模式初始化(仅 Server 实例执行)
     */
    @Bean
    @ConditionalOnProperty(name = "sentinel.server.mode", havingValue = "true")
    public CommandLineRunner initTokenServer() {
        return args -> {
            System.out.println("=== Token Server 模式 - 初始化集群配置 ===");

            // 1. 设置当前实例为 CLUSTER_SERVER 模式
            ClusterStateManager.applyState(CLUSTER_SERVER);

            // 2. 加载集群限流规则到集群规则管理器(关键!)
            FlowRule clusterRule = buildClusterFlowRule();

            // 2.1 加载到集群规则管理器(Token Server用)
            ClusterFlowRuleManager.loadRules("baobanserver",
                    Collections.singletonList(clusterRule));

            // 2.2 也加载到本地规则管理器(Token Server如果不加载本地规则管理器的话,会导致Token Server限流失败)
            FlowRuleManager.loadRules(Collections.singletonList(clusterRule));

            System.out.println("✅ Token Server 初始化完成:端口=" + clusterServerPort + ",规则已加载");
        };
    }

    /**
     * Token Client 模式初始化(仅 Client 实例执行)
     */
    @Bean
    @ConditionalOnProperty(name = "sentinel.server.mode", havingValue = "false", matchIfMissing = true)
    public CommandLineRunner initTokenClient() {
        return args -> {
            System.out.println("=== Token Client 模式 - 初始化集群配置 ===");

            // 1. 关键:设置当前实例为 CLUSTER_CLIENT 模式(核心!否则降级本地限流)
            ClusterStateManager.applyState(ClusterStateManager.CLUSTER_CLIENT);

            // 2. 配置 Token Server 连接信息(Client 必须指定 Server 的 IP+通信端口)
            ClusterClientAssignConfig assignConfig = new ClusterClientAssignConfig();
            assignConfig.setServerHost(clusterServerHost);
            assignConfig.setServerPort(clusterServerClientPort);
            ClusterClientConfigManager.applyNewAssignConfig(assignConfig);

            // 3. 配置 Client 通信参数(超时、重试等)
            ClusterClientConfig clientConfig = new ClusterClientConfig();
            clientConfig.setRequestTimeout(1000); // 请求超时1s
            ClusterClientConfigManager.applyNewConfig(clientConfig);

            // 4. 加载集群限流规则(Client 侧仅标记集群模式,阈值以 Server 为准)
            FlowRule clusterRule = buildClusterFlowRule();
            FlowRuleManager.loadRules(Collections.singletonList(clusterRule));

            System.out.println("✅ Token Client 初始化完成:连接 Server=" + clusterServerHost + ":" + clusterServerClientPort + ",规则已加载");
        };
    }

    /**
     * 构建集群限流规则
     */
    private FlowRule buildClusterFlowRule() {
        FlowRule clusterRule = new FlowRule();
        clusterRule.setResource("clusterApi"); // 资源名
        clusterRule.setGrade(RuleConstant.FLOW_GRADE_QPS); // QPS 限流
        clusterRule.setCount(100); // 阈值到校
        clusterRule.setClusterMode(true); // 开启集群模式(核心)

        // 集群规则配置(关键:thresholdType=1 表示集群总阈值)
        ClusterFlowConfig clusterConfig = new ClusterFlowConfig();
        clusterConfig.setFlowId(1L); // 规则ID,需全局唯一
        clusterConfig.setThresholdType(1); // 1=集群总阈值,0=单机阈值
        clusterConfig.setFallbackToLocalWhenFail(true); // 被的话限流是否降级
        clusterRule.setClusterConfig(clusterConfig);
        return clusterRule;
    }
}

4. 配置文件

spring:
  application:
    name: baobanserver
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080 # dashboard面板地址
Logo

更多推荐