docs(route): define deployment-wide SFU admission
This commit is contained in:
1 parent
6b0b1a37e3
commit
56ae363838
5 files changed
+66
-10
No files matched your search
@@ -184,6 +184,20 @@ SFU and TURN remain bounded fallback resources with independent deployment-wide
|
||||
admission. Resource exhaustion produces the next bounded candidate, an explicit
|
||||
wait, or failure; it never creates unbounded central fanout.
|
||||
|
||||
For the single-process deployment, SFU admission is one injected in-memory
|
||||
authority with deployment-wide ingress and egress counters. Enabling LiveKit
|
||||
requires explicit positive safe-integer `SFU_INGRESS_CAPACITY` and
|
||||
`SFU_EGRESS_CAPACITY` values; neither has a product default and neither is
|
||||
derived from endpoint capacity, Viewer admission, or a fixed root count. One
|
||||
Host publication consumes one ingress unit and every SFU subscription consumes
|
||||
one egress unit. A concurrently media-producing candidate consumes its actual
|
||||
units in addition to the committed generation. The controller reserves against
|
||||
the exact room, share, and publication generation before token issuance,
|
||||
promotes that reservation at route commit, and idempotently releases it on
|
||||
abort, timeout, participant loss, share rollover, room stop, or room deletion.
|
||||
A multi-process application deployment requires a shared atomic admission
|
||||
authority before it may claim these values are deployment-wide.
|
||||
|
||||
## Current Production Divergence
|
||||
|
||||
Production release `9461e20` predates this revision. Its exact behavior is owned
|
||||
|
||||
+15
-9
@@ -219,7 +219,8 @@ PEER_ASSISTED_MEDIA=true
|
||||
LIVEKIT_URL=wss://share.example.com
|
||||
LIVEKIT_API_KEY=<GENERATED_LIVEKIT_API_KEY>
|
||||
LIVEKIT_API_SECRET=<INDEPENDENT_SECRET_OF_AT_LEAST_32_BYTES>
|
||||
MAX_SFU_ROOTS_PER_ROOM=2
|
||||
SFU_INGRESS_CAPACITY=<MEASURED_DEPLOYMENT_INGRESS_COPIES>
|
||||
SFU_EGRESS_CAPACITY=<MEASURED_DEPLOYMENT_EGRESS_COPIES>
|
||||
```
|
||||
|
||||
The rejected `PEER_ICE_TURN_*` participant-wide tuple is removed; supplying any
|
||||
@@ -247,7 +248,7 @@ errors to the result.
|
||||
`PEER_ASSISTED_ROOM_IDS` is retired. Supplying it, even blank, fails startup so
|
||||
that a stale room-1 deployment cannot silently retain the old scope. With
|
||||
`PEER_ASSISTED_MEDIA=true`, every normal room receives peer-assisted routing,
|
||||
optional LiveKit fallback, and the same per-room root/fanout/failure guards.
|
||||
optional LiveKit fallback, and the same deployment resource/fanout/failure guards.
|
||||
Every ordinary peer connection remains STUN-only; selected-edge TURN is still
|
||||
issued only to a current controller-selected edge. There is no browser control,
|
||||
percentage rollout, or second router.
|
||||
@@ -282,14 +283,19 @@ sender atomically on `screener-v6`; restore the exact prior environment and
|
||||
release together when rolling back.
|
||||
|
||||
The three `LIVEKIT_*` values must either all be absent or all be present, and a
|
||||
complete tuple requires `PEER_ASSISTED_MEDIA=true`. An empty tuple keeps the
|
||||
optional SDK and server path dormant. `LIVEKIT_URL` must be a plain `ws:` or
|
||||
`wss:` origin with no `/rtc` suffix; production requires `wss:`.
|
||||
complete tuple requires `PEER_ASSISTED_MEDIA=true` plus explicit positive
|
||||
safe-integer `SFU_INGRESS_CAPACITY` and `SFU_EGRESS_CAPACITY` values. The two
|
||||
capacities have no defaults and must be selected from the instance's measured
|
||||
publisher/subscriber/bitrate and accepted concurrency matrix. Supplying either
|
||||
capacity without the complete fallback configuration fails startup rather than
|
||||
silently enabling or ignoring a partial policy. An empty tuple with neither
|
||||
capacity keeps the optional SDK and server path dormant. `LIVEKIT_URL` must be a
|
||||
plain `ws:` or `wss:` origin with no `/rtc` suffix; production requires `wss:`.
|
||||
`LIVEKIT_API_SECRET` must contain at least 32 bytes and must not reuse
|
||||
`SITE_ACCESS_PASSWORD`. In that same held release, `MAX_SFU_ROOTS_PER_ROOM` defaults to
|
||||
2 and accepts only 1 or 2; it is ignored when LiveKit is not configured. These
|
||||
credentials authorize short-lived LiveKit room tokens and do not provide E2EE:
|
||||
the LiveKit operator can access ordinary SFU media.
|
||||
`SITE_ACCESS_PASSWORD`. These credentials authorize short-lived LiveKit room
|
||||
tokens and do not provide E2EE: the LiveKit operator can access ordinary SFU
|
||||
media. The current admission owner is one Screener process; run only one
|
||||
application process until a shared atomic ledger is implemented.
|
||||
|
||||
For the first candidate canary, use an isolated instance and a protected
|
||||
persistent room whose ID is stable across restarts. Restart the application and
|
||||
|
||||
@@ -533,6 +533,39 @@ the server must. Redundancy can improve recovery but costs traffic and
|
||||
coordination; removing redundancy leaves a recovery interval after a relay is
|
||||
lost.
|
||||
|
||||
## Deployment-Wide SFU Admission
|
||||
|
||||
LiveKit's official benchmark guidance says each room must fit on one SFU node
|
||||
and identifies published tracks, subscribers, and bytes forwarded per subscriber
|
||||
as separate capacity drivers. Its room `maxParticipants` setting is a participant
|
||||
count guard; it does not express Screener's Host-publication ingress or
|
||||
per-subscription egress budget. The application therefore needs its own typed
|
||||
admission boundary instead of treating a root count or the SDK room setting as
|
||||
resource evidence.
|
||||
|
||||
For the current single application process, one O(1) ledger owns two explicitly
|
||||
configured positive safe-integer capacities: each Host publication uses one
|
||||
ingress unit and each authorized SFU subscription uses one egress unit. There is
|
||||
no built-in default or fixed root count. A candidate reserves its full actual
|
||||
ingress/egress demand under exact room/share/publication identity before any
|
||||
token is issued; concurrent old and candidate generations are both charged.
|
||||
Commit promotes the candidate and releases the superseded generation. Abort,
|
||||
timeout, disconnect, share rollover, room stop, and room deletion use the same
|
||||
idempotent release. Capacity exhaustion leaves the current route unchanged and
|
||||
returns control to the bounded fallback sequence.
|
||||
|
||||
These capacities are operator inputs derived from the actual instance, codec,
|
||||
representation, bitrate, and accepted concurrency matrix. LiveKit's published
|
||||
example benchmark cannot supply Screener defaults. A later multi-process
|
||||
Screener deployment needs a shared atomic ledger; independent process-local
|
||||
counters would not be deployment-wide admission.
|
||||
|
||||
Primary sources accessed 2026-08-22:
|
||||
|
||||
- [LiveKit benchmarking](https://docs.livekit.io/transport/self-hosting/benchmark/)
|
||||
- [LiveKit server configuration sample](https://github.com/livekit/livekit/blob/master/config-sample.yaml)
|
||||
- [LiveKit access tokens and room configuration](https://docs.livekit.io/frontends/reference/tokens-grants/)
|
||||
|
||||
## Route Screening
|
||||
|
||||
| Route | Where copies are emitted | Endpoint cost | Evidence status |
|
||||
|
||||
@@ -376,6 +376,8 @@ Parent selection 使用硬过滤加字典序,不建立综合质量评分器。
|
||||
|
||||
所有非服务器端点共享一个 server-authoritative steady outbound media-copy capacity:唯一配置 `ENDPOINT_MEDIA_COPY_CAPACITY` 默认 `2`,只接受 `1`、`2` 或 `3`,不兼容旧键。peer child 或 Host publication 各占一份,upstream receive 免费,committed selected TURN 只替换同一份 edge transport;SFU subscriber egress 与 TURN allocation 使用独立 server admission。客户端 capability 只能收紧该值,不能按角色、浏览器、UA、设备或页面可见性建立另一套 policy。服务端通过 v6 `authenticated.endpointMediaCopyCapacity` 把最终值交给 Web 与 Native;Native 不从 `maxViewers` 推导发送预算,普通 admission、peer-assisted child assignment 和槽位分配共用该值。代码通过一个 shared accounting guard 执行,不在 Host、Viewer、active、recovery 或 migration 分支重复 magic number;client/server/native wire 随该能力原子升级。首个迁移波次在独立 server admission 就绪前保留现有 SFU subscriber 与 room-wide selected-lease 安全护栏,但不把其固定值当作产品 policy;`C=3` 满载时必须在发出会产生第四份 Host media copy 的 token/grant 前明确等待或失败。
|
||||
|
||||
SFU admission 在应用单进程中只有一个注入实例。LiveKit credential tuple 完整时,`SFU_INGRESS_CAPACITY` 与 `SFU_EGRESS_CAPACITY` 都必须显式配置为正 safe integer;它们没有产品默认值,也不从 Viewer 数、endpoint cap 或历史 root 数推导。账本只保存全局已用计数和按 exact room/share/publication generation 索引的 `reserved | committed` 条目:Host publication 计 ingress `1`,每个订阅计 egress `1`,候选与旧 generation 并存时按实际副本同时计数。route controller 先 reserve,再 prepare 和签发 token;media proof 后 commit candidate 并释放同房旧 generation,任何失败、超时、失联、分享换代、停止或删房都调用同一幂等 release。所有操作是 Map lookup 与整数加减,不扫描房间或参与者。当前切片不实现 TURN allocation admission,不改 parent selection,也不预建多进程协调;多应用进程部署必须先增加共享原子 owner。
|
||||
|
||||
普通 Web relay 把收到的 remote track 加入独立 downstream `RTCPeerConnection`,因此可能逐跳解码和重编码;浏览器不保证跨连接 shared encode。每条 ordinary child 是独立网络副本,实际 encode time、CPU/GPU、bitrate、loss、frame rate、depth 和 recovery 必须测量。
|
||||
|
||||
迁移使用 exact room/share/session/revision/assignment/connection/media-binding identity。旧 route 保持 active,candidate 在 active map 外准备;只有当前代 live track、正 RTP 与 decoded-frame progress 同时成立时才原子 promotion。失败、超时、代次变化或授权撤销销毁 candidate 并保留或恢复旧 route。Make-before-break 的 overlap 由统一端点容量、单个有界 `TransitionOverlapSlot` 和 typed server-resource admission 同时决定。
|
||||
|
||||
+2
-1
@@ -52,7 +52,7 @@ SFU/TURN 的 publication、subscription、transport、server-resource accounting
|
||||
- 原生 shared encode relay:具备原生 relay 能力的非服务器端点同样受统一服务端权威下游容量约束,并应复用兼容编码输出而不再次编码。当前普通浏览器 relay 使用逐边重编码的标准 WebRTC 路径,不伪称 shared encode。
|
||||
- SVC 重开条件:当前标准 Web/LiveKit SVC 已静态拒绝为 `no-go-web-svc-cross-path-hardware-contract`。sender `scalabilityMode` 没有 direct/peer receiver 对应的按层选择或跨 PeerConnection shared-encode 契约;requested/applied mode、Media Capabilities `powerEfficient` 和 RTCStats encoder 字段也不能证明没有静默软件 fallback。Pinned client 2.22.0 还会把 screen-share SVC 覆盖为三层 temporal-only `L1T3`,不满足低分辨率 base 与最多两层。只有未来 native sender 能明确选择硬件编码器、最多发布两层、将同一编码输出复用于 direct/peer/SFU、保持每条路径独立选择并通过真实游戏和亚秒延迟门槛时,才可用新的 capability decision 重开 SVC;不能把浏览器 API 支持或 UA 推断当成采用理由。
|
||||
- 分包/分层多树实验:把编码包、对象或可独立解码层拆到多个 peer 路径以分散上传,只能在独立 spike 中验证。必须保持亚秒级,处理多父重组、排序、丢包恢复、关键帧、同步和节点退出;未通过门槛前不进入产品路由控制器。
|
||||
- SFU/TURN 中央兜底:产品部署可以提供有界 SFU 与可选 TURN 资源,但不要求用户选模式,也不得默认变成整房 always-SFU。只有 Host 拥有一个 authoritative publication;SFU-fed Viewer 具备独立出站证明时才可继续 relay,严格受限 Viewer 保持 leaf。TURN 是某条授权 logical edge 或 Host-SFU ingress 的 selected transport,不是拓扑节点。central egress/admission、temporary overlap 和 exact fallback 由同一个 route controller 与资源账本约束,不能由固定 root 数或普通端点 child 数代替。
|
||||
- SFU/TURN 中央兜底:产品部署可以提供有界 SFU 与可选 TURN 资源,但不要求用户选模式,也不得默认变成整房 always-SFU。只有 Host 拥有一个 authoritative publication;SFU-fed Viewer 具备独立出站证明时才可继续 relay,严格受限 Viewer 保持 leaf。TURN 是某条授权 logical edge 或 Host-SFU ingress 的 selected transport,不是拓扑节点。启用 LiveKit fallback 时必须显式提供无默认值的正整数 `SFU_INGRESS_CAPACITY` 与 `SFU_EGRESS_CAPACITY`;一份 Host publication 占一个 ingress,每份 SFU subscription 占一个 egress,实际并行 candidate 另占资源。单进程部署由一个 O(1) 全局账本在发 token 前按 exact room/share/publication fence reserve,commit 后替换旧 generation,abort、timeout、disconnect、share rollover、room stop/delete 都幂等释放。固定 root 数和普通端点 child 数都不能代替该准入;资源耗尽进入下一条有界候选、明确等待或失败。多应用进程部署必须先引入共享原子账本,不能把各进程本地计数相加冒充全局准入。
|
||||
- 分享端桌面封装:用 Electron 固定 Chromium 版本、改善选源/热键/系统音频体验,同时保留 Web 观看端。
|
||||
- Windows 应用音频:Windows 11 Native sender 使用本地 opaque window target 绑定 HWND、PID 与进程创建时间,只捕获所选游戏及其子进程的音频,避免把语音聊天或通知声一并分享;“全部系统声音”只能由分享者显式选择。普通 Windows 10 不具备当前 process-loopback API 门槛,必须明确标为未解决/不支持而不是伪兼容。浏览器无法证明或隔离任意进程音频时必须如实提示,原生捕获失败、无声或进程退出不得静默扩大为整机捕获。
|
||||
- 受限网络增强:短期鉴权 TURN 只有在完整、默认关闭的部署配置和当前 route controller 明确授权时可用;普通 peer PC 从创建起保持 STUN-only,不得向整个 participant、房间或所有 peer connections 预发 TURN candidates。凭据必须绑定 exact room/share/session/route/connection generation,短期有效、内存态、受配额约束且不进入 URL、日志、浏览器持久化或 SQLite。TURN 只替换授权 edge 的 transport;Host 无 direct first-level path 时可作为单条 Host-SFU ingress 的 transport。TURN 不得被描述为更高清的传输方式。
|
||||
@@ -139,6 +139,7 @@ SFU/TURN 的 publication、subscription、transport、server-resource accounting
|
||||
- Given ADR-0004 的任一硬门槛只有在引入 Encoded Transform/DataChannel/WebCodecs 媒体、自定义拥塞控制、FEC/RTX、多树、综合评分、转码、codec ladder、浏览器 RTP 注入 hack 或放宽 endpoint capacity 后才能满足,When 结束 bounded spike,Then 放弃并删除该浏览器 relay 实验路径,保留标准 P2P 与整体路由模型已接受的 fallback;后续 native shared encode sender 仍按独立 ADR 推进,但不能据此把失败的 relay 拓扑判为通过。
|
||||
- Given 新观看者会使预计总上行超过安全预算,When 其请求加入,Then 系统只选择整体路由模型已授权且满足配置容量与资源准入的路径;没有合格路线时明确等待或拒绝,而不是创建超过配置容量的 ordinary edge 或持续堆积发送队列。各 transport 的拥塞控制适应该路径,应用证据只改变拓扑资格,不能合成全房降档。
|
||||
- Given SFU 或 TURN 参与路线,When 计算准入、迁移 overlap 或失败恢复,Then 同时检查统一端点容量和独立的 server ingress/egress、SFU、TURN 资源预算;不得把普通端点 child 数当作 server cap,也不得借兜底形成无界整房 fanout。
|
||||
- Given 配置完整 LiveKit credential tuple,When `SFU_INGRESS_CAPACITY` 或 `SFU_EGRESS_CAPACITY` 缺失、非正整数或超出 JavaScript safe-integer 范围,Then 服务必须在启动时 fail closed。Given 两项均有效,When 当前 committed 与 reserved 的 ingress 或 egress 会越过任一部署容量,Then controller 必须在签发任何新 SFU token 前拒绝该 candidate,并保持旧 route 和计数不变。
|
||||
- Given Host、relay parent 或 leaf 处于受限网络,When direct/peer 路径不足,Then 只执行 ADR-0005 授权的 publisher、subscriber、selected transport 和 fallback sequence;不得靠未授权的固定数量或静态 lease 假设猜测实现。
|
||||
|
||||
### 质量和恢复
|
||||
|
||||
Reference in new issue
Block a user