微服务架构|怎样解决超大附件分片上传?(代码片段)

码农架构 码农架构     2023-03-07     514

关键词:

导读:分片上传、断点续传,这两个名词对于做过或者熟悉文件上传的朋友来说应该不会陌生,总结本篇文章希望对从事相关工作的同学能够有所帮助或者启发。     

当我们的文件特别大的时候,上传是不是需要很长的时间啊,这么长时间的长连接,如果网络波动了呢?中间网络断开了呢?在这么长时间的过程中如果出现不稳定的情况,本次上传的所有内容就全部失败了,又要重新上传。

分片上传,就是将所要上传的文件,按照一定的大小,将整个文件分隔成多个数据块(我们称之为 Part)来进行分别上传,上传完之后再由服务端对所有上传的文件进行汇总整合成原始的文件。分片上传不仅可以避免因网络环境不好导致的一直需要从文件起始位置还是上传的问题,还能使用多线程对不同分块数据进行并发发送,提高发送效率,降低发送时间。

一、背景


在系统用户量突增以后,为了更好适配各群体的定制化需求。业务上慢慢实现了支持 C 端用户自定义布局和配置,导致配置数据读取 IO 激增。

为了更好优化此类场景,将用户自定义配置静态化管理!也就是将对应的配置文件生成静态文件,在生成静态文件的过程中遇到棘手的问题,配置文件文件过大导致在文件上传服务器等待时间过长,致使整个业务场景性能整体下滑。

二、生成配置文件


生成文件三大要素

  • 文件名

  • 文件内容

  • 文件存储格式

文件内容、文件存储格式都好理解和处理,当然先前整理过微服务中常用的加密方式

这里做下补充说明,如果要想对文件内容进行加密可以考虑。但是本文的案例场景对于配置信息保密程度较低,这里不做拓展。

而对于文件名的命名规范具体结合业务场景来定,通常都是以文件概要+时间戳格式为主。但是这类命名规范容易导致文件名冲突,造成没有必要的后续麻烦。

所以我这里对于文件名的命名做了特殊处理,有处理过前端 Route 路由经验的应该能联想到,文件名可以通过基于内容生成 Hash 值来代替。

Spring 3.0 之后提供了计算摘要的的方法。

DigestUtils#md

复制代码

返回给定字节的 MD5 摘要的十六进制字符串表示形式。

md5DigestAsHex 源码

/**
 * 计算摘要的字节
 * @param  一个十六进制摘要字符
 * @return 串返回给定字节的 MD5 摘要的十六进制字符串表示形式。
 */
public static String md5DigestAsHex(byte[] bytes) 
  return digestAsHexString(MD5_ALGORITHM_NAME, bytes);

文件名、内容、后缀(存储格式)确定后直接生成文件

/**
  * 直接根据内容生成 文件
  */
public static void generateFile(String destDirPath, String fileName, String content) throws FileZipException 
    File targetFile = new File(destDirPath + File.separator + fileName);
      //确保父级目录存在
      if (!targetFile.getParentFile().exists()) 
        if (!targetFile.getParentFile().mkdirs()) 
          throw new FileZipException(" path is not found ");
        
      
    //设置文件编码格式
    try (PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(targetFile), ENCODING)))
        ) 
      writer.write(content);
      return;
     catch (Exception e) 
      throw new FileZipException("create file error",e);
    

通过内容生成文件优点不言而喻,可以极大减少我们主动基于内容比较来生成新的文件、如果文件内容较大生成对应的文件名相同则表示内容未做任何调整,此时我们也就不用做后续的文件更新操作。

三、分片上传附件


所谓的分片上传,就是将所要上传的文件,按照一定的大小,将整个文件分隔成多个数据块(我们称之为 Part)来进行分别上传,上传完之后再由服务端对所有上传的文件进行汇总整合成原始的文件。分片上传不仅可以避免因网络环境不好导致的一直需要从文件起始位置还是上传的问题,还能使用多线程对不同分块数据进行并发发送,提高发送效率,降低发送时间。

分片上传主要适用于以下几种场景:

  • 网络环境不好:当出现上传失败的时候,可以对失败的 Part 进行独立的重试,而不需要重新上传其他的 Part。

  • 断点续传:中途暂停之后,可以从上次上传完成的 Part 的位置继续上传。

  • 加速上传:要上传到 OSS 的本地文件很大的时候,可以并行上传多个 Part 以加快上传。

  • 流式上传:可以在需要上传的文件大小还不确定的情况下开始上传。这种场景在视频监控等行业应用中比较常见。

  • 文件较大:一般文件比较大时,默认情况下一般都会采用分片上传。

分片上传的整个流程大致如下:

  • 将需要上传的文件按照一定的分割规则,分割成相同大小的数据块;

  • 初始化一个分片上传任务,返回本次分片上传唯一标识;

  • 按照一定的策略(串行或并行)发送各个分片数据块;

  • 发送完成后,服务端根据判断数据上传是否完整,如果完整,则进行数据块合成得到原始文件

▐ 定义分片规则大小

默认情况都以文件达到 20MB 进行强制分片

/**
 * 强制分片文件大小(20MB)
 */
long FORCE_SLICE_FILE_SIZE = 20L* 1024 * 1024;

为了方便调试,强制分片文件的阈值调整为 1KB

▐ 定义分片上传对象

如上图红色序号的文件碎片,定义分片上传对象基础属性包含附件文件名、原始文件大小、原始文件 MD5 值、分片总数、每个分片大小、当前分片大小、当前分片序号等

定义基础属于便于后续对文件合理分割、分片的合并等业务拓展,当然根据业务场景可以定义拓展属性。

分片总数

long totalSlices = fileSize % forceSliceSize == 0 ? 
    fileSize / forceSliceSize : fileSize / forceSliceSize + 1;

每个分片大小

long eachSize = fileSize % totalSlices == 0 ? 
    fileSize / totalSlices : fileSize / totalSlices + 1;

原始文件的 MD5 值

MD5Util.hex(file)

复制代码

如:

当前附件大小为:3382KB,强制分片大小限制为 1024KB

通过上述计算:分片数量为 4 个每个分片大小为 846KB

▐ 读取每个分片的数据字节

标记当前字节下标,循环读取 4 个分片的数据字节

try (InputStream inputStream = new FileInputStream(uploadVO.getFile())) 
    for (int i = 0; i < sliceBytesVO.getFdTotalSlices(); i++) 
        // 读取每个分片的数据字节
        this.readSliceBytes(i, inputStream, sliceBytesVO);
      // 调用分片上传API的函数
        String result = sliceApiCallFunction.apply(sliceBytesVO);
        if (StringUtils.isEmpty(result)) 
            continue;
        
        return result;
    
 catch (IOException e) 
    throw e;

三、总结


所谓的分片上传,就是将所要上传的文件,按照一定的大小,将整个文件分隔成多个数据块(我们称之为 Part)来进行分别上传。

处理大文件进行分片主要核心确定三大点

  • 文件分片粒度大小

  • 分片如何读取

  • 分片如何存储

本篇文章主要分析和处理大文件上传过程中如何针对大文件文件文件内容比较、进行分片处理。合理设置分片阈值以及如何读取和标记分片。希望对从事相关工作的同学能够有所帮助或者启发。后续会对分片如何存储、标记、合并文件进行详细解读。

原文:微服务架构 | 怎样解决超大附件分片上传?

vue超大文件上传解决方案:分片断点上传

...面接收完毕后合并文件的思路。实现文件夹上传,要求:服务端保留层级结构,支持10w级别的文件夹上传。大文件上传及断点续传,要求:支持50G级的单个文件上传和续传。续传要求:在刷新浏览器后能够续传上传,在重启浏览... 查看详情

如何解决控件附件上传时超大附件无法上传的问题

...型的值,所以我们在用QueryString取的时候的值为Null。 解决:打开Portal->Ajax->FileUploadHandler.ashx文件里,找到以下代码: 查看详情

如何解决控件附件上传时超大附件无法上传的问题

...型的值,所以我们在用QueryString取的时候的值为Null。 解决:打开Portal->Ajax->FileUploadHandler.ashx文件里,找到以下代码: 查看详情

邮件发送超大附件,上传下载特别慢,怎么解决?

目前,已有不少邮箱如QQ邮箱、网易邮箱等支持超大附件,可以发送2G或3G大小的文件。但是诸多邮箱发送超大附件普遍存在以下问题:首先,邮件发送大文件对文件大小有限制,超过上限的超大附件无法发送;其次,超大附件上... 查看详情

自建exchange邮箱怎么发送超大附件?

...的问题:公司自建exchange邮箱,但是大附件如果存到邮件服务器里对服务器负担会比较大,也并没有找到其他靠谱的方法,怎么破?其实,公司內部使用的邮件系统,如果有超大附件的需求,可私有化部署邮件服务器或选择商业S... 查看详情

通过邮件发送超大附件的3种方法介绍

...使压缩了,也还是很大,还是发送不了。3、选择第三方服务商。如果一些常规的方式无法解决超大附件发送问题的话,不妨试试第三方服务啊,比如《Ftrans邮件超大附件解决方案》,可完美解决通过邮件发送超大附件的问题,... 查看详情

第04章分布式索引架构(代码片段)

本章内容如何为集群选择合适的分片数和副本数。路由是什么以及它对ElasticSearch的意义。分片分配器是怎样工作的,如何配置它。怎样调节分片分配机制以满足应用需求。怎样确定应该在哪个分片上执行指定的操作。怎样结合... 查看详情

java分片上传全解决方案,真香(代码片段)

...果网络波动就前功尽弃了,今天就来复述下这个方案1、解决方案我们的方案是第一步需要创建转写任务,返回给前段一个taskId。第二步就是分片上传语音,每次只能上传一片语音,并且是顺序上传。在最后一片上传完成后进行... 查看详情

分享:it管理员都喜欢用的outlook超大附件系统

...超大附件有解决方案了吗?我看单纯解除附件大小限制,服务器顶不住啊……”刚帮同事处理好问题,顶头boss就来关照。众所周知为了缓解Exchange服务器压力,Outlook附件大小一般限制在20M。各种打听来、百度来的土方、偏方都... 查看详情

springcloud01:回顾微服务和微服务架构(代码片段)

回顾微服务和微服务架构微服务微服务架构微服务架构技术栈SpringCloud和SpringBoot的关系微服务微服务架构微服务架构的四个核心问题服务很多,客户端怎么访问?这么多服务,服务之间如何通信?这么多服务,... 查看详情

微服务架构|服务之间跨域问题怎么解决?(代码片段)

...的同源策略,可以通过浏览器让不同的网站和不同的服务器之间通信。一、背景当前微服务拆分已经成为趋势,大部分公司都对其软件产品做微服务架构调整。对产品先进行业务、模块拆分,大部分也进行前后端分离... 查看详情

微服务架构下分布式事务解决方案——阿里云gts(代码片段)

https://blog.csdn.net/jiangyu_gts/article/details/79470240  1微服务的发展微服务倡导将复杂的单体应用拆分为若干个功能简单、松耦合的服务,这样可以降低开发难度、增强扩展性、便于敏捷开发。当前被越来越多的开发者推崇,很... 查看详情

初识微服务(技术栈单体分布式架构)springcloud(代码片段)

(目录)微服务技术栈从单体架构过度到微服务架构,需要一系列中间技术支撑,其中重要的部分包括:认识微服务随着互联网行业的发展,对服务的要求也越来越高,服务架构也从单体架构逐渐演变为现在流行的微服务架构。这... 查看详情

超大文件上传和断点续传的源代码

总结一下大文件分片上传和断点续传的问题。因为文件过大(比如1G以上),必须要考虑上传过程网络中断的情况。http的网络请求中本身就已经具备了分片上传功能,当传输的文件比较大时,http协议自动会将文件切片(分块)... 查看详情

java分片上传全解决方案,真香(代码片段)

...网络波动就前功尽弃了,今天就来复述下这个方案1、解决方案我们的方案是第一步需要创建转写任务,返回给前段一个taskId。第二步就是分片上传语音,每次只能上传一片语音,并且 查看详情

微服务架构-解决docker-compose服务编排启动顺序问题(代码片段)

基于DockerCompose进行服务编排时,一定碰到服务启动顺序的问题,例如:B服务启动之前,A服务要已经启动并且可以正常对外服务。这个启动顺序的问题,DockerCompose本身它是无法解决的,即使定义了depends_on或者links,它只能保证... 查看详情

微服务课程_springcloud_01(代码片段)

SpringCloud01点击查看微服务课程点击下载微服务课程资料提取码:12341.认识微服务随着互联网行业的发展,对服务的要求也越来越高,服务架构也从单体架构逐渐演变为现在流行的微服务架构。这些架构之间有怎样的... 查看详情

微服务架构(代码片段)

一、微服务简介微服务架构解决方案二、SpringCloudAlibaba解决方案架构设计三、创建SpringCloud项目1.创建空项目GitCGB2110IVProjects 2.项目初始化配置Maven3.8.4 配置jdk编译环境3.创建工程创建聚合父工程编辑共享资源 删除父工程src目录... 查看详情