NestJS如何直接上传文件到DropBox 解决高并发下临时存储崩溃问题
NestJS 文件上传到 DropBox 优化方案
你当前的流程最大的问题是多了三次不必要的本地磁盘IO操作(写临时文件、读临时文件、删临时文件),高并发下磁盘IO很容易成为瓶颈,而且如果进程意外中断,临时文件没有及时清理,长期下来会占满磁盘空间,确实有并发上来之后服务崩溃的风险。以下是可落地的优化方案:
1. 直接流式上传,跳过本地临时存储(优先推荐)
完全抛弃本地临时文件写入逻辑,直接用内存中转文件流,省掉所有磁盘IO开销,100并发场景下完全够用:
- 配置multer使用
memoryStorage,文件上传后直接以Buffer形式存在内存中,不需要写入磁盘 - 拿到文件Buffer后直接调用DropBox SDK的上传接口,全程不操作本地文件
- 示例配置代码:
import { multer } from '@nestjs/platform-express'; const multerUploadConfig = { storage: multer.memoryStorage(), limits: { fileSize: 20 * 1024 * 1024, // 单文件大小上限,按需调整,这里是20MB files: 1 // 单请求最多上传文件数 }, fileFilter: (req, file, cb) => { // 在这里加文件类型校验,只允许合法后缀的文件上传,避免恶意资源占用 const allowedMimeTypes = ['image/jpeg', 'image/png', 'application/pdf']; if (allowedMimeTypes.includes(file.mimetype)) { cb(null, true); } else { cb(new Error('不支持的文件类型'), false); } } }
- 路由中使用:在
@UseInterceptors(FileInterceptor('file', multerUploadConfig))装饰器中传入上面的配置即可,上传逻辑里直接取file.buffer传给DropBox上传方法 - 如果经常需要上传100MB以上的大文件,可以配合DropBox的分片上传接口,把Buffer切片后逐片上传,进一步降低内存占用
2. 引入消息队列削峰,应对更高并发
如果单实例并发超过200,或者文件普遍偏大,内存压力较高时可以用该方案:
- 引入轻量消息队列(如Redis队列、RabbitMQ),用户上传文件到服务后,先把上传任务写入队列,立刻给用户返回上传中状态
- 启动独立的消费者进程消费队列任务,异步执行上传到DropBox、后续业务逻辑处理的操作,处理完成后再通过站内信、回调等方式通知用户结果
- 该方案完全把用户请求和上传耗时逻辑解耦,就算同时上千人上传也不会压垮主服务,注意要开启队列持久化,避免服务重启时任务丢失
3. 前端直传DropBox,彻底释放后端压力
如果业务逻辑允许的话该方案是性能天花板:
- 前端先请求后端接口,后端调用DropBox接口生成带过期时间的预签名上传地址返回给前端
- 前端直接用这个地址把文件上传到DropBox,上传完成后再调用后端接口做业务数据落库等收尾操作
- 整个流程后端完全不需要接触文件流,没有任何IO、内存开销,并发能力只取决于你接口的QPS上限,几千并发都能扛
- 注意要给预签名地址设置合理的过期时间,避免被恶意滥用
额外兜底优化
如果暂时不改现有流程,也可以加这几个配置降低崩溃风险:
- 限制单用户上传频率,避免恶意刷接口占满资源
- 加定时脚本,定期清理临时目录中超过1小时的残留文件,避免磁盘占满
- 给multer加上文件大小、文件数量、请求频率限制,避免异常请求打垮服务
内容的提问来源于stack exchange,提问作者Mateusz Świątek
相关产品推荐
相关产品推荐

