WuKongIM MQTT 精确 Owner 执行与静默(Quiescence)契约:从本地准入栅栏到跨节点接管证明
发布时间:2026/10/15 11:27:58 锦皓数字建站
契约:从本地准入栅栏到跨节点接管证明`)
即时通讯后端【免费下载链接】WuKongIMMore than just IM 不只是即时通讯(IM)项目地址https://gitcode.com/gh_mirrors/wu/WuKongIM点击查看免费下载导读本文以 WuKongIM 仓库内 MQTT owner execution and quiescence 规范文档为主体系统讲解 MQTT 模块中“连接 Owner执行主体的本地执行门禁”如何与“跨节点接管时的隔离证明”协作从Owner身份模型、Reserve/Activate/Renew/Begin/Quiesce生命周期到 Service 107 精确 Owner RPC 的二进制编解码再到配套的自动清扫sweep调度与可观测指标。读完本文你将掌握 WuKongIM 如何通过本地单调时钟 保守执行期限挡住过期执行同时拒绝用本地过期代替分布式隔离证明并能在源码与测试中逐一找到对应实现。模块定位owner 本地半边与权威协议的边界该模块是“已批准接管契约takeover contract”的 owner 本地半边。它明确声明自己不会把“socket 关闭请求、context 取消或 deadline”当成“旧 owner 已停止”的分布式证明。运行时激活仍然要求一个已提交committed的 Session owner由权威 lease 协议提供的保守本地执行期限conservative local execution deadline。在协议、恢复与投递被完整接线并验证之前产品准入product admission保持关闭。换句话说mqttsession运行时包只负责有界本地执行与静默不负责认证用户、不获取持久所有权、不推导分布式 lease、不发布消息也不解释 MQTT 报文——这一点在 internal/runtime/mqttsession/FLOW.md 的 Responsibility 中写得很明确。实现前的故障清单Failure Inventory规范文档在实现前整理了一份九大类故障清单每一项都对应后续实现中的一条硬性约束理解它们才能看懂代码为什么这样写待定预留pending reservation抢在已提交激活之前执行不同 UID、ClientID、生命周期、owner 代际、进程或连接可能作用于错误的 owner。ClientID 共存不得继承 WK 主设备冲突规则。过期/重复的激活或续期延长执行过期 owner 可能因 expiry worker 迟到而重启。因此每个操作都同步、独立于清扫调度地检查本地期限。Quiesce 在请求 socket 关闭后就返回成功而已准入的操作仍可能继续执行。成功要求 close 回调完成、且每个已准入操作都释放其 scope仅取消不构成证明。close 错误、回调 panic 或调用方取消不得释放容量或重新打开准入并发 close 调用不得触发互相竞争的回调。失败的 close 保持 fenced 并被保留后续调用可重试同一个精确 owner。缺失行被当作已关闭连接 ID 必须由本注册表分配与发布绝不由调用方提供、复用或包装。只有本进程内已退役的已签发 ID才能证明缺席外部 boot / 未来 ID 一律 fail-closed。限额遗漏 pending/closing owner 或在途 scope续期不得让 expiry 队列无限增长关闭不得为每个连接创建 goroutine 或每 tick 扫描全部 Session。应每个被保留 owner 维护一个索引化期限限制 reservation/operation/sweep 页面并在锁外执行回调。过期与续期竞争过期的堆弹出版本不得关闭已续期的 owner调用方取消或重复释放 scope 不得泄漏计数。快照计数不含身份或凭据。重复清扫只能由 App 驱动。Gateway close 适配不得在未封住报文写入、未关闭物理连接的情况下报告 quiescence运行时回调不得重入 quiescence 造成死锁。回调只负责关闭传输从不等待业务清理。Owner RPC不得接受畸形/无界身份、不得把目标指向别的节点、不得把不支持/缺失/错误响应解读为关闭、不得接受针对另一个 owner 的回执。闭合版本化编解码必须回显完整身份取消与瞬时错误必须和 quiesced 回执区分开。Owner 身份模型与本地契约Owner 的构成Owner是不可变的执行化身标识包含broker namespace 与 ClientID合成KeySession 代际SessionGeneration持久订阅/游标生命周期owner 代际OwnerGeneration每次已提交的连接接管都变化node ID、boot ID注册表重建时必须变化包括 restore注册表签发的连接 IDConnectionID由 owner 注册表签发客户端或之前的 boot 都不能提供。它不含凭据、报文或具体 socket。每个 reservation 只在本节点上保留一个 UID 与一个 close 回调。连接 ID 独立于 Gateway 的 Session ID。以上定义可见 internal/contracts/mqttsession/owner.go其中ValidIdentity对 namespace/ClientID/BootID 的长度、UTF-8 合法性、空串/空白做了统一校验。Reserve待定且有界Reserve在身份进入持久元数据之前发布一个待定身份。不同的 ClientID 与并发候选不会触发 WK 设备踢除。它受两个硬限制len(m.entries) Capacity或issued MaxUint64时返回ErrOwnerLimit。ConnectionID只在注册表锁内递增永不回绕或复用见 internal/runtime/mqttsession/owner.go。OwnerOptions的所有边界在 owner.go 中都有校验参数约束/含义NodeID节点 ID必须非零BootID本进程与注册表生命周期内唯一≤128 字节Capacity包含 pending 与 closing owner范围 [1, 1,000,000]MaxOperations每 owner 准入 scope 上限范围 [1, 1024]无等待队列PendingTimeout激活前未完成本地预留的期限范围 (0, 1 分钟]MaxLease本地执行视野上限范围 (0, 1 分钟]CloseRetry失败/未完成清理的重试延迟范围 (0, 1 分钟]Now与所有提供的期限共用本进程单调时间基NewOwners还会拒绝Now()返回now.Round(0)的假时钟owner.go防止非单调时钟混入。Activate / Renew递增持久修订 未来期限Activate只在调用方证明了这个精确的已提交 owner并推导出保守期限后打开执行Renew只接受更新的已提交回执且仅在现有 lease 存活时有效。延迟续期或精确重试都不能让已 fenced 的 owner 复活。installLease的实现要点owner.go本地时钟已越过e.deadline或处于 closing 阶段 →fenceLocked并返回ErrOwnerFencedrevision 0、期限非单调、until不超过 now、或until.Sub(now) MaxLease→ErrOwnerInvalid精确回执重试相同 revision 相同 until幂等返回 nil但不能移动期限续期要求revision e.revision否则 fenced。Begin / Operation一次准入一个 scopeBegin在执行任何业务工作前准入一个有界操作其 scope 必须跨越所有关联效果与网络写入保持打开同步检查stopped、owner 非 active、本地期限已过此时会顺带fenceLocked、operations MaxOperations返回ErrOwnerLimitOperation.Done是显式且幂等的CompareAndSwap忽略已取消的 scope 会保留 owner 并防止伪造 quiescence 回执scope不得逃逸到未跟踪的后台效果元数据变更仍携带持久 owner 栅栏Check在不再占用第二个 operation 槽位的情况下重新校验存活 lease即便 sweep 尚未运行期限过期也会栅栏准入owner.go。一个依赖项可能返回时已接受的 Channel 工作仍在继续。此时必须在Done之前调用MarkUncertain它将一个“隔离未证明”的屏障永久保留在这个有界注册表中。物理关闭与本地 scope 排空只会以失败唤醒等待者时间、Sweep 与 Close 都不能擦除它且当前没有恢复证明清除 APIowner.go。Quiesce先永久关闭准入再关传输Quiesce的执行顺序owner.gofenceLocked永久关闭准入、取消操作 context不等待不提供隔离证明通过注入的 close 回调关闭传输只有物理关闭与 scope 排空都完成才算成功重复请求合并coalesce到同一个ownerCloseAttempt回调失败保持 fenced、保留容量后续调用可重试同一精确 owner成功回执只针对这个精确 owner不是凭据、未来 owner 或发布授权。callOwnerClose会把回调 panic 与一般错误统一为ErrOwnerClose但保留context.Canceled/DeadlineExceeded语义owner.go。awaitQuiescence在等待结束后还会复查e.uncertain一旦为 true 即返回ErrOwnerUnknown。期限过期是准入栅栏不是已准入工作已排空的证明。分布式接管路径不得用本地过期、presence TTL、boot 不匹配或 best-effort 踢除来替代所需的隔离证明。Fence / Close / StopAdmission关闭路径的三个层次Fence永久关闭准入并取消 scope不调用传输、不等待已准入效果owner.goStopAdmission永久拒绝新 reservation/scope 并取消现有 scope不等待传输或业务清理也不提供证明owner_deadlines.goClose先StopAdmission再按最多 256 个一页循环Quiesce所有保留 owner超时后可重试保留的工作绝不被擦除以伪造成功关闭owner_deadlines.go。已实现的 Owner RPC 契约Service 107线协议规范文档给出的协议被 internal/access/node/mqtt_owner_codec.go 完整实现服务 ID107经既有CallRPC传输向精确 owner 节点请求 quiescence请求 magicWKMQ响应 magicWKMq两者都使用格式字节 1 后跟操作/状态字节请求操作 1 quiesce响应状态 1quiesced、2isolation unproved、3close failed、4cancelled、5deadline exceeded未知格式/操作/状态一律失败双方向按固定顺序携带namespace、ClientID、SessionGeneration、OwnerGeneration、NodeID、BootID、ConnectionID字符串用大端 uint16 字节长度上限 1,024/1,024/128整数为大端 uint64帧上限 2,304 字节拒绝截断与尾部多余字节客户端只接受与其完整精确请求身份匹配的成功不支持的服务或通信失败既不重路由也不推断隔离。测试 internal/access/node/mqtt_owner_rpc_test.go 给出了一个黄金字节串断言574b4d51010100016e0001630000000000000001000000000000000200000000000000030001620000000000000004逐字节对应magicWKMQ、格式 1、操作 1、0001nnamespace、0001cClientID、1SessionGeneration、2OwnerGeneration、3NodeID、0001bBootID、4ConnectionID。同一个测试还验证了对每个前缀截断、尾部追加、4096 字节、JSON、错误操作/格式字节的请求服务端都不调用底层 close 端口对响应中篡改 ConnectionID、BootID 或返回空/单字节的回执客户端一律报错。与 Gateway 物理关闭的衔接Quiescence 的“物理关闭”由 Gateway 的可选能力提供详见 gateway-transport-close-proof.mdtransport.CloseWaiter.CloseAndWait(ctx)栅栏未来写入仅当物理关闭回调成功后才返回 nil取消只限制调用方等待不影响底层关闭后续调用合并到同一个回执pkg/gateway/transport/transport.gosession.OutboundFencer.FenceOutbound()永久关闭普通写入准入不等待已进入的编码器types.Context.CloseTransportAndWait(ctx, reason)要求两个能力都存在栅栏入站/出站准入、取消请求工作、请求物理关闭不调用也不等待协议/业务清理。实现位于 pkg/gateway/core/transport_close.go先检查transport.CloseWaiter与session.OutboundFencer两个能力缺失返回ErrCloseProofUnsupported再FenceOutbound()、取消请求 context最后closer.CloseAndWait(ctx)。文档特别强调在 gnet v2.9.7 中OnClose先于残余写入与 close 系统调用只有CloseWithCallback的完成才能提供这个边界。自动清扫Owner Sweep调度动机即使 acquisition 从未注册连接产品也必须驱动已有的 owner 期限堆。本地期限栅栏准入但不证明远端效果完成也不授权持久 Session 迁移。早期实现前App 集成测试在 7 秒后失败product never swept an expired unregistered reservation——只有已注册连接才受自动监督导致 pending reservation 与未注册过期 owner 永远占用容量。实现契约OwnerSweeper拥有一个可选的受管任务mqtt/owner_sweeper每轮调用Owners.Sweep最多 256 次访问、250ms 取消期限默认间隔 250ms不新增队列、per-owner 任务、表、命令、RPC 或产品配置字段既有的同步准入检查在 sweep 落后时仍会栅栏过期 lease。参数边界在 owner_sweeper.goLimit默认 256、上限 256Interval默认 250ms、范围 [1ms, 1 分钟]TurnTimeout默认 250ms、范围 [1ms, 5s]。一个不配合的回调占用当前轮直到返回Stop可以取消但不能丢弃它。超时的Stop保留 run 所有权并拒绝Start直到后续Stop完成 join。Start的 context 不拥有 runowner_sweeper.go。Sweep 的公平性与选型Owners.Sweepowner_deadlines.go在注册表锁内完成选型、续期与栅栏过期堆顶条目先fenceLocked再把下次尝试移到now CloseRetry——失败 close 不会垄断后续每一页的堆头物理回调在锁外执行一轮内至多访问limit个到期 owner每个保留 owner 在ownerDeadlines堆中只有一个索引化期限续期用heap.Fix修正既有堆项而非追加陈旧记录owner_deadlines.go因此 100 次续期后Snapshot().Deadlines仍为 2见 owner_test.go。复杂度每轮 O(k log n)k 为访问条目数聚合快照 O(1)。调度器每轮只加一个 goroutine/timer 与一个 context绝无per-session goroutine、全注册表扫描或消息体存储。配置的访问上限不是吞吐度量也不构成 10 万用户恢复 SLA——完整规模认证仍需进行见 mqtt-owner-sweeping.md。App 组合中的启动/停止顺序internal/app/mqtt_product.go 展示了完整组合wireMQTT在启用mqtt.enable后注册MQTTOwnerRPCServiceID并向自有 Gateway 追加 mqtt TCP 监听器newMQTTGeneration每次全新构造随机 bootcrypto/rand16 字节 hex、NewOwnersCapacityMaxConnections、MaxOperations8、PendingTimeout5s、MaxLease1 分钟、CloseRetry250ms、sweeper、retirements、dispatches、sessions、connections、deliveries 等Start在Gateway 准入之前启动[sweeper, replay, deadlines, wills, consumers, connections, deliveries]Stop先StopAdmission、停认证再依次 join 各 worker最后owners.Close(ctx)之后才持久化 graceful boot retirement 并释放数据目录锁——顺序保证“先栅栏 owner 准入再在传输与集群依赖仍可用时 join 清扫”。可观测性两个封闭指标wukongim_mqtt_owner_sweep_total只含turns、visited、failures三类事件visits 统计尝试次数含重试不是唯一退役数取消可计为失败轮次wukongim_mqtt_owner_work只含held、pending、active、closing、operations、deadlines、uncertain七种状态零值全部物化。Gauge 是“最后一次采样的聚合”不是原子性的抓取时点普查Stop不会为保留工作伪造零值。实现位于 pkg/metrics/mqtt.go 与 pkg/metrics/mqtt.goObserveOwnerSweep(visited, failed)与SetOwnerWork(state, value)都只接受封闭名称绝不从 owner 身份、回调错误或凭据创建 label。App 侧接线见 internal/app/mqtt_owner_sweep.go。集成测试 internal/app/mqtt_owner_sweep_integration_test.go 验证了完整产品路径单节点 256 hash slot、启用 MQTT 与指标手动owners.Reserve一个“被遗弃”的 pending 连接未走连接注册断言 sweeper 自动关闭它、Held归零、wukongim_mqtt_owner_sweep_total{eventvisited}≥ 1且Stop后所有 MQTT 任务 join、Deadlines归零。与周边模块的协作边界产品组合mqtt-product-runtime.md 注册该适配器并将运行时回调接到 GatewayCloseTransportAndWait只负责物理关闭完成普通CloseSession仍只是关闭请求foreground 组合与 graceful restart retirement 已接线不可达/崩溃 owner 的恢复证明仍是完整接管验收的必需项Session acquisitionmqtt-session-acquisition.md 现在执行带提交结果与“proposal 前捕获期限”的认证 acquisition/renewal它要求显式的 prior-owner isolation隔离端口只有在精确 owner 执行与传输隔离后才返回 nil绝不由 Session 行或时间推导该证明租期默认上限 86,400 秒本地 lease 与注入时钟共用 owner 本地单调时间基Owner sweepermqtt-owner-sweeping.md 补充了自动本地过期/重试清理但不改变分布式证明要求sweeper 永不修改 Session 行、不清除 uncertain 效果、不签发隔离回执。测试验证速览internal/runtime/mqttsession/owner_test.go 覆盖未激活 begin 被 fenced、精确激活幂等、单 owner 操作数上限、身份任一字段篡改即失败、quiescence 等待物理关闭与 scope 排空回执先于 drain 会失败、失败 close 三种模式error/panic/cancel保持 fenced 且占用容量、续期不增长期限堆、取消不结束 operation、关闭后拒绝新 reservationinternal/access/node/mqtt_owner_rpc_test.go 验证 RPC 等待运行时 quiescence先等传输回调触发断言回执未提前返回op.Done()后成功且篡改 BootID 返回ErrOwnerUnknown默认层级全套 runtime/app/metrics/goroutine 测试以-race通过聚焦 race 集成覆盖慢回调 join、保留操作、uncertain 屏障、有界/公平轮次、续期与产品启停。结论与剩余范围WuKongIM 的 MQTT owner 执行模块把“本地执行门禁”与“跨节点隔离证明”严格分离本地一侧用单调时钟、保守期限、有界容量与精确身份保证过期即栅栏、scope 不逃逸、quiesce 不放水远端一侧用 Service 107 的闭合版本化编解码保证只有精确 owner 的回执才算数。目前 foreground 组合与 graceful restart retirement 已接线但崩溃隔离、uncertain 远端效果解析、pending-unsubscribe 与无游标恢复、持久记录回收、restore 再激活以及完整进程故障/规模矩阵仍属于开放工作见 mqtt-owner-sweeping.md 的 Capacity and remaining scope。赞分享即时通讯后端【免费下载链接】WuKongIMMore than just IM 不只是即时通讯(IM)项目地址https://gitcode.com/gh_mirrors/wu/WuKongIM点击查看免费下载相关推荐WuKongIM 禁言插件入口与在途验证从静默拒绝到显式 reason25 的错误契约WuKongIM 禁言插件入口与在途验证从静默拒绝到显式 reason25 的错误契约 本文基于 WuKongIM 仓库中 2026 09 24 的验证即时通讯后端WuKongIM 发送准入诊断权限指标证据补齐契约与三节点重跑验证解析WuKongIM 发送准入诊断权限指标证据补齐契约与三节点重跑验证解析 本文基于 WuKongIM 仓库中的压力诊断记录 docs/reports/2026即时通讯后端WuKongIM MQTT Channel Leader 故障转移写栅栏下的 Replay 恢复与准入重建WuKongIM MQTT Channel Leader 故障转移写栅栏下的 Replay 恢复与准入重建 导读 本文基于 WuKongIM 仓库的 docs即时通讯后端上一篇全球时区速查清单IANA 时区标识符与 UTC 偏移完整对照表reference 项目下一篇Plate 项目 Portable Text 测试索引test-index完全指南从 200 个可运行测试行到源码锚点的检索体系创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。