一、分布式文件系统
随着业务继续发展,单台服务器存储和响应也很快到达了瓶颈,新的业务需要文件访问具有高响应性、高可用性来支持系统
优点:
- 扩展能力:扩展能力是一个分布式文件系统最重要的特点
- 高可用性:在分布式文件系统中,高可用性包含两层,一是整个文件系统的可用性,二是数据的完整和一致性
- 弹性存储:可以根据业务需要灵活地增加或缩减数据存储以及增删存储池中的资源,而不需要中断系统运行
缺点:
- 系统复杂度较高,需要更多服务器
二、FastDFS 简介以及传输机制
介绍:
- FastDFS是一个开源的轻量级分布式文件系统
- 解决了大数据量存储和负载均衡等问题
- 特别适合以中小文件(4KB < size <500MB)为载体的在线服务
特性:
- 文件不分块存储,上传的文件和OS文件系统中的文件一一对应
- 支持相同内容的文件只保存一份,节约磁盘空间
- 下载文件支持HTTP协议,可以使用内置Web Server,也可以和其他Web Server配合使用
- 在线扩容、主从文件,非常适合存在关联关系的图片
角色:
- 跟踪服务器 (Tracker Server)
- 存储服务器 (Storage Server)
- 客户端 (Client)
传输机制:
(1)上传机制:
- Tracker定时询问Storage状态
- 客户端请求Tracker上传连接请求
- Tracker查询可用Storage可用状态
- Tracker返回存储服务器的ip地址和端口
- 客户端根据返回的 IP 地址和端口号请求上传文件
- 存储服务器接收到请求后生产文件
- 并且将文件内容写入磁盘并返回给客户端file_id、路径信息、文件名等信息
- 客户端保存相关信息上传完毕
(2)下载机制
- Tracker定时询问Storage状态
- Client携带文件名向Tracker发送下载连接请求
- Tracker查询可用相关Storage可用与否
- Tracker返回Client Storage的 ip 以及端口
- Client重新向Storage请求下载,此时携带(file_id 、 组名 、 路径 、 文件名)
- Storage查找文件,将文件以流的形式响应给Client
三、下载安装以及指令
1. docker安装
#默认端口
#tracker 22122
#storage 23000
3#nginx 8888
#查找以及拉取镜像
docker search fastdfs
docker pull delron/fastdfs
# 创建文件夹
mkdir -p /usr/local/fastdfs/my_data/tracker
mkdir -p /usr/local/fastdfs/my_data/storage
# 创建tracker 容器
docker run -d --name tracker --network=host -p 22122:22122 -v /usr/local/fastdfs/my_data/tracker:/var/fdfs delron/fastdfs tracker
# 注意:tracker服务默认的端口为22122
#创建tracker 容器
docker run -d --name storage --network=host -e TRACKER_SERVER=8.130.19.210:22122 -v /usr/local/fastdfs/my_data/storage:/var/fdfs -e GROUP_NAME=group1 delron/fastdfs storage
此时进入storge的配置文件,查看nginx的端口设置
#将数据卷挂载的目录存放文件,使用如下命令
/usr/bin/fdfs_upload_file /etc/fdfs/client.conf 2.jpg
#验证是否返回group1/M00/00/00/rBsbdmPp_ECAAr44AAHzR5e1M08279.jpg
#在浏览器运行http://ip:port/group1/M00/00/00/rBsbdmPp_ECAAr44AAHzR5e1M08279.jpg即可
#注意: 运行命令的时候这里的 1.jpg是相对路径
2. 文件指令
#上传指令
/usr/bin/fdfs_upload_file /etc/fdfs/client.conf 1.jpg
#下载指令
/usr/bin/fdfs_download_file /etc/fdfs/client.conf group1/M00/00/00/rBsbdmPp-qKAKUnOAAHzR5e1M08289.jpg
#查询文件信息
fdfs_file_info /etc/fdfs/client.conf group1/M00/00/00/rBsbdmPp-qKAKUnOAAHzR5e1M08289.jpg
#删除文件
fdfs_delete_file /etc/fdfs/client.conf group1/M00/00/00/rBsbdmPp-qKAKUnOAAHzR5e1M08289.jpg
四、SpringBoot操作FastDFS
1. 引入标记
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
<version>1.26.5</version>
</dependency>
2. 添加配置
fdfs:
# 连接时间
so-timeout: 1500
# 超时时间
connect-timeout: 600
thumb-image: #缩略图生成参数
width: 150
height: 150
tracker-list: #TrackerList参数,支持多个
- 8.130.19.210:22122
4. 主类
//获取带有连接池的FastDFS Java客户端
@Import(FdfsClientConfig.class)
// 解决jmx重复注册bean的问题
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
4. 测试类验证
package com.zbzzs.fastdfs;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@SpringBootTest
class FastDfsApplicationTests {
@Autowired
private FastFileStorageClient fastFileStorageClient;
@Test
public void testUpload() throws FileNotFoundException {
//获取本地文件
File file = new File("D:\\文件列表\\文件\\1 (2).jpg");
//创建传输文件的输入流
FileInputStream fileInputStream = new FileInputStream(file);
//文件上传:
// 参数一:传输文件内容的输入流;
// 参数二:文件的size;
// 参数三:文件扩展名;
// 参数四:描述文件的元数据;
// 返回值:上传文件在存储节点的唯一标识(卷名+文件名)
StorePath storePath = fastFileStorageClient.uploadFile(fileInputStream, file.length(), "jpg", null);
//将卷名与文件名一起打印
System.out.println(storePath.getFullPath());
//将卷名与文件名分别打印
System.out.println(storePath.getGroup()+" | "+storePath.getPath());
// 结果
// group1/M00/00/00/rBsbdmPqKXyAfRoYAAH66g2Ew-8091.jpg
// group1 | M00/00/00/rBsbdmPqKXyAfRoYAAH66g2Ew-8091.jpg
}
/**
* 测试springboot环境下的javaAPI对分布式文件系统的下载文件的操作
* @throws IOException
*/
@Test
public void testDownload() throws IOException {
// 下载文件:
// 参数一:文件处于存储节点的卷名;
// 参数二:文件在存储节点的文件名;
// 参数三:下载的回调函数;
// 返回值:文件内容的字节数组
byte[] bytes = fastFileStorageClient.downloadFile(
"group1",
"M00/00/00/rBsbdmPqKXyAfRoYAAH66g2Ew-8091.jpg",
new DownloadByteArray()
);
//创建文件输出流,指定输出位置及文件名
FileOutputStream fileOutputStream = new FileOutputStream("d:\\桌面\\12.jpg");
//使用文件输出流将文件内容字节数组写出
fileOutputStream.write(bytes);
//刷新输出流
fileOutputStream.flush();
//关闭输出流
fileOutputStream.close();
}
}
5. 富文本编辑器
[富文本编辑器帮助](快速开始 | wangEditor)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
</head>
<body>
<div id="div1">
<p>欢迎使用 <b>wangEditor</b> zbzzs</p>
</div>
<script type="text/javascript"
src="https://cdn.jsdelivr.net/npm/wangeditor@latest/dist/wangEditor.min.js">
</script>
<script type="text/javascript">
const E = window.wangEditor
const editor = new E('#div1')
//设置文件上传的参数名称
editor.config.uploadFileName = 'files'
// 配置 server 接口地址
editor.config.uploadImgServer = '/upload.do'
// 2M
editor.config.uploadImgMaxSize = 2 * 1024 * 1024
editor.config.uploadImgAccept = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']
// 一次最多上传 5 个图片
editor.config.uploadImgMaxLength = 5
editor.create()
</script>
</body>
</html>
@Controller
public class UoloadToFastDFSController {
//fastdfs存储节点的客户端对象
@Autowired
private FastFileStorageClient fastFileStorageClient;
@PostMapping("/upload.do")
public void uploadMoreImage(MultipartFile[] files){
//判断是否上传图片
if(files != null && files.length != 0 ){
//遍历上传图片
for (MultipartFile multipartFile : files) {
String filename = multipartFile.getOriginalFilename();
String fileSuffix = filename.substring(filename.lastIndexOf(".") + 1);
StorePath storePath = null;
try {
//上传文件
storePath = fastFileStorageClient.uploadFile(multipartFile.getInputStream(), multipartFile.getSize(), fileSuffix, null);
} catch (IOException e) {
e.printStackTrace();
}
//打印返回的文件在存储节点的唯一标识
System.out.println(storePath.getFullPath());
// 进行jdbc操作,将信息存储
}
}
}
}