RobustMQ 限流模块的设计
限流是消息中间件的基础能力,没有它,一个行为异常的客户端就能把整个集群的资源耗尽。
为什么要两层
消息中间件通常要同时服务多个业务方,这就是多租户场景下的核心矛盾:任何一个租户的流量突增,都不应该让其他租户受到影响。
只在集群层限流解决不了这个问题,某个租户把集群配额占满,其他人就什么也做不了。只在租户层限流则保护不了节点本身,极端情况下节点依然可能被打垮。
所以两层都要有——节点层是节点自保,租户层是租户间隔离。
请求到来
│
▼
节点层(保护节点总资源)
│
▼
租户层(保障租户间资源隔离)
│
▼
处理请求两种不同的限流方式
限流有两种完全不同的语义,RobustMQ 都有用到。
速率限流
限制每秒最多处理多少个请求,用令牌桶算法实现。超出速率的请求不会立刻被拒绝,而是等待令牌补充。
这适合连接建立、消息发布这类场景——流量突然上来,让它排个队平滑一下,比直接断掉客户端要好。
数量限流
限制某类资源的总量,超出就直接拒绝,不等待。
这适合连接数、会话数、主题数这类场景——资源没有释放,等再久也没用。
速率限流覆盖的范围
速率限流分两块:全局和 MQTT 协议层。
全局层不区分协议,控制网络层面的速度:
- 每秒新建 TCP 连接数,防止连接风暴
- 管理 API 按 URI 维度限速,防止管理操作压垮 Broker
MQTT 层在节点和租户两个维度各有控制:
| 限流维度 | 节点层 | 租户层 |
|---|---|---|
| 消息发布速率 | 节点每秒最多发布多少条消息 | 单租户每秒最多发布多少条消息 |
| 连接建立速率 | 节点每秒最多建立多少个新连接 | 单租户每秒最多建立多少个新连接 |
租户的限流器是懒加载的,首次请求时按租户配置初始化,后续直接命中缓存。节点层速率可以运行时热更新,不需要重启服务。
数量限流覆盖的范围
连接数
新连接建立时检查两件事:节点当前总连接数是否超过集群配置的 max_connections_per_node,以及该租户的连接数是否超过自己的配额。任一超限,CONNECT 请求被拒绝。
会话数
会话和连接是两个独立的概念。持久会话(Clean Start = 0)断开连接后会话仍然保留,所以会话数和连接数不一定相等,两个维度都要单独检查。
主题数
主题是全局资源,创建新主题时检查节点总量和租户配额。
QoS 飞行窗口
这个限制和多租户无关,是针对单个连接的。
MQTT 客户端在连接时可以通过 Receive Maximum 属性声明自己能同时处理多少条 QoS1/QoS2 的在途消息(已发出但尚未完成确认握手的)。Broker 向该客户端推送时,如果在途消息数达到这个上限,就必须停下来等已有消息确认完成再继续。
这个机制是保护客户端的,防止 Broker 发得太快把客户端的缓冲区撑爆。
限流在请求处理中的顺序
PUBLISH 消息:
Client → PUBLISH
│
├─ 主题数是否超限?
├─ QoS 飞行窗口是否已满?
├─ 发布速率是否超限?(等待令牌)
│
▼
消息处理(存储、路由、推送订阅者)CONNECT 请求:
Client → CONNECT
│
├─ 连接速率是否超限?(等待令牌)
├─ 连接总数是否超限?
├─ 会话总数是否超限?
│
▼
建立连接、加载会话配置
集群层(broker.toml)
[mqtt_limit.cluster]
# 节点最大连接数
max_connections_per_node = 10000000
# 每秒最大新建连接数
max_connection_rate = 100000
# 节点最大主题数
max_topics = 5000000
# 节点最大会话数
max_sessions = 50000000
# 每秒最大发布消息数
max_publish_rate = 10000这些是节点维度的上限,所有租户共享。
租户层(Admin API)
| 字段 | 说明 |
|---|---|
max_connections_per_node | 租户在节点上的最大连接数 |
max_create_connection_rate_per_second | 租户每秒最大新建连接速率 |
max_topics | 租户最大主题数 |
max_sessions | 租户最大会话数 |
max_publish_rate | 租户每秒最大发布消息数 |
租户配额通常设得比集群配额小。集群配额是硬上限,租户配额是在这个上限内的再切分,两者要配合着用。
