211 lines
4.0 KiB
Markdown
211 lines
4.0 KiB
Markdown
# 生产架构说明
|
|
|
|
## 目标
|
|
|
|
将一个前端大屏应用稳定投放到 `14880 x 3510` LED 大屏。
|
|
|
|
硬件约束:
|
|
|
|
- 两台 GPU 服务器。
|
|
- 每台服务器 4 路 4K 输出。
|
|
- 两台服务器品牌或 GPU 可能不同,无法依赖硬件级 GPU 同步。
|
|
|
|
因此系统目标不是让两张 GPU 每一帧硬同步,而是:
|
|
|
|
- 统一业务状态。
|
|
- 统一提交时间。
|
|
- 统一动画时间轴。
|
|
- 输出端本地渲染。
|
|
- 拼控完成物理拼接和输入对齐。
|
|
|
|
## 推荐架构
|
|
|
|
```text
|
|
控制服务 FastAPI
|
|
- 场景管理
|
|
- WebSocket 同步
|
|
- 时间校准
|
|
- ACK 追踪
|
|
- 性能监控
|
|
|
|
左 GPU 服务器
|
|
- 打开 /output/left
|
|
- 渲染完整大屏应用的 left tile
|
|
- 4 路 4K 输出到拼控
|
|
|
|
右 GPU 服务器
|
|
- 打开 /output/right
|
|
- 渲染完整大屏应用的 right tile
|
|
- 4 路 4K 输出到拼控
|
|
|
|
拼控 / LED 控制器
|
|
- 接收 8 路 4K
|
|
- 按物理坐标拼接成 14880 x 3510
|
|
```
|
|
|
|
## 左右屏如何分开
|
|
|
|
完整逻辑画面:
|
|
|
|
```text
|
|
|-------------------------- 14880 --------------------------|
|
|
|------------ left 7440 ------------|-------- right 7440 ----|
|
|
```
|
|
|
|
`config/tiles.json` 定义:
|
|
|
|
```text
|
|
left:
|
|
x=0, y=0, width=7440, height=3510
|
|
|
|
right:
|
|
x=7440, y=0, width=7440, height=3510
|
|
```
|
|
|
|
输出端页面创建完整逻辑大屏坐标系,然后根据自己的 tile 做视口偏移。真实 Three.js 项目中,应使用:
|
|
|
|
```js
|
|
camera.setViewOffset(
|
|
fullWidth,
|
|
fullHeight,
|
|
tile.x,
|
|
tile.y,
|
|
tile.width,
|
|
tile.height
|
|
);
|
|
```
|
|
|
|
## 每台服务器 4 路 4K
|
|
|
|
每台服务器建议配置为 `2 x 2` 逻辑桌面:
|
|
|
|
```text
|
|
7680 x 4320
|
|
```
|
|
|
|
四路输出:
|
|
|
|
```text
|
|
1: x=0, y=0, 3840 x 2160
|
|
2: x=3840, y=0, 3840 x 2160
|
|
3: x=0, y=2160, 3840 x 2160
|
|
4: x=3840, y=2160, 3840 x 2160
|
|
```
|
|
|
|
单侧业务 tile 是 `7440 x 3510`,可以放入该逻辑桌面。
|
|
|
|
## 同步协议
|
|
|
|
场景切换:
|
|
|
|
```text
|
|
POST /api/scenes/{scene_id}/switch
|
|
```
|
|
|
|
服务端广播:
|
|
|
|
```text
|
|
prepare_scene(command_id, apply_at_ms)
|
|
commit_scene(command_id, apply_at_ms)
|
|
```
|
|
|
|
输出端流程:
|
|
|
|
```text
|
|
1. 收到 prepare,记录命令,可预加载资源。
|
|
2. 收到 commit,等到 apply_at_ms。
|
|
3. 到点提交场景。
|
|
4. 回 ACK。
|
|
```
|
|
|
|
局部动作:
|
|
|
|
```text
|
|
POST /api/actions
|
|
```
|
|
|
|
支持结构化动作:
|
|
|
|
```text
|
|
page.next
|
|
page.prev
|
|
energy.mode
|
|
security.alert
|
|
timeline.pause
|
|
timeline.resume
|
|
```
|
|
|
|
## 关键渲染原则
|
|
|
|
所有动画、Three.js、地图和视频都应基于统一时间轴:
|
|
|
|
```js
|
|
const t = serverNowMs() - sceneStartedAtMs;
|
|
renderSceneAt(t);
|
|
```
|
|
|
|
不要让左右服务器各自自由播放:
|
|
|
|
```js
|
|
// 不推荐
|
|
animation += localDeltaTime;
|
|
```
|
|
|
|
这样即使某台机器偶尔慢一帧,也会在下一帧追到统一时间,不会越播越偏。
|
|
|
|
## 为什么不推荐单机渲染后网络分发
|
|
|
|
单侧半屏未压缩数据量:
|
|
|
|
```text
|
|
7440 x 3510 x 4 bytes x 60fps ~= 6.3 GB/s
|
|
```
|
|
|
|
左右两侧合计超过 `12 GB/s`。普通网络视频流需要编码、传输、解码,会带来延迟、画质损失、文字细线压缩失真,以及新的编码/解码同步问题。
|
|
|
|
## 生产验收指标
|
|
|
|
建议关注 P95/P99,而不是平均值:
|
|
|
|
```text
|
|
60 FPS:
|
|
P95 frame time < 16.67ms
|
|
P99 frame time < 20ms
|
|
|
|
30 FPS:
|
|
P95 frame time < 33.33ms
|
|
P99 frame time < 40ms
|
|
```
|
|
|
|
同步指标:
|
|
|
|
```text
|
|
WebSocket RTT < 10ms
|
|
clock offset < 5ms
|
|
left/right 都返回 committed 或 action_committed
|
|
不得频繁出现 late ACK
|
|
```
|
|
|
|
硬件建议:
|
|
|
|
- 两台输出服务器尽量使用同型号 GPU、同驱动、同浏览器版本。
|
|
- 电源策略设置为高性能。
|
|
- 关闭系统休眠、屏保、自动更新弹窗。
|
|
- 拼控侧开启输入缓存、帧同步或延迟对齐能力。
|
|
- 生产环境使用 PTP 或内网 NTP。
|
|
|
|
## 边界
|
|
|
|
能保证:
|
|
|
|
- 两边业务状态一致。
|
|
- 两边按同一服务端时间点提交。
|
|
- 动画长期不漂移。
|
|
- 命令和性能可观测。
|
|
|
|
不能单独保证:
|
|
|
|
- 两张不同 GPU 每一帧物理扫描完全同相。
|
|
|
|
如果必须达到广播级帧同步,需要硬件层支持 Genlock / Frame Lock / 专业视频墙控制器。
|