分布式文件系统
什么是分布式文件系统
一个计算机无法存储海量的文件,通过网络将若干计算机组织起来共同去存储海量的文件,去接收海量用户的请求,这些组织起来的计算机通过网络进行通信,如下图:
好处:
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();@Testpublic 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进行预览
删除文件
然后我们来进行文件删除测试
//删除文件@Testpublic void test_delete() throws Exception{//删除参数构建RemoveObjectArgs testbucket1 = RemoveObjectArgs.builder().bucket("testbucket").object("1.mp4").build();//上传文件minioClient.removeObject(testbucket1);}
查询文件
查询文件的意思就是下载文件
//查询文件@Testpublic void test_getFile() throws Exception{//根据扩展名取出mimeTypeContentInfo 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>
//根据扩展名取出mimeTypeContentInfo extensionMatch = ContentInfoUtil.findExtensionMatch(".mp4");String mimeType = MediaType.APPLICATION_OCTET_STREAM_VALUE;//通用mimeType,字节流
那么我们就可以修改上传文件的代码来试一下
public void test_upload() throws Exception{//根据扩展名取出mimeTypeContentInfo 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);}