Skip to content

后端为FastDFS结合Redis,实现大文件分片上传,断点续传,秒传功能。

Notifications You must be signed in to change notification settings

SennerMing/renew-upload

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

86 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

大文件上传,断点续传,秒传,fastdfs

该项目是对gitee名为令狐大侠老哥的renew_upload项目进行改造的,感谢这位好大哥提供的解决方案。

如果图片看不到了请参考此解决办法

为什么要做这个东西呢?因为没有钱嘛,没钱一定要做嘛!

精神领袖

我们公司的后端存储工具为FastDFS,关于这个存储工具小明百度过,比较适合小文件就类似于抖音小视频的那种,好像有一种说法是5M到500M之间,没仔细阅读过官方文档不是很懂,总之就是不适合大文件的上传。之前我们公司的一些个老哥,写过一个基于此的文件上传接口,在实际应用当中,有些不听话的用户就反馈啦:哎呀,我上传1个G的文件,怎么传着传着莫名其妙的就失败了,而且我再上传,这个小东西都不做上传记录的,还要重新开始,真的是太难用、太浪费时间了!

客户反馈关键词:上传1个G、历史记录,拿着这两个关键词的小明就开始胡思乱想了🤔,上传大文件的时候,不管是网络哇还是前后台处理请求的原因,总是有可能中途断掉,那能不能通过工具将用户上传的大文件切成小块再进行上传哇,这样的话,既能降低莫名其妙上传失败的几率,又能记录用户上传的进度这样的话,就算是上传中途失败了,用户再重新开始上传的时候,也不用从0开始了,还能实现秒传你说喜不喜人。小明想的正美着呢,领导拍了拍小明聪明的大腿说道,对对对,明啊,你这思路不错,那就顺手把实现的前后台技术方案也调研一下吧,这周做个Demo出来。哔哔哔哩?

小明百度的第一条,就是令狐大侠的技术方案,粗略的看了下简介,各方面感觉整挺好,工程抢过来不必自己做,十亿先拿掉五亿,接下来发包,两转三转,四五六七八转,用docker装个redis,改下配置文件就算齐活了。项目跑起来,小明试着上传了几个大文件,感觉中途中断的几率还是蛮高的,管它呢,反正可以交差了。

可是等到了实际要上线的时间,前端的好大哥又说了:明啊,你这个WebUploader就这个前端大文件上传工具啊,它没发集成到我的VUE项目里去哇,小明气的当时差点就要叫出来了,心想:MD,老子刚刚才看到将WebUploader集成到VUE的文章,不就是不愿意费那一点点的事嘛真的是,转脸微笑着对着前端老大哥说:那您说咋整?“再整一个用VUE框架的插件呗”,呵呵呵,好吧好吧都是老大,刚来几天手头活也不是那么多,立马翻出来个Vue-Simple-Uploader给他,其实交互的原理和百度的WebUploader差不多,Vue-Simple-Uploader说是比WebUploader多了支持多线程....然鹅坏就坏在这个支持多线程。

===========2020年11月22日00:46:08,夜深了,🍊晚安不要噩梦===========

原本令狐老大的思路是文件流按照顺序发送的,Vue-Simple-Uploader默认是多个线程同时开启向后端发送,这个就比较麻烦了,没办法,原以为已经交差的小明,还得拿起键盘对令狐老哥的后台接口进行一番改造。

怎么硕呢,我小阿giao认为,这种解决方案真的是不行,虽然是自己写的代码,但是总感觉这种实现大文件上传的方式不怎么对劲儿。俗话说得好,一图胜千言,废话不多说上图:

大体思路

===========2020年11月22日21:22:59,挺冷的,🍊注意保暖早休息===========

暂且想到的遗留问题:

场景1:用户在文件上传中间按下暂停键

后台处理相应文件的对应异步线程还在轮询,应该设置定时器,在一定时间内没有获取不到对应的该上传的文件流,异步线程自动挂起,且要在upload接口中,对应的加上对异步线程的恢复。

场景2:用户想实时获取块上传状态,该场景也可替换为:暂停后恢复对文件的上传(按理说这个是很合理且比较常见的需求,但是我司本次的实现当中,就很奇怪,前端的大佬说,Vue-Simple-Uploader插件不支持获取每个块的上传状态,没有回调接口的预留!晚上静下来想想吧,也有合理之处,异步一股脑的传完了,如果FastDFS能有个Client也支持异步文件无序的写入话,前后台就基本保持“完美同步”了,末了返回一个最终结果,成功返回地址,失败就让用户重试)

分片上传总入口Controller包下面ChunkUpload的upload(),在第一次接收到文件块的时候,会创建一个异步线程,并且这个第一次请求会被阻塞,等待着所有分片写入FastDFS,并将地址返回给前端,本文件的其他分片上传,会继续发送请求,将文件流填入对应的缓存中,也就是MD5_FILEPATH_MAP。所以除了第一个分片,其他的分片请求都是只获得了该请求将文件流放入缓存中的操作状态。

===========2020年11月23日13点18分,刚从宿舍回来对上午进行总结===========

对上面遗留的问题,已经做出了修复,以下是分片上传Spring-Framework-5.2.5.RELEASESE.zip前端发送请求的截图:

中间请求步骤:

中间步骤请求截图

其中upload请求为分片上传调用的接口,其他请求请无视。如果前端暂停上传,则反馈的结果是"Uploading suspend..."

最后一次请求:

大文件上传请求截图

最后一次上传成功后,则反馈的结果中包含viewPath也就是上传到FastDFS的地址。

解决方案:

和遗留问题场景1中所想的思路很像,先从task包下的TaskExecutor(处理入FastDFS的异步线程类)入手,在每次循环中,获得当前需要上传的文件流处做判断,如果获取不到文件流则,则开始开始计时并判断是否从计时开始到此刻为止,有没有超过设置的超时时间,如果超时则MD5_FILEPATH_MAP.remove(fileMd5),详细的思路请看代码行号:239

================2020年11月23日20点54分,下午可把我搞死了===============

遇到了Future.get()会阻塞线程的问题,沙雕了,自己一步一步排查出来的耗时超长,基本上占据了整个下午的时间,程序中同时还隐藏了一个问题就是文件追加offset写错了,导致根据地址下载的文件大小超级小,还以为是将文件写入tmp目录出现问题了呢,还好晚上加班把这个问题解决了。在公司内网上传1.6G的文件没到一分钟,啪的一下就传好了,hin快啊!棒棒哒o( ̄▽ ̄)ブ,还有灿哥说要把代码整理好,周四说是要讲给大家听,真蛋疼。

遗留问题:

没有加上已上传块的校验,如果已经上传过,则将已经上传的块返回给前端,需要前端配合上传之前要调用check接口。

删除临时文件功能(代码已加但是并没有验证)

关于分布式部署的问题,估计到时候要按IP来进行分辨文件啦。

=================2020年11月24日18点10分,存在重大的问题================

对上传文件流的处理,现在的版本没有加入线程池,加入线程池会出现很大问题,并且现在程序同样存在隐患,就是没有对非第一次上传,任何importSeq接口中对md5_asyncresult_map的操作都存在风险。

=================2020年11月24日20点43分,伪解决================

控制线程池的线程数只有一个,还特么不如写个函数,在接收文件的时候用逻辑判断是否去执行,暂停,续传问题在1个线程的情况下实现了,哎,留下了没有技术含量的眼泪!

About

后端为FastDFS结合Redis,实现大文件分片上传,断点续传,秒传功能。

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published