AWS环境下Node.js上传视频转MP4存S3实现方案咨询
问题背景
- 现有基于Node.js开发的PUT类型接口
/api/uploadS3,可接收视频文件与AWS S3目标URL,调用后会将文件上传至对应S3地址。 - 因不同浏览器录制生成的视频格式存在差异,用户上传的视频格式不统一,需要将所有上传视频统一转换为mp4格式后再存储到S3,现需寻找最优实现方案。
- 当前梳理了两种候选方案,存在对应疑问,同时接受其他更优实现思路。
- 备注:Node API接收到的S3路径对每个用户都是唯一的。
候选方案1:Node服务端本地使用ffmpeg完成转码
已知问题:ffmpeg同一时间仅能执行单个转码操作,当前只有一台服务器,若采用该方案需要为多并发请求实现队列机制,会导致队列末尾的用户等待时间过长。
核心疑问:视频转码任务运行期间会对Node服务的正常流量处理能力造成什么影响?其他请求发送到服务器时,RAM、CPU占用率以及其他请求的处理速度会受到怎样的冲击?
候选方案2:采用AWS Lambda函数实现转码
方案思路:为降低Node服务端负载,先由Node接口将用户上传的原格式文件上传至S3,上传完成后触发Lambda函数,由Lambda读取对应S3文件,通过ffmpeg或AWS MediaConvert将其转换为.mp4格式,转换完成后将mp4文件上传到指定S3路径。
硬性要求:
- 转码后的输出路径必须是Node接口最初接收到的目标S3路径,不能使用任意临时路径
- 业务要求用户端需要等待全流程执行完成,接口需要根据上传全流程的成功/失败状态返回结果,供前端启用对应UI功能
核心疑问: - 是否可以仅通过
/api/uploadS3单个接口实现「上传至S3→触发Lambda→文件转码→上传mp4版本文件→返回成功/错误响应」的全链路流程? - 当前流程中文件上传到S3后请求就会直接结束,是否有方式可以延迟API响应,直到所有操作全部执行完成后再返回结果?
- Lambda函数要如何获取最初传递给Node API的输出S3存储桶路径?
回答
方案1(服务端本地ffmpeg转码)的实际表现
首先纠正一个误区:ffmpeg本身支持多进程并行转码,不存在只能同时跑单个任务的限制,但单机跑转码对API服务的冲击非常明显,不建议和业务API服务部署在同一台机器上:
- CPU影响:视频转码是纯CPU密集型任务,只要转码进程启动,默认会抢占所有可用CPU资源。如果和Node服务混跑,CPU占用打满后Node的事件循环会直接卡顿,原本毫秒级响应的普通接口,会出现数秒甚至数十秒的延迟,高并发下很容易触发超时雪崩。哪怕手动给ffmpeg进程调低系统调度优先级,只要转码任务堆积,CPU资源还是会被持续占满。
- 内存影响:转码的内存占用和视频分辨率、时长、码率直接相关,常规1080P、5分钟时长的视频转码,通常会占用1GB左右内存,同时跑2-3个转码任务就可能把服务器内存打满,触发系统交换分区后整个服务会卡到几乎不可用。
- 队列等待是硬伤:单机性能存在明确天花板,只要上传并发上来,排在队列尾部的用户等待数分钟是常事,体验非常差。除非是日活极低、每天只有数十次以内上传请求的场景,否则不推荐该方案。
方案2(Lambda转码)的落地方法
你的所有疑问都有非常直接的落地解法,这个方案也是目前中小规模视频上传场景的最优选择之一:
- 单接口全链路同步响应完全可以实现:不要使用S3上传事件自动触发Lambda,改成Node接口把原始视频先上传到S3的临时存储前缀后,主动以同步模式调用Lambda,此时Node服务会保持连接等待,直到Lambda执行完「读取原始文件→转码为mp4→上传到目标S3路径→校验文件完整性」全流程后,拿到Lambda返回的成功/失败状态,再给前端返回对应响应,完全可以做到所有操作完成后再结束请求,不会出现传完原始文件就提前返回的问题。
- Lambda获取目标S3路径没有额外成本:你主动调用Lambda时,直接把「原始临时文件的S3地址」「最终要求的目标S3地址」作为入参传给Lambda的事件对象即可,Lambda执行时直接从入参读取路径,不需要额外对接数据库或者做路径映射。
- 落地时注意几个避坑点:
- 原始文件不要直接上传到最终目标路径,单独划分一个临时存储前缀,转码成功并校验目标文件合法后,直接删除临时原始文件,避免产生冗余存储费用
- 转码工具按需选择:10分钟以内的短视频场景,直接打包ffmpeg作为Lambda层使用即可,Lambda内存配置到2GB左右时,CPU和网络性能足够支撑快速转码;10分钟以上的长视频场景,直接在Lambda内调用MediaConvert服务处理转码,不需要自己处理编码兼容问题,稳定性更高
- Lambda同步调用的最长超时时间是15分钟,如果你的业务都是用户录制的短视频(通常在5分钟以内)完全够用;如果存在超过15分钟的长视频场景,改成异步任务模式即可:接口收到请求后生成唯一任务ID,转码完成后更新任务状态,前端轮询任务状态接口获取结果。
补充可选方案
如果对转码延迟稳定性要求较高,也可以选择服务拆分方案:单独采购一台低配服务器专门跑转码任务,和运行业务API的服务器物理隔离。Node接口收到上传请求后,把转码任务投递到转码服务器的任务队列中,等待转码结果返回后再响应前端。该方案成本略高于Lambda,但不会遇到Lambda冷启动问题,性能可控性更强。
内容的提问来源于stack exchange,提问作者Gurmeet Singh
相关产品推荐
相关产品推荐

