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