不能直接用os.readfile+write分发短视频,因会一次性加载整个视频到内存导致oom;200mb文件10并发即占2gb内存,且首帧延迟高、不支持range请求、慢客户端易阻塞goroutine;正确做法是流式打开、分块透传、连接级超时控制,并使用http.newresponsecontroller设写入截止时间。
为什么不能直接用 os.readfile + write 分发短视频
会立刻 oom,尤其在并发稍高时。一个 200mb 的 mp4,10 个连接就吃掉 2gb 内存;更糟的是,os.readfile 必须等整个文件读完才开始响应,首帧延迟不可控,且完全不支持拖拽(range 请求)、无法应对慢客户端——tcp 缓冲区一满,write 就阻塞,整个 goroutine 卡死,后续请求排队。
正确路径是流式打开 + 分块透传 + 连接级超时控制。关键不是“要不要常驻”,而是“怎么让常驻不崩”。
http.NewResponseController 必须用,且要设写入截止时间
Go 1.22+ 提供的 http.NewResponseController 是视频分发的生命线。不用它,你就只能靠运气扛住卡顿连接。
-
rc.SetWriteDeadline(time.Now().Add(30 * time.Second)):防止单个慢连接无限占着 goroutine -
rc.Conn().SetReadDeadline(...):防止客户端突然断连或不读,服务端缓冲持续堆积 - 别手动封装
bufio.Writer或 chunked 逻辑——io.Copy(w, f)底层已按 32KB 自动分块,且受 deadline 约束
常驻进程下必须隔离 buffer、复用连接、限 idle 时间
裸跑常驻进程比短生命周期还危险:fd 耗尽、goroutine 泄漏、日志阻塞、ticker 不停打点,上线即雪崩。
-
ReadTimeout/WriteTimeout建议 ≤30s;IdleTimeout设为 90s 左右,配合KeepAlivePeriod - 所有流逻辑必须包裹
context.WithTimeout(ctx, 60*time.Second),禁止无约束循环 - 视频分片 buffer 用
sync.Pool复用,比如pool.Get().([]byte),切忌每次make([]byte, 1
元数据热更新不能靠重启,得用 sync.Map + fsnotify
短剧/短视频业务变更极快:新剧上线、CDN 切换、权限下架,硬重启会导致播放中断、监控断点、用户投诉。
元数据(如 video_id → oss_path 映射)必须走 sync.Map 存储,监听配置文件变化用 fsnotify,加载失败要 fallback 到旧版本;路由层替换 http.ServeMux 为原子可替换的自定义 http.Handler,所有配置变更通过 atomic.Value 安全读取。
最容易被忽略的是 buffer 复用粒度和超时嵌套层级——一个 io.Copy 外面包了 context,里面又调用了带 timeout 的 HTTP client,deadline 可能互相覆盖,最终形同虚设。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











