Skip to content

RobustMQ 限流模块的设计

限流是消息中间件的基础能力,没有它,一个行为异常的客户端就能把整个集群的资源耗尽。

为什么要两层

消息中间件通常要同时服务多个业务方,这就是多租户场景下的核心矛盾:任何一个租户的流量突增,都不应该让其他租户受到影响。

只在集群层限流解决不了这个问题,某个租户把集群配额占满,其他人就什么也做不了。只在租户层限流则保护不了节点本身,极端情况下节点依然可能被打垮。

所以两层都要有——节点层是节点自保,租户层是租户间隔离。

text
请求到来


节点层(保护节点总资源)


租户层(保障租户间资源隔离)


处理请求

两种不同的限流方式

限流有两种完全不同的语义,RobustMQ 都有用到。

速率限流

限制每秒最多处理多少个请求,用令牌桶算法实现。超出速率的请求不会立刻被拒绝,而是等待令牌补充。

这适合连接建立、消息发布这类场景——流量突然上来,让它排个队平滑一下,比直接断掉客户端要好。

数量限流

限制某类资源的总量,超出就直接拒绝,不等待。

这适合连接数、会话数、主题数这类场景——资源没有释放,等再久也没用。

速率限流覆盖的范围

速率限流分两块:全局和 MQTT 协议层。

全局层不区分协议,控制网络层面的速度:

  • 每秒新建 TCP 连接数,防止连接风暴
  • 管理 API 按 URI 维度限速,防止管理操作压垮 Broker

MQTT 层在节点和租户两个维度各有控制:

限流维度节点层租户层
消息发布速率节点每秒最多发布多少条消息单租户每秒最多发布多少条消息
连接建立速率节点每秒最多建立多少个新连接单租户每秒最多建立多少个新连接

租户的限流器是懒加载的,首次请求时按租户配置初始化,后续直接命中缓存。节点层速率可以运行时热更新,不需要重启服务。

数量限流覆盖的范围

连接数

新连接建立时检查两件事:节点当前总连接数是否超过集群配置的 max_connections_per_node,以及该租户的连接数是否超过自己的配额。任一超限,CONNECT 请求被拒绝。

会话数

会话和连接是两个独立的概念。持久会话(Clean Start = 0)断开连接后会话仍然保留,所以会话数和连接数不一定相等,两个维度都要单独检查。

主题数

主题是全局资源,创建新主题时检查节点总量和租户配额。

QoS 飞行窗口

这个限制和多租户无关,是针对单个连接的。

MQTT 客户端在连接时可以通过 Receive Maximum 属性声明自己能同时处理多少条 QoS1/QoS2 的在途消息(已发出但尚未完成确认握手的)。Broker 向该客户端推送时,如果在途消息数达到这个上限,就必须停下来等已有消息确认完成再继续。

这个机制是保护客户端的,防止 Broker 发得太快把客户端的缓冲区撑爆。

限流在请求处理中的顺序

PUBLISH 消息:

text
Client → PUBLISH

  ├─ 主题数是否超限?
  ├─ QoS 飞行窗口是否已满?
  ├─ 发布速率是否超限?(等待令牌)


消息处理(存储、路由、推送订阅者)

CONNECT 请求:

text
Client → CONNECT

  ├─ 连接速率是否超限?(等待令牌)
  ├─ 连接总数是否超限?
  ├─ 会话总数是否超限?


建立连接、加载会话

配置

集群层(broker.toml)

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租户每秒最大发布消息数

租户配额通常设得比集群配额小。集群配额是硬上限,租户配额是在这个上限内的再切分,两者要配合着用。

🎉 既然都登录了 GitHub,不如顺手给我们点个 Star 吧!⭐ 你的支持是我们最大的动力 🚀