SpringCloud面试题 - Sentinel是怎么实现集群限流的?


一、集群限流概述

Sentinel 是阿里巴巴开源的分布式系统的流量防卫组件,它不仅支持单机限流,还提供了集群限流的能力。集群限流是指在整个分布式系统中对某个资源的调用总量进行限制,而不是单机维度的限制。

为什么需要集群限流?

  1. 全局流量控制:当服务部署在多个节点上时,单机限流无法准确控制整个集群的流量
  2. 避免单机不均:防止因负载均衡不均导致的某些节点过载
  3. 精准控制:对于重要资源,需要精确控制整个集群的QPS/并发量

二、集群限流架构设计

Sentinel 的集群限流采用了 Token Server 的模式,架构如下:

请求Token
请求Token
请求Token
发放Token
发放Token
发放Token
Client 1
Token Server
Client 2
Client 3

主要组件:

  • Token Client:嵌入在应用中的 Sentinel 客户端,负责与 Token Server 通信
  • Token Server:独立的服务,负责管理全局的令牌发放

三、核心实现原理

1. 集群限流规则传播

首先需要在集群中配置限流规则,规则会从 Dashboard 推送到各个客户端和 Token Server。

// 创建集群限流规则示例
ClusterFlowConfig clusterConfig = new ClusterFlowConfig()
    .setFlowId(123)  // 全局唯一ID
    .setThresholdType(1)  // 阈值类型 (0-线程数, 1-QPS)
    .setFallbackToLocalWhenFail(true);  // 与server通信失败时是否退化到本地

FlowRule rule = new FlowRule()
    .setResource("cluster-resource")
    .setClusterMode(true)
    .setClusterConfig(clusterConfig)
    .setCount(100);  // 集群总QPS

2. 令牌请求流程

Token ClientToken Server申请令牌(数量,超时时间)返回成功(实际获取数量)返回失败或等待alt[有可用令牌][无可用令牌]Token ClientToken Server

3. 令牌服务器实现

Token Server 内部使用滑动窗口算法统计请求量:

public class ClusterTokenServer {
    // 时间窗口数组
    private volatile AtomicReferenceArray<Window> windows;
    
    public TokenResult requestTokens(int count, long timeout) {
        long currentTime = TimeUtil.currentTimeMillis();
        // 获取当前时间窗口
        Window window = currentWindow(currentTime);
        
        // 计算窗口内已使用令牌
        long used = calculateUsedTokens(currentTime);
        
        // 判断是否超过阈值
        if (used + count > threshold) {
            return new TokenResult(TokenStatus.SHOULD_WAIT);
        }
        
        // 发放令牌
        window.value.addAndGet(count);
        return new TokenResult(TokenStatus.OK, count);
    }
}

四、关键实现细节

1. 通信协议

Sentinel 使用 Netty 实现客户端与服务器之间的通信,协议格式如下:

+-----+-----+----+----+--------+------+
| 类型 | 长度 | ID | 数量 | 超时时间 | 保留位 |
+-----+-----+----+----+--------+------+

2. 失败处理策略

当客户端与服务器通信失败时,Sentinel 提供了多种降级策略:

public enum ClusterRuleManagerFallback {
    // 直接通过
    NO_FAILOVER,
    // 退化到本地限流
    LOCAL_FAILOVER,
    // 快速失败
    FAIL_FAST
}

3. 动态配置更新

Token Server 支持动态调整限流参数:

// 动态更新集群限流阈值
ClusterFlowRuleManager.loadRules(
    Collections.singletonList(
        new ClusterFlowRule("cluster-resource")
            .setThreshold(200)  // 新阈值
    )
);

五、完整使用示例

1. 启动 Token Server

public class TokenServerStartup {
    public static void main(String[] args) {
        ClusterTokenServer tokenServer = new SentinelDefaultTokenServer();
        // 配置参数
        ClusterServerConfigManager.loadGlobalTransportConfig(
            new ServerTransportConfig().setIdleSeconds(600).setPort(9999));
        // 启动服务器
        tokenServer.start();
    }
}

2. 客户端配置

public class ClientConfig {
    @PostConstruct
    public void init() {
        // 配置集群服务端信息
        ClusterClientConfig clientConfig = new ClusterClientConfig();
        clientConfig.setServerHost("127.0.0.1");
        clientConfig.setServerPort(9999);
        
        // 注册客户端配置
        ClusterClientConfigManager.applyNewConfig(clientConfig);
        
        // 初始化集群流控规则
        initFlowRules();
    }
    
    private void initFlowRules() {
        ClusterFlowConfig clusterConfig = new ClusterFlowConfig()
            .setFlowId(123)
            .setThresholdType(1)
            .setFallbackToLocalWhenFail(true);
            
        FlowRule rule = new FlowRule()
            .setResource("clusterResource")
            .setClusterMode(true)
            .setClusterConfig(clusterConfig)
            .setCount(100);
            
        FlowRuleManager.loadRules(Collections.singletonList(rule));
    }
}

3. 资源保护

@RestController
public class DemoController {
    @GetMapping("/test")
    @SentinelResource(value = "clusterResource", blockHandler = "handleBlock")
    public String test() {
        return "Hello, Sentinel Cluster Flow Control!";
    }
    
    public String handleBlock(BlockException ex) {
        return "Request blocked by cluster flow control";
    }
}

六、性能优化策略

  1. 批量令牌申请:客户端可以批量申请令牌,减少网络开销
  2. 本地缓存:客户端可以缓存少量令牌,避免每次请求都访问服务器
  3. 异步更新:后台线程定期同步全局状态,不影响主流程
  4. 分级超时:根据请求优先级设置不同的超时时间
客户端请求
本地有令牌?
使用本地令牌
批量向服务器申请
申请成功?
缓存部分令牌
触发降级策略

七、总结

Sentinel 的集群限流通过 Token Server 集中式管理全局流量,具有以下特点:

  1. 高可用:支持故障自动降级
  2. 高性能:采用 Netty 异步通信,低延迟
  3. 动态配置:支持运行时调整限流规则
  4. 扩展性强:可自定义通信协议和令牌分配策略

集群限流是分布式系统中流量控制的重要手段,Sentinel 提供了完善的实现方案,能够有效保护系统不被突发流量冲垮。

更多推荐