一、什么是文件系统
分布式文件系统(Distributed File System)是指文件系统管理的物理存储资源不一定直接连接在本地节点上,而是通过计算机网络与节点相连。分布式文件系统的设计基于客户机/服务器模式。一个典型的网络可能包括多个供多用户访问的服务器。另外,对等特性允许一些系统扮演客户机和服务器的双重角色。例如,用户可以“发表”一个允许其他客户机访问的目录,一旦被访问,这个目录对客户机来说就像使用本地驱动器一样。
-----------------百度百科
为什么需要:以前,我们将上传的视屏文件等放在一台宿主机内,如果一个盘符内存不够,就增加硬盘个数,但是单纯的增加硬盘个数已经无法满足当代的需求,毕竟硬盘访问速度有限
解决方式:增加计算机个数,将视屏分别放在不同计算机内,通过网络将一个一个计算机的文件系统连接起来组成一个网络文件系统,形成一个分布式网络
优点:用于扩容、高并发场景
1、一台计算机的文件系统处理能力扩充到多台计算机内同时处理
2、一台计算机挂了还有另外副本计算提供数据
3、每台计算机可以放在不同的地域,这样用户就可以就近访问,提高访问速度
二、分布式文件服务提供商
1、阿里的OSS
2、七牛云存储
3、百度云储存
三、什么是fastDFS
FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。
FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。
-----百度百科
图片来源于百度百科
四、fastdfs安装:
1、安装编译环境
[root@bogon ~]# docker exec -it centos /bin/bash
[root@0b5933e7fd96 /]# yum -y groupinstall 'Development Tools'
[root@0b5933e7fd96 /]# yum -y install wget
2、下载安装libfastcommon
[root@0b5933e7fd96 /]#git clone https://github.com/happyfish100/libfastcommon.git
[root@0b5933e7fd96 /]#cd libfastcommon/
[root@0b5933e7fd96 /]#./make.sh
[root@0b5933e7fd96 /]#./make.sh install
3、下载安装fastdfs
[root@0b5933e7fd96 /]#wget https://github.com/happyfish100/fastdfs/archive/V5.05.tar.gz
[root@0b5933e7fd96 /]#tar -zxvf V5.05.tar.gz
[root@0b5933e7fd96 /]#cd fastdfs-5.05/
[root@0b5933e7fd96 /]#./make.sh
[root@0b5933e7fd96 /]#./make.sh install
4、修改tracker与storage配置文件命名
备份tracker与storage配置文件,为了防止数据文件的破坏
[root@0b5933e7fd96 /]# find / -name fdfs
/etc/fdfs
[root@0b5933e7fd96 fdfs]# ll
total 40
-rw-r--r--. 1 root root 1461 Jan 13 02:08 client.conf.sample
-rw-r--r--. 1 root root 7829 Jan 13 02:08 storage.conf.sample
-rw-r--r--. 1 root root 7102 Jan 13 02:08 tracker.conf.sample
[root@0b5933e7fd96 fdfs]# cp client.conf.sample client.conf
[root@0b5933e7fd96 fdfs]#cp storage.conf.sample storage.conf
[root@0b5933e7fd96 fdfs]#cp tracker.conf.sample tracker.conf
[root@0b5933e7fd96 fdfs]# ll
total 40
-rw-r--r--. 1 root root 1461 Jan 13 02:14 client.conf
-rw-r--r--. 1 root root 1461 Jan 13 02:08 client.conf.sample
-rw-r--r--. 1 root root 7836 Jan 13 03:30 storage.conf
-rw-r--r--. 1 root root 7829 Jan 13 02:08 storage.conf.sample
-rw-r--r--. 1 root root 7103 Jan 13 03:28 tracker.conf
-rw-r--r--. 1 root root 7102 Jan 13 02:08 tracker.conf.sample
5、配置tracker
[root@0b5933e7fd96 fdfs]# vi tracker.conf
disabled=false
port=22122
base_path=/home/fastdfs/tracker
http.server_port=8080
7、配置storage
disabled=false
group_name=group1
port=23000
base_path=/home/fastdfs/storage
store_path0=/home/fastdfs/storage-data
tracker_server=192.168.174.128:22122
http.server_port=8888
8、配置路径
[root@0b5933e7fd96 home]# ll
total 0
drwxr-xr-x. 5 root root 53 Jan 13 03:26 fastdfs
[root@0b5933e7fd96 home]# cd fastdfs/
[root@0b5933e7fd96 fastdfs]# ll
total 0
drwxr-xr-x. 3 root root 17 Jan 13 03:31 storage
drwxr-xr-x. 2 root root 6 Jan 13 03:26 storage-data
drwxr-xr-x. 4 root root 28 Jan 13 03:31 tracker
8、启动tracker和storage
[root@0b5933e7fd96 fdfs]# /usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart
[root@0b5933e7fd96 fdfs]# /usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart
[root@0b5933e7fd96 storage-data]# ps -ef | grep fdfs
五、构建JAVA Client API
github访问地址:https://github.com/happyfish100/fastdfs-client-java
搭建环境
1、创建一个maven工程
2、添加依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<groupId>cn.ibo</groupId>
<artifactId>fastdfs</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>net.oschina.zcx7878</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.27.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
3、新增配置文件fastdfs-client.properties
## fastdfs-client.properties
fastdfs.connect_timeout_in_seconds = 5
fastdfs.network_timeout_in_seconds = 30
fastdfs.charset = UTF-8
fastdfs.http_anti_steal_token = false
fastdfs.http_secret_key = FastDFS1234567890
fastdfs.http_tracker_http_port = 80
fastdfs.tracker_servers = 192.168.174.128:22122
4、编写测试类
4.1) 上传
需求:将window 盘符下的指定文件通过fastFDS上传到linux指定目录下
/**
* Created by 佳先森 on 2019/1/13.
* 在此文件中通过fastDSF的client代码访问tracker和storage
* 通过client的api代码访问tracker和storage,他们中间走的socket协议
*/
public class TestFastDFS {
// 测试文件上传
@Test
public void testUpload(){
//通过fastDSF的client代码访问tracker和storage
String local_filename = "77.jpg";//上传文件名
try {
//加载fastDFS客户端的配置文件
ClientGlobal.initByProperties("config/fastdfs-client.properties");
System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
System.out.println("charset=" + ClientGlobal.g_charset);
//创建tracker的客户端
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
//定义storage的客户端
StorageClient1 client = new StorageClient1(trackerServer, storageServer);
//文件元数据(如文件名称大小等)
NameValuePair[] metaList = new NameValuePair[1];
metaList[0] = new NameValuePair("fileName",local_filename);//这是个数组,可以继续添加
//执行上传
String fileId = client.upload_file1("E:\\壁纸\\77.jpg", "jpg", metaList);
System.out.println("upload success. file id is: " + fileId);
//关闭trackerServer的连接
trackerServer.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
验证:此时在storage-data目录下可以看到上传的文件
[root@bogon 00]# pwd
/home/fastdfs/storage-data/data/00/00
[root@bogon 00]# ll
-rw-r--r--. 1 root root 55310 1月 13 21:15 wKiugFw7OeSAMlI9AADYDjkgjlY905.jpg
4.2) 检索
根据控制台打印的信息,利用文件ID检索文件信息
//查询上传的文件
@Test
public void testSearch(){
try {
//加载fastDFS客户端的配置文件
ClientGlobal.initByProperties("config/fastdfs-client.properties");
System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
System.out.println("charset=" + ClientGlobal.g_charset);
//创建tracker的客户端
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
//定义storage的客户端
StorageClient1 client = new StorageClient1(trackerServer, storageServer);
FileInfo group1 = client.query_file_info("group1", "M00/00/00/wKiugFw7OeSAMlI9AADYDjkgjlY905.jpg");
FileInfo fileInfo = client.query_file_info1("group1/M00/00/00/wKiugFw7OeSAMlI9AADYDjkgjlY905.jpg");
System.out.println(group1);
System.out.println(fileInfo);
//查询文件元信息
NameValuePair[] metadata1 = client.get_metadata1("group1/M00/00/00/wKiugFw7OeSAMlI9AADYDjkgjlY905.jpg");
for(NameValuePair temp:metadata1){
System.out.print(temp.getName()+"\t"+temp.getValue());
}
//关闭trackerServer的连接
trackerServer.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
4.3) 下载文件
根据文件ID下载文件到指定目录
@Test
public void downLoad(){
try {
//加载fastDFS客户端的配置文件
ClientGlobal.initByProperties("config/fastdfs-client.properties");
System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
System.out.println("charset=" + ClientGlobal.g_charset);
//创建tracker的客户端
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
//定义storage的客户端
StorageClient1 client = new StorageClient1(trackerServer, storageServer);
//下载
byte[] bytes = client.download_file1("group1/M00/00/00/wKiugFw7OeSAMlI9AADYDjkgjlY905.jpg");
File file = new File("e:/a.jpg");
FileOutputStream fos = new FileOutputStream(file);
fos.write(bytes);
fos.close();
//关闭trackerServer的连接
trackerServer.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
六、文件服务案列
先将文件存放到临时目录,再通过tracker server将临时文件上传到fastdfs中的storage中
注意:得先安装fastdfs-nginx-module,再安装nginx,在编译nginx过程中添加fastdfs-nginx-module,顺序弄反,会报
[emerg] unknown directive "ngx_fastdfs_module" ngix整合fastdfs启动后报错
FastDFS通过Tracker服务器,将文件放在Storage服务器存储,但是同组存储服务器之间需要进入文件复制,有同步延迟的问题。假设Tracker服务器将文件上传到了192.168.4.125,上传成功后文件ID已经返回给客户端。此时FastDFS存储集群机制会将这个文件同步到同组存储192.168.4.126,在文件还没有复制完成的情况下,客户端如果用这个文件ID在192.168.4.126上取文件,就会出现文件无法访问的错误。而fastdfs-nginx-module可以重定向文件连接到源服务器取文件,避免客户端由于复制延迟导致的文件无法访问错误。
1、安装fastdfs-nginx-module
[root@bogon local]# wget https://sourceforge.net/projects/fastdfs/files/FastDFS%20Nginx%20Module%20Source%20Code/fastdfs-nginx-module_v1.16.tar.gz
[root@bogon local]# tar xf fastdfs-nginx-module_v1.16.tar.gz
[root@bogon local]# cd fastdfs-nginx-module/src/
[root@bogon local]# vim config
#编辑config文件,执行如下命令进行批量替换并保存退出,目的:去掉local前缀,指定正确路径目录
:%s+/usr/local/+/usr/+g
[root@bogon src]# pwd
/usr/local/fastdfs-nginx-module/src
[root@bogon src]# cp mod_fastdfs.conf /etc/fdfs
[root@bogon local]# cd /etc/fdfs
[root@bogon fdfs]# vim mod_fastdfs.conf
#修改内容如下:
connect_timeout=10
base_path=/tmp(默认为/tmp)
tracker_server=192.168.174.128:22122
storage_server_port=23000(默认配置为23000)
url_have_group_name = true
store_path0=/home/fastdfs/storage-data
group_name=group1(默认配置为group1)
[root@bogon fastdfs-5.05]# pwd
/usr/java/fastdfs-5.05
[root@bogon fastdfs-5.05]# cd conf
[root@bogon conf]# cp http.conf /etc/fdfs
[root@bogon conf]# cp mime.types /etc/fdfs
安装nginx
[root@bogon local]# tar -zxvf nginx-1.6.0
[root@bogon local]# cd nginx-1.6.0/
[root@bogon nginx-1.6.0]#
./configure --prefix=/usr/local/nginx --add-module=/usr/local/fastdfs-nginx-module/src
[root@bogon nginx-1.6.0]#make && make install
[root@bogon local]# cd nginx
[root@bogon nginx]# cd conf
[root@bogon conf]# vim nginx.conf
location /group1/M00 {
root /home/fastdfs/storage-data;
ngx_fastdfs_module;
}
[root@bogon conf]# cd ..
[root@bogon nginx]# cd sbin/
[root@bogon sbin]# ./nginx
ngx_http_fastdfs_set pid=11005
配置nginx:
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location /group1/M00 {
root /home/fastdfs/storage-data/data; #storage_path0
ngx_fastdfs_module; #虚拟模块
}
}
此时根据刚刚测试类中上传的文件利用nginx访问:如果nginx能够正常访问表示配置nginx成功
这是通过http的方式(集成nginx)访问上传图片
七、搭建文件管理服务
文件管理服务提供通过http方式上传文件、删除文件、查询文件的功能,管理员通过文件管理服务队文件服务器上的文件进行管理
文件管理服务采用Spring Boot开发,文件管理服务通过与fastDFS交互最终将用户上传的文件存储到fastDFS上
1、建立实体类
/**
* Created by 佳先森 on 2019/1/13.
*/
public class FileSystem {
private String fileId;
private String filePath;
private long fileSize;
private String fileName;
private String fileType;
//省去set/get
}
2、编写配置文件application.yml
server:
port: 22100
fastdfs:
#文件上传临时目录
upload_location: E:\\download\\
3、建立controller
/**
* Created by 佳先森 on 2019/1/13.
*/
@RestController
@RequestMapping("/filesystem")
public class FileServerController {
@Value("${fastdfs.upload_location}") //读取配置文件
private String upload_location;
@PostMapping("/upload")
@ResponseBody
public FileSystem upload(@RequestParam("file") MultipartFile file) throws IOException {
//先将文件存储在web服务器上(本机),再使用fastDFS的client将文件到fastDFS服务器
FileSystem fileSystem = new FileSystem();
//得到文件的原始名称
String originalFilename = file.getOriginalFilename();
String extention = originalFilename.substring(originalFilename.lastIndexOf("."));
//重构上传文件名
String newFileName = UUID.randomUUID()+extention;
//定义file,使用file存储上传的文件
File file1 =new File(upload_location+newFileName);
file.transferTo(file1);
//获取新上传文件的物理路径
String newFilePath = file1.getAbsolutePath();
try {
//加载fastDFS客户端的配置文件
ClientGlobal.initByProperties("config/fastdfs-client.properties");
System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
System.out.println("charset=" + ClientGlobal.g_charset);
//创建tracker的客户端
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
//定义storage的客户端
StorageClient1 client = new StorageClient1(trackerServer, storageServer);
//文件元数据(如文件名称大小等)
NameValuePair[] metaList = new NameValuePair[1];
metaList[0] = new NameValuePair("fileName",originalFilename);//这是个数组,可以继续添加
//执行上传,将上传成功的存放在web服务器(本机)上的文件上传到fastDFS
String fileId = client.upload_file1(newFilePath, extention, metaList);
System.out.println("upload success. file id is: " + fileId);
fileSystem.setFileId(fileId);
fileSystem.setFilePath(fileId);
fileSystem.setFileName(originalFilename);
//通过调用service即dao将文件路径存储到数据库中
//....todo
//关闭trackerServer的连接
trackerServer.close();
} catch (Exception ex) {
ex.printStackTrace();
}
return fileSystem;
}
}
4、编写启动类
/**
* Created by 佳先森 on 2019/1/13.
*/
@SpringBootApplication
public class FileServiceApplication {
public static void main(String[] args) {
SpringApplication.run(FileServiceApplication.class);
}
}
5、编写前端界面
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>Upload</title>
</head>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<body>
<div id="clj">
<el-upload
action=""
list-type="picture-card"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove">
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
</div>
<script type="text/javascript" src="vue.min.js"></script>
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script>
new Vue({
el: '#clj',
data: {
dialogVisible: false,
dialogImageUrl: ''
},
methods: {
handlePictureCardPreview(file){ #预览
this.dialogImageUrl ="http://192.168.174.128/"+file.response.filePath #注意:预览时访问的图片地址是通过nginx代理的,需要配置图片所在宿主机地址
this.dialogVisible = true;
},
handleRemove(){}
}
})
</script>
</body>
</html>
6、nginx中配置页面访问路径
#图片服务测试(图片页面)
server {
listen 7283;
server_name localhost;
location / {
root /usr/java/javademo/springboot-vue-fastdfs/upload/;
index index.html;
}
}
此时访问http://192.168.174.128:7283/upload.html,若成功访问到页面,则配置成功
但是这样远远不够的,因为页面中的action配置的请求后台的action是访问不到的,存在跨域问题(页面与后端代码不在同一台宿主机上),解决跨域问题常见的思路就是在nginx中配置代理
#图片服务测试(图片页面)
server {
listen 7283;
server_name localhost; #这里配置的是页面所在宿主机ip
location / {
root /usr/java/javademo/springboot-vue-fastdfs/upload/;
index index.html;
}
location ^~ /filesystem/ { #配置代理
proxy_pass http://192.168.2.174:22100/filesystem/; #注意这里配置的是后端代码所在宿主机ip
}
}
此时上传和预览功能已经完成