分布式文件系统
什么是分布式文件系统
一个计算机无法存储海量的文件,通过网络将若干计算机组织起来共同去存储海量的文件,去接收海量用户的请求,这些组织起来的计算机通过网络进行通信,如下图:

好处:
1、一台计算机的文件系统处理能力扩充到多台计算机同时处理。
2、一台计算机挂了还有另外副本计算机提供数据。
3、每台计算机可以放在不同的地域,这样用户就可以就近访问,提高访问速度。
Minlo
介绍
MinIO构建分布式文件系统,MinIO 是一个非常轻量的服务,可以很简单的和其他应用的结合使用,它兼容亚马逊 S3 云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等。
它一大特点就是轻量,使用简单,功能强大,支持各种平台,单个文件最大5TB,兼容 Amazon S3接口,提供了 Java、Python、GO等多版本SDK支持。
官网:https://min.io
中文:https://www.minio.org.cn/,http://docs.minio.org.cn/docs/
MinIO集群采用去中心化共享架构,每个结点是对等关系,通过Nginx可对MinIO进行负载均衡访问。
去中心化有什么好处?
在大数据领域,通常的设计理念都是无中心和分布式。Minio分布式模式可以帮助你搭建一个高可用的对象存储服务,你可以使用这些存储设备,而不用考虑其真实物理位置。
它将分布在不同服务器上的多块硬盘组成一个对象存储服务。由于硬盘分布在不同的节点上,分布式Minio避免了单点故障。如下图:

Minio使用纠删码技术来保护数据,它是一种恢复丢失和损坏数据的数学算法,它将数据分块冗余的分散存储在各各节点的磁盘上,所有的可用磁盘组成一个集合,上图由8块硬盘组成一个集合,当上传一个文件时会通过纠删码算法计算对文件进行分块存储,除了将文件本身分成4个数据块,还会生成4个校验块,数据块和校验块会分散的存储在这8块硬盘上。
使用纠删码的好处是即便丢失一半数量(N/2)的硬盘,仍然可以恢复数据。 比如上边集合中有4个以内的硬盘损害仍可保证数据恢复,不影响上传和下载,如果多于一半的硬盘坏了则无法恢复。
SDK
上传文件
MinIO提供多个语言版本SDK的支持,下边找到java版本的文档:
地址:https://docs.min.io/docs/java-client-quickstart-guide.html
最低需求Java 1.8或更高版本:
maven依赖如下:
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.4.3</version>
</dependency>
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.8.1</version>
</dependency>
 
参数说明:
需要三个参数才能连接到minio服务。
| 参数 | 说明 | 
|---|---|
| Endpoint | 对象存储服务的URL | 
| Access Key | Access key就像用户ID,可以唯一标识你的账户。 | 
| Secret Key | Secret key是你账户的密码。 | 
然后我们来看官方示例
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.UploadObjectArgs;
import io.minio.errors.MinioException;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
public class FileUploader {
  public static void main(String[] args)throws IOException, NoSuchAlgorithmException, InvalidKeyException {
    try {
      // Create a minioClient with the MinIO server playground, its access key and secret key.
      MinioClient minioClient =
          MinioClient.builder()
              .endpoint("https://play.min.io")
              .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG")
              .build();
      // Make 'asiatrip' bucket if not exist.
      boolean found =
          minioClient.bucketExists(BucketExistsArgs.builder().bucket("asiatrip").build());
      if (!found) {
        // Make a new bucket called 'asiatrip'.
        minioClient.makeBucket(MakeBucketArgs.builder().bucket("asiatrip").build());
      } else {
        System.out.println("Bucket 'asiatrip' already exists.");
      }
      // Upload '/home/user/Photos/asiaphotos.zip' as object name 'asiaphotos-2015.zip' to bucket
      // 'asiatrip'.
      minioClient.uploadObject(
          UploadObjectArgs.builder()
              .bucket("asiatrip")
              .object("asiaphotos-2015.zip")
              .filename("/home/user/Photos/asiaphotos.zip")
              .build());
      System.out.println(
          "'/home/user/Photos/asiaphotos.zip' is successfully uploaded as "
              + "object 'asiaphotos-2015.zip' to bucket 'asiatrip'.");
    } catch (MinioException e) {
      System.out.println("Error occurred: " + e);
      System.out.println("HTTP trace: " + e.httpTrace());
    }
  }
}
 

那么基于这个我们来创建个测试类,测试是否能够上传文件
public class MinioTest {
    MinioClient minioClient =
          MinioClient.builder()
                  .endpoint("http://192.168.101.65:9001")
              .credentials("minioadmin", "minioadmin")
              .build();
    @Test
    public void test_upload() throws Exception{
        //上传参数设置
        UploadObjectArgs testbucket = UploadObjectArgs.builder()
                .bucket("testbucket") //桶
                .filename("F:\\BaiduNetdiskDownload\\2023新版JavaWeb开发教程\\视频\\day01-HTML-CSS\\1.mp4") //指定本地文件路径
                .object("test/01/1.mp4") //存放的文件名 放在子目录下 直接写文件名是放在根目录下
                .build();
        //上传文件
        minioClient.uploadObject(testbucket);
    }
}
 
注意这里我们需要在网页控制台设置桶,并给它改成公共属性




然后我们运行测试样例,看看是否上传到我们的minio中

可以看到已经上传到minio中了,我们可以点击2进行预览
删除文件
然后我们来进行文件删除测试
    //删除文件
    @Test
    public void test_delete() throws Exception{
        //删除参数构建
        RemoveObjectArgs testbucket1 = RemoveObjectArgs.builder()
                .bucket("testbucket")
                .object("1.mp4").build();
        //上传文件
        minioClient.removeObject(testbucket1);
    }
 

查询文件
查询文件的意思就是下载文件
    //查询文件
    @Test
    public void test_getFile() throws Exception{
        //根据扩展名取出mimeType
        ContentInfo extensionMatch = ContentInfoUtil.findExtensionMatch(".mp4");
        String mimeType = MediaType.APPLICATION_OCTET_STREAM_VALUE;//通用mimeType,字节流
        if (extensionMatch!=null){
            mimeType = extensionMatch.getMimeType();
        }
        //查询参数构建
        GetObjectArgs testbucket = GetObjectArgs.builder()
                .bucket("testbucket")
                .object("test/01/1.mp4")
                .build();
        //下载文件 远程流
        FilterInputStream inputStream = minioClient.getObject(testbucket);
        //指定输出流  
        FileOutputStream outputStream = new FileOutputStream(new File("F:\\BaiduNetdiskDownload\\2023新版JavaWeb开发教程\\视频\\day01-HTML-CSS\\2.mp4"));
       //拷贝到输出流
        IoUtils.copy(inputStream,outputStream);
    }
 
这样我们就可以从桶中下载文件下来,然后我们看是否成功

补充-文件校验问题
我们在上传和下载的时候由于分布式文件系统是基于网络传输,万一用户正在处于网络波动状态,造成文件丢包,那么我们怎么判断下载下来的内容和上传上去的内容是否完整
这里没找到以后补充,我没搜索到资料
补充-拿取扩展名
一般情况,我们需要指定媒体文件的类型,那么我们怎么能知道要传什么呢
可以参考这个源码

这里面就有很么枚举类型 例如我传图片

这些东西我们可以根据扩展名得到,所以可以调用工具类
设置contentType可以通过com.j256.simplemagic.ContentType枚举类查看常用的mimeType(媒体类型)
               <!--根据扩展名取mimetype-->
		<dependency>
            <groupId>com.j256.simplemagic</groupId>
            <artifactId>simplemagic</artifactId>
            <version>1.17</version>
        </dependency>
 
        //根据扩展名取出mimeType
        ContentInfo extensionMatch = ContentInfoUtil.findExtensionMatch(".mp4");
        String mimeType = MediaType.APPLICATION_OCTET_STREAM_VALUE;//通用mimeType,字节流
 
那么我们就可以修改上传文件的代码来试一下
    public void test_upload() throws Exception{
        //根据扩展名取出mimeType
        ContentInfo extensionMatch = ContentInfoUtil.findExtensionMatch(".mp4");
        String mimeType = MediaType.APPLICATION_OCTET_STREAM_VALUE;//通用mimeType,字节流
        if (extensionMatch!=null){
            mimeType = extensionMatch.getMimeType();
        }
        //上传参数设置
        UploadObjectArgs testbucket = UploadObjectArgs.builder()
                .bucket("testbucket") //桶
                .filename("F:\\BaiduNetdiskDownload\\2023新版JavaWeb开发教程\\视频\\day01-HTML-CSS\\1.mp4") //指定本地文件路径
                .object("test/01/1.mp4") //存放的文件名 放在子目录下 直接写文件名是放在根目录下
                .contentType(mimeType) //设置文件类型
                .build();
        //上传文件
        minioClient.uploadObject(testbucket);
    }
 




















