Vue3多文件上传只请求一次(调用一次接口)

Element-plus中使用el-upload 组件进行多文件上传时经常会遇到一个问题,接口会调用多次,这样浪费性能且不符合常理,在使用默认的情况下,多个文件上传是多次调用接口。想要多个文件只调用一个接口,就需要替换掉默认的上传方法。

需求:在使用el-upload多文件上传的时候,只请求一次后端接口。思路:

1、要知道 el-upload 组件默认是自动上传,首先要取消自动上传,对应的属性 auto-upload:false;

2、需要在确定上传之前,拿到选中的文件流;(最好是选择文件时候出现一个友好弹框这样点击确定的时候可以拿到选中的文件流)

3、实例化一个FormData()对象,循环拿到的多个文件流,append到FormData中;

4、调用上传接口,把FormData传给后端即可;

代码如下:

html代码

    ref="uploadRef"
        :action="importUrlMore"  //上传接口
        name="file"
        class="model-uploader"
        :show-file-list="false"
        :headers="{ token: getToken() }"  //需要的token
        :data="{ token: getToken() }"
        :on-change="handleChange"   //用change事件获取文件
        accept=".pdf"        //选择文件上传的类型
        :multiple="true"
        :limit="100"     //最多上传100个文件
        :auto-upload="false"  //取消自动上传
      >
        type="success">发票
  

js代码

    let videolist = reactive([]);
    let newList = reactive([]);
    const handleChange = (file, fileList) => {
      videolist = fileList; 
      data.fileList = fileList.map((m) => m.raw);  //我这个文件流是列表里面row字段,可以根据自己的实际情况来
      dialogVisibleOfd.value = true;  //显示弹出框
    };

事件中两个参数分别是当前文件以及选中的多个文件列表,需要考虑到多次文件上传时需要把上一次已经上传的列表清空,所以定义一个变量videolist来接收,上传完成之把这变量赋空

    const ofdsBtnSure = () => {
      const formData = new FormData();  //实例化form对象
      data.fileList.forEach((file) => {
        formData.append('file', file, file.name);   //循环添加到form对象中
      });
      importInvoice(formData).then((response) => {   //调用接口
        if (response.heads && response.heads.code && response.heads.code === 200) {
          ElMessage({
            message: '导入成功',
            type: 'success',
            duration: 3 * 1000
          });
        } else {
          if (response.heads.message) {
            ElMessage({
              message: '导入失败!' + response.heads.message,
              type: 'error',
              duration: 3 * 1000
            });
          }
        }
        videolist.length = 0;   //把已经上传成功的列表清空
        dialogVisibleOfd.value = false;   //关闭弹出框
      });
    };

分布式存储ceph:后端存储ObjectStore

ObjectStore是Ceph OSD中最重要的概念之一,它完成实际的数据存储,封装了所有对底层存储的I/O操作。I/O请求从客户端发出后,最终会使用ObjectStore提供的API进行相应的处理。

ObjectStore也有不同的实现方式,目前主要有FileStore、BlueStore、MemStore、KStore。可以在配置文件中通过osd_objectstore字段来指定ObjectStore的类型。MemStore和元数据主要用于测试,其中MemStore将所有数据全部放在内存中,KStore将元数据与Data全部存放到KVDB中。MemStore和KStore都不具备生产环境的要求。

FileStore

FileStore是基于Linux现有的文件系统,将Object存放在文件系统上的,也就是利用传统的文件系统操作实现ObjectStore API。每个Object会被FileStore看作是一个文件,Object的属性(xattr)会利用文件的属性存取,因为有些文件系统(如ext4)对属性的长度有限制,所以超出长度的属性会作为omap存储。

FileStore目前支持的文件系统有XFS/ext4/Btrfs,推荐使用XFS。FileStore基本没人用这里不多介绍。

BlueStore

FileStore最初只是针对机械盘进行设计的,并没有对固态硬盘的情况进行优化,而且写数据之前先写journal也带来了一倍的写放大。为了解决FileStore存在的问题,Ceph推出了BlueStore。BlueStore去掉了journal,通过直接管理裸设备的方式来减少文件系统的部分开销,并且也对固态硬盘进行了单独的优化。BlueStore架构如下图所示。

BlueStore和传统的文件系统一样,由3个部分组成:数据管理、元数据管理、空间管理(即所谓的Allocator)。与传统文件系统不同的是,数据和元数据可以分开存储在不同的介质中。

BlueStore不再基于ext4/XFS等本地文件系统,而是直接管理裸设备,为此在用户态实现了BlockDevice,使用Linux AIO直接对裸设备进行I/O操作,并实现了Allocator对裸设备进行空间管理。至于元数据则以Key/Value对的形式保存在KV数据库里(默认为RocksDB)。但是RocksDB并不是基于裸设备进行操作的,而是基于文件系统(RocksDB可以将系统相关的处理抽象成Env,BlueStore实现了一个BlueRocksEnv,来为RocksDB提供底层系统的封装)进行操作的,为此BlueStore实现了一个小的文件系统BlueFS,在将BlueFS挂载到系统中的时候将所有的元数据加载到内存中。

1)KVDB

使用KVDB的原因是它可以快速实现ObjectStore的事务的语义。图中使用的是RocksDB,但不表示只能用RocksDB,RocksDB只是目前默认的一种KVDB。只要能提供相应接口的,任何KVDB都可以使用。

RocksDB后端存储必须基于一个文件系统,所以对于RocksDB有两种选择:使用标准Linux文件系统,比如ext4/XFS等;实现一套简单的用户空间文件系统,满足RocksDB的需求。同样基于性能的考虑,Ceph实现了BlueFS,而没有使用XFS/Btrfs。

2)Allocator

由于BlueStore和BlueFS直接操作裸设备,所以和传统文件系统一样,磁盘空间也需要自己来管理。不过这部分并没有创新,都是按照最小单元进行格式化的,使用BitMap来进行分配。

3)BlueFS

BlueFS是专门为RocksDB开发的文件系统,根据RocksDB WAL和SST(Sorted Sequence Table)的不同特性,可以配置两个单独的块设备。BlueFS自己管理裸设备,所以也有自己的Allocator,不同于BlueStore,BlueFS的元数据是作为一个内部特殊的文件进行管理的,这是因为它的文件和目录都不是很大。

4)元数据

和传统文件系统的元数据一样,包含文件的基本信息:name、mtime、size、attributes,以及逻辑和物理块的映射信息,同时包含裸设备的块的分配信息。

ext2/3/4在存放大量小文件时可能会出现元数据空间不够,但是数据空间大量空闲的情况。BlueFS会共享BlueStore的块设备,在其原有空间不够的情况下,会从这个块设备分配空间。用这种方式来解决元数据和数据空间出现不匹配的问题。

5)BlockDevice

在使用BlueFS+RocksDB的情况下最多有3个块设备:Data存放BlueStore数据;WAL存放RocksDB内部journal;DB存放RocksDB SST。

·1个块设备。只有Data设备,BlueStore和BlueFS共享这个设备。

·2个块设备。有2种配置:Data+WAL,RocksDB SST存放在Data上;Data+DB,WAL放在DB上。

·3个块设备。Data+DB+WAL,原则上数据存放在Data上,RocksDB journal存放在WAL上,RocksDB SST存放在DB上。

·空间互借的原则。mkfs时不知道元数据到底有多少,KVDB空间大小也很难确定,所以就会允许当空间出现不足时,可以按照WAL→DB→Data这个原则进行分配。

6)驱动

驱动是指如何读/写块设备,根据不同的设备种类可以选择不同的方式,以获取更高的性能。

·系统调用读/写。

这是最常用的方式,对任何块设备都适用。使用Linux系统调用读/写或aio_submit来访问块设备。

·SPDK。

SPDK是专门为NVMe开发的用户空间驱动,放弃原有系统调用模式,是基于以下两个原因:①NVMe设备的IOps很高,如果按照传统的系统调用,需要先从用户空间进入内核空间,完成后再从内核空间返回用户空间,这些开销对NVMe而言就比较大了;②内核块层是通用的,而作为存储产品这些设备是专用的,不需要传统的I/O调度器。

·PMDK。

PMDK是专门为英特尔AEP设备开发的驱动。AEP可以看成是带电的DRAM,掉电不丢数据。不同于NAND Flash,写之前需要擦除。基本存储单元不是扇区,而是和DRMA一样为Byte。接口不是PCIe,而是和DRAM一样直接插在内存槽上的。目前Kernel已经有驱动,将AEP作为一个块设备使用,也针对AEP的特性,实现了DAX的访问模式(AEP设备不使用Page Cache)。

基于性能的考虑,PMDK专门作为AEP的驱动出现。考虑到AEP存储单元是Byte,所以其将AEP设备mmap,这样就可以直接按字节访问AEP了。由于使用的是DAX技术,所以mmap跳过Page Cache,直接映射到AEP。这样就实现了用户空间直接访问AEP,极大地提高了I/O性能。

SeaStore

SeaStore是下一代的ObjectStore,目前仅仅有一个设计雏形。因为SeaStore基于SeaStar,所以暂时称为SeaStore,但是不排除后面有更合适的名字。SeaStore有以下几个目标。

·专门为NVMe设备设计,而不是PMEM 和硬盘驱动器。

·使用SPDK访问NVMe而不再使用Linux AIO。

·使用SeaStar Future编程模型进行优化,以及使用share-nothing机制避免锁竞争。

·网络驱动使用DPDK来实现零拷贝。

由于Flash设备的特性,重写时必须先要进行擦除操作。垃圾回收擦除时,并不清楚哪些数据有效,哪些数据无效(除非显式调用discard线程),但是文件系统层是知道这一点的。所以Ceph希望将垃圾回收功能可以提到SeaStore来做。SeaStore的设计思路主要有以下几点。

·SeaStore的逻辑段(segment)应该与硬件segment(Flash擦除单位)对齐。

·SeaStar是每个线程一个CPU核,所以将底层按照CPU核进行分段。

·当空间使用率达到设定上限时,就会进行回收。当segment完全回收后,就会调用discard线程通知硬件进行擦除。尽可能保证逻辑段与物理段对齐,避免逻辑段无有效数据,但是底层物理段存在有效数据,那么就会造成额外的读/写操作。同时由discard带来的消耗,需要尽量平滑处理回收工作,减少对正常读/写的影响。

·用一个公用的表管理segment的分配信息,所有元数据用B-Tree进行管理。

本站内容来自用户投稿,如果侵犯了您的权利,请与我们联系删除。联系邮箱:835971066@qq.com

本文链接:http://news.xiuzhanwang.com/post/1094.html

发表评论

评论列表

还没有评论,快来说点什么吧~

友情链接: