Skip to content

按用户名的会话配额

该插件用于强制执行按用户名的会话配额。

  • 会话计数按用户名维护,并在集群范围内同步。
  • 当达到配置的配额时,认证会以 quota_exceeded 被拒绝。
  • 使用已存在的 clientid 重连不会占用额外的配额。
  • 按用户名的配额覆盖(overrides)支持自定义上限、无限会话或阻断连接。

提示

如果部署中可以通过在 client_attrs_init 配置中设置 client_attrs.tns,将用户名作为命名空间,则可以通过基于命名空间的会话数量限制实现这类控制。 仅当命名空间分配采用其他方案时,才需要使用此插件。

配置

字段默认值校验规则说明
max_sessions_per_username100必须为正整数(>= 1)。小于 1 或非数字的值会被拒绝。每个用户名默认的最大并发会话数。单个用户名可通过 overrides API 覆盖此值。
snapshot_min_age_ms300000必须在 120000900000 范围内。超出范围的值会被截断到边界。触发重建前快照的最小存活时间,单位为毫秒。用于避免在大型集群上频繁重建。
snapshot_request_timeout_ms5000字符串值如可转换为正整数,也会被接受。列表 API 快照请求处理的超时预算。

通过标准的插件配置 API 更新插件配置:

PUT /api/v5/plugins/<name-vsn>/config

运行时 API

该插件通过插件 API 网关暴露运行时 API。

基础路径:/api/v5/plugin_api/emqx_username_quota

会话查询

  • GET /quota/usernames:列出所有有活跃会话的用户名。
  • GET /quota/usernames/:username:获取单个用户名的详情。
  • GET /metrics:以 Prometheus 文本格式导出插件指标。
  • POST /kick/:username:踢除某个用户名的所有会话。

快照管理

  • DELETE /quota/snapshot:强制重建快照。

配额覆盖

  • POST /quota/overrides:设置按用户名的配额覆盖。
  • DELETE /quota/overrides:删除按用户名的配额覆盖。
  • GET /quota/overrides:列出所有配额覆盖。

GET /quota/usernames

该接口从预先构建的快照返回结果,而不是在每次请求时扫描实时会话数据。

快照是按用户名会话计数的某一时刻副本,按计数排序以支持高效的基于游标的分页。快照在后台异步构建并缓存;仅当当前快照存活时间超过 snapshot_min_age_ms 时,才会触发新的构建。

当第一个请求到达且尚无快照时,服务器会等待正在进行的构建完成,最长等待时间为请求截止时间减 1 秒。如果构建及时完成,接口返回正常的 200 响应;否则返回带有部分数据的 503

查询参数:

  • limit:正整数,上限为 100(默认 100
  • used_gte:无游标时必填。表示最小会话计数过滤条件,仅包含会话数不少于该值的用户名。必须为正整数(>= 1)。
  • cursor:可选的不透明游标,由上一次列表调用返回。若缺省,则返回第一页。

参数规则:

  • used_gtecursor:OK(第一页)
  • cursorused_gte:OK(used_gte 已内嵌在游标中)
  • 同时有 used_gtecursor400 BAD_REQUEST。过滤条件已锁定在游标中。
  • 既无 used_gte 也无 cursor400 BAD_REQUEST

行为:

  • 结果始终按会话计数再按用户名排序。
  • 分页基于游标。第一页请求省略 cursor
  • 每一项包含 username、实时的 used 以及 limit(有效配额)。
  • 如果实时 used 与快照计数不同,则包含 snapshot_used,使调用方能够同时看到缓存值和当前值。

成功响应结构:

  • data:用户名配额条目
  • meta.limit:页大小(分页上限)
  • meta.count:本页条目数
  • meta.total:快照中的总条目数
  • meta.next_cursor:下一页的游标(在可用时)
  • meta.snapshot:快照元数据:
    • node
    • generation(递增的快照 id)
    • taken_at_ms(快照时间戳,毫秒)

错误响应:

  • 400 BAD_REQUEST:缺少 used_gte,或在带游标时提供了 used_gte
  • 400 INVALID_CURSOR:游标引用了不可用的节点或格式错误
  • 503 SERVICE_UNAVAILABLE:快照正在重建
    • 响应体包含 snapshot_build_in_progress: truedatameta
    • data:从正在构建的快照中读取的部分第一页(如果构建刚开始可能为空)
    • meta.count:部分条目数,meta.partial: true
    • 使用有界退避重试同一请求

DELETE /quota/snapshot

强制立即重建快照。在异步发起重建后返回 200{"status": "ok"}。快照将在后台重建。

GET /quota/usernames/:username

返回单个用户名的详情。响应字段:usernameusedlimitclientids

如果该用户名没有活跃会话,返回 404 NOT_FOUND

GET /metrics

以 Prometheus 文本格式返回插件指标。 在 replicant 节点上,请求会被转发到快照所属的 core 节点。

当前导出:

  • emqx_username_count:当前活跃快照中的用户名总数。

POST /kick/:username

踢除某个用户名的所有会话。返回 {"kicked": N},其中 N 为被踢除的会话数。

如果该用户名没有活跃会话,返回 404 NOT_FOUND

POST /quota/overrides

设置按用户名的配额覆盖。请求体为 JSON 数组:

json
[
  {"username": "user1", "quota": 1000},
  {"username": "vip", "quota": "nolimit"},
  {"username": "blocked", "quota": 0}
]

覆盖语义:

quota 取值含义
正整数该用户名的自定义会话上限
"nolimit"无限会话(不做配额限制)
0封禁:拒绝所有新连接

覆盖会持久化到磁盘并在集群范围内复制。当某个用户名没有覆盖时,使用全局配置 max_sessions_per_username

DELETE /quota/overrides

按用户名删除覆盖。请求体为用户名字符串的 JSON 数组:

json
["user1", "blocked"]

GET /quota/overrides

列出所有覆盖。返回 {"data": [{"username": "...", "quota": ...}, ...]}

基于快照的列表查询机制

本节说明插件如何为 GET /quota/usernamesGET /metrics 等列表类 API 构建并提供快照数据。

快照所属节点路由

快照在 core 节点上构建。GET /quota/usernamesGET /metrics 会被路由到快照所属的 core 节点,该节点选取为已排序的运行中 core 节点列表中的第一个。

蓝绿快照

维护两个快照缓冲区(蓝和绿)。当其中一个用于服务读取请求时,另一个用于构建下一个快照。一旦构建完成,两者角色互换。旧快照会一直可用,直到新快照就绪,从而避免重建期间出现数据空档。

后台快照构建

快照重建在后台进程中运行,采用基于让出(yield)的节流以避免阻塞服务器。构建进行期间列表 API 仍保持响应。

运维注意事项与限制

本节说明在生产环境中运行该插件时需要关注的运行时行为与限制。

连接突发下的配额超额

配额决策在认证阶段做出,而会话计数在会话生命周期钩子中最终确定。在高并发连接突发(尤其是在集群中)时,这会造成一个短暂的同步窗口,期间某个用户名被观察到的并发会话数可能暂时超过 max_sessions_per_username

实际影响:

  • 该插件在突发负载下以最终一致性提供集群范围的配额强制。
  • 在极端连接扇入场景下,该插件不保证在任意时刻都能严格逐连接执行配额限制。

插件启动时的引导行为

当插件被安装到运行中的集群时,已有的客户端会话是在钩子注册之前建立的。启动时,插件通过遍历所有本地 channel 并注册每个会话来引导配额状态。

为避免以大量 DB 写操作压垮 Core 节点(尤其当 replicant 节点已有大量现有连接时),引导循环会被节流:

  • 会话以每批 100 个进行注册。
  • 每批之后,引导会等待最后写入的记录被复制回本地表后再继续。它每 10ms 轮询一次。
  • 如果复制在 10 秒内未完成,会记录一条错误,并以 error 级别日志中止引导。 超时前已注册的会话会被保留;其余会话将在重连时通过后续基于钩子的注册自然被纳入。

处理列表 API 返回的 503 响应

当服务器繁忙或正在构建快照时,列表 API 返回 503

503 响应体包含一个 data 数组,其中是从正在构建的快照表中读取的部分第一页。这为调用方立即提供尽力而为的数据,而不是空响应。meta.partial: true 标志表明数据不完整。如果构建刚开始,部分页可能为空。

API 客户端指南:

  • 检查 data 中立即可用的任何部分结果。
  • 使用有界退避重试。

下载

各 EMQX 版本对应的插件安装包:

EMQX 版本插件版本安装包
6.1.11.0.0emqx_username_quota-1.0.0.tar.gz
6.1.21.2.1emqx_username_quota-1.2.1.tar.gz
6.1.31.2.2emqx_username_quota-1.2.2.tar.gz