跳到主要内容

集群限流

在分布式系统中,单机限流往往无法精确控制整个集群的流量。Sentinel 提供了集群限流功能,可以在集群维度对流量进行统一管控,解决流量不均匀导致总体限流效果不佳的问题。

为什么需要集群限流

假设我们希望给某个用户限制调用某个 API 的总 QPS 为 50,但机器数可能很多(比如有 100 台)。如果采用单机限流,每台机器的阈值设置为 0.5 QPS 显然不现实,设置更大的阈值又会导致总量超标。这时候就需要一个中心化的服务来统计总的调用量,其他实例都与这个服务通信来判断是否可以调用。

另外,集群限流还可以解决流量不均匀导致总体限流效果不佳的问题。假设集群中有 10 台机器,我们给每台机器设置单机限流阈值为 10 QPS,理想情况下整个集群的限流阈值就为 100 QPS。不过实际情况下流量到每台机器可能会不均匀,会导致总量没有到的情况下某些机器就开始限流。因此仅靠单机维度去限制的话会无法精确地限制总体流量。

集群限流可以精确地控制整个集群的调用总量,结合单机限流兜底,可以更好地发挥流量控制的效果。

架构设计

Sentinel 集群限流采用 Client-Server 架构,共涉及两种角色:

Token Client(客户端)

嵌入到应用中,负责向 Token Server 请求 token。每次流量经过时,客户端会向服务端发起请求,询问是否允许通过。

Token Server(服务端)

独立部署或嵌入到某个应用中,负责统计整个集群的流量并进行限流判断。Token Server 维护全局的统计数据,根据配置的规则决定是否发放 token。

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│ Client │ │ Client │ │ Client │
│ (App 1) │ │ (App 2) │ │ (App 3) │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└───────────────────┼───────────────────┘

┌──────▼──────┐
│ Token Server│
│ (限流) │
└─────────────┘

模块结构

Sentinel 集群限流模块主要包含以下几部分:

模块说明
sentinel-cluster-common-default公共模块,包含公共接口和实体
sentinel-cluster-client-default默认集群流控 client 模块,使用 Netty 进行通信
sentinel-cluster-server-default默认集群流控 server 模块,使用 Netty 进行通信

注意:集群流控模块要求 JDK 版本最低为 1.7。

集群限流规则

规则配置

FlowRule 添加了两个字段用于集群限流相关配置:

private boolean clusterMode;           // 标识是否为集群限流配置
private ClusterFlowConfig clusterConfig; // 集群限流相关配置项

ClusterFlowConfig 包含以下配置项:

// 全局唯一的规则 ID,由集群限流管控端分配
private Long flowId;

// 阈值模式,默认(0)为单机均摊,1 为全局阈值
private int thresholdType = ClusterRuleConstant.FLOW_THRESHOLD_AVG_LOCAL;

// 在 client 连接失败或通信失败时,是否退化到本地的限流模式
private boolean fallbackToLocalWhenFail = true;

阈值模式

单机均摊模式(thresholdType = 0)

集群总阈值 = 配置的单机阈值 × 当前连接的 client 数量。

例如:配置阈值为 10,当前有 3 个 client 连接,则集群总阈值为 30 QPS。

这种方式适合希望根据机器数量动态调整总阈值的场景。

全局阈值模式(thresholdType = 1)

配置的阈值即为整个集群的总阈值,与连接的 client 数量无关。

例如:配置阈值为 100,无论有多少个 client 连接,集群总阈值都是 100 QPS。

这种方式适合需要固定总阈值的场景。

配置示例

FlowRule rule = new FlowRule();
rule.setResource("getUser");
rule.setCount(10);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setClusterMode(true); // 开启集群限流模式

// 集群限流配置
ClusterFlowConfig clusterConfig = new ClusterFlowConfig();
clusterConfig.setFlowId(1001L); // 规则 ID
clusterConfig.setThresholdType(ClusterRuleConstant.FLOW_THRESHOLD_AVG_LOCAL); // 单机均摊模式
clusterConfig.setFallbackToLocalWhenFail(true); // 失败时退化到本地限流

rule.setClusterConfig(clusterConfig);

FlowRuleManager.loadRules(Collections.singletonList(rule));

集群限流客户端

引入依赖

<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-cluster-client-default</artifactId>
<version>1.8.8</version>
</dependency>

配置 Token Server 地址

可以通过 API 或动态配置源配置 Token Server 地址。

API 方式

http://<ip>:<port>/cluster/client/modifyConfig?data=<config>

其中 data 是 JSON 格式的 ClusterClientConfig:

{
"serverHost": "192.168.1.100",
"serverPort": 18730,
"requestTimeout": 20
}

动态配置源方式

// 注册动态配置源
ClusterClientConfigManager.registerServerAssignProperty(
new NacosDataSource<>(remoteAddress, groupId, dataId, parser)
);

客户端配置项

配置项说明默认值
serverHostToken Server 主机地址-
serverPortToken Server 端口-
requestTimeout请求超时时间(ms)20

失败降级

当 Token Client 与 Server 之间的连接断开时,Client 会不断进行重试,每次重试的间隔时间以 n * 2000 ms 的形式递增。

如果配置了 fallbackToLocalWhenFail = true,在连接失败或通信失败时,会自动退化到本地限流模式,确保服务可用性。

集群限流服务端

Token Server 有两种部署模式:

独立模式(独立进程)

独立部署 Token Server,专门负责集群限流。适合大规模集群场景。

public class ClusterTokenServerDemo {

public static void main(String[] args) throws Exception {
// 创建 Token Server
ClusterTokenServer tokenServer = new DefaultClusterTokenServer();

// 配置端口
ClusterServerConfigManager.loadGlobalTransportConfig(
new ServerTransportConfig()
.setPort(18730)
.setIdleSeconds(600)
);

// 配置命名空间(应用名)
ClusterServerConfigManager.loadServerNamespaceSet(
Collections.singleton("my-service")
);

// 启动
tokenServer.start();
}
}

嵌入模式(嵌入应用)

将 Token Server 嵌入到某个应用中,该应用既作为业务应用,又作为 Token Server。适合小规模集群场景。

<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-cluster-server-default</artifactId>
<version>1.8.8</version>
</dependency>

通过 API 切换模式:

# 切换为 Server 模式
http://<ip>:<port>/setClusterMode?mode=1

# 切换为 Client 模式
http://<ip>:<port>/setClusterMode?mode=0

# 关闭集群限流
http://<ip>:<port>/setClusterMode?mode=-1

服务端配置

配置项说明默认值
port服务端口18730
idleSeconds连接空闲超时时间600
maxAllowedQps最大允许的总 QPS-

配置最大允许 QPS 可以对 Token Server 的资源使用进行限制,防止在嵌入模式下影响应用本身:

ClusterServerConfigManager.loadGlobalFlowConfig(
new ServerFlowConfig()
.setMaxAllowedQps(20000)
);

动态规则配置

在集群限流场景下,推荐使用动态规则源来管理规则。

客户端规则配置

// 使用 Nacos 作为规则数据源
ReadableDataSource<String, List<FlowRule>> flowRuleDataSource =
new NacosDataSource<>(remoteAddress, groupId, dataId, parser);
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());

服务端规则配置

集群限流服务端有命名空间(namespace)的概念,需要注册根据 namespace 生成动态规则源的 PropertySupplier:

ClusterFlowRuleManager.setPropertySupplier(namespace -> {
return new NacosDataSource<>(remoteAddress, groupId,
namespace + "-flow-rules", parser).getProperty();
});

每当集群限流服务端 namespace set 产生变更时,Sentinel 会自动针对新加入的 namespace 生成动态规则源并进行监听。

Spring Cloud Alibaba 整合

添加依赖

<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>
</dependency>

配置文件

spring:
application:
name: my-service
cloud:
sentinel:
transport:
dashboard: localhost:8080
datasource:
flow:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-flow-rules
groupId: SENTINEL_GROUP
rule-type: flow

启用集群限流

@Configuration
public class SentinelClusterConfig {

@PostConstruct
public void init() {
// 配置 Token Server 地址
ClusterClientConfig clientConfig = new ClusterClientConfig();
clientConfig.setServerHost("192.168.1.100");
clientConfig.setServerPort(18730);
clientConfig.setRequestTimeout(20);

ClusterClientConfigManager.applyConfig(clientConfig);

// 设置为 Client 模式
ClusterStateManager.applyState(ClusterStateManager.CLUSTER_CLIENT);
}
}

监控与运维

查看集群状态

# 查看 Token Server 连接信息
curl http://localhost:8719/cluster/server/transportInfo

# 查看客户端连接状态
curl http://localhost:8719/cluster/client/transportInfo

Token Server 分配

在生产环境中,可以使用 Sentinel 控制台的集群流控管理功能来动态分配 Token Server。控制台可以:

  • 查看所有应用的机器列表
  • 指定某台机器作为 Token Server
  • 动态调整 Server/Client 角色

高可用考虑

  1. Token Server 高可用:部署多个 Token Server,通过负载均衡或主备切换实现
  2. 失败降级:配置 fallbackToLocalWhenFail = true,确保服务可用性
  3. 监控告警:监控 Token Server 的健康状态和性能指标

注意事项

1. 网络延迟

集群限流需要与 Token Server 进行网络通信,会有一定的延迟。建议:

  • Token Server 部署在与应用同机房的位置
  • 设置合理的 requestTimeout(默认 20ms)
  • 高频调用的场景谨慎使用

2. Token Server 性能

Token Server 的处理能力会影响整个集群的限流效果。建议:

  • 使用独立模式部署,避免影响业务应用
  • 配置合理的 maxAllowedQps
  • 监控 Token Server 的资源使用情况

3. 规则同步

确保所有 Client 的规则配置与 Server 一致,否则可能导致限流效果异常。

4. 服务发现

在动态扩缩容场景下,需要考虑服务发现机制,确保新加入的机器能够正确连接到 Token Server。

最佳实践

1. 选择合适的阈值模式

  • 机器数量相对固定:使用全局阈值模式
  • 机器数量动态变化:使用单机均摊模式

2. 合理配置失败降级

clusterConfig.setFallbackToLocalWhenFail(true);

确保在 Token Server 不可用时,服务仍然可用。

3. 监控与告警

  • 监控 Token Server 的健康状态
  • 监控集群限流的触发情况
  • 设置合理的告警阈值

4. 压测验证

在生产环境使用前,进行压测验证:

  • 验证限流效果是否符合预期
  • 测试 Token Server 的性能瓶颈
  • 验证失败降级机制是否正常

与单机限流的对比

特性单机限流集群限流
部署复杂度简单复杂
精确度依赖流量均匀分布精确控制总量
性能影响无网络开销有网络通信开销
可用性无单点问题需要 Token Server 高可用
适用场景流量相对均匀需要精确控制总量

下一步