初创时期由于时间紧迫,在各种资源有限的情况下,通常就直接在项目目录下建立静态文件夹,用于用户存放项目中的文件资源。如果按不同类型再细分,可以在项目目录下再建立不同的子目录来区分。例如:resources\static\file
、resources\static\img
等。
优点:便利,使用方便。
缺点:文件越多存放越混乱
随着公司业务不断发展,将代码和文件放在同一服务器的弊端就会越来越明显。为了解决上面的问题引入独立图片服务器,
流程:
项目上传文件时,首先通过ftp或者ssh将文件上传到图片服务器的某个目录下,再通过Ngnix或者Apache来访问此目录下的文件,返回一个独立域名的图片URL地址,前端使用文件时就通过这个URL地址读取。
缺点:
存在单点故障的问题。数据备份需要人为干预。
业务继续发展,单台服务器存储和响应也很快到达了瓶颈,新的业务需要文件访问具有高响应性、高可用性来支持系统。
优点:
- 扩展能力: 毫无疑问,扩展能力是一个分布式文件系统最重要的特点;
- 高可用性: 在分布式文件系统中,高可用性包含两层,一是整个文件系统的可用性,二是数据的完整和一致性;
- 弹性存储: 可以根据业务需要灵活地增加或缩减数据存储以及增删存储池中的资源,而不需要中断系统运行。
缺点:系统复杂度稍高,需要更多服务器
FastDFS是一个开源的轻量级分布式文件系统。它解决了大数据量存储和负载均衡等问题。特别适合以中小文件(建议范围:4KB < file_size <500MB)为载体的在线服务,如相册网站、视频网站等等。
1、阿里的OSS
2、七牛云存储
3、百度云储存
FastDFS服务端有三个角色:跟踪服务器(tracker)、存储服务器(storage)和客户端(client)。
跟踪服务器,主要做调度工作,起负载均衡的作用。在内存中记录集群中所有存储组和存储服务器的状态信息,是客户端和数据服务器交互的枢纽。就相当于是工厂的包工头。
存储服务器(又称:存储节点或数据服务器),文件和文件属性(meta data)都保存到存储服务器上。Storage server直接利用OS的文件系统调用管理文件。相当于是工厂的工人。
客户端,作为业务请求的发起方,通过专有接口,使用TCP/IP协议与跟踪器服务器或存储节点进行数据交互。FastDFS向使用者提供基本文件访问接口,比如upload、download、append、delete等,以客户端库的方式提供给用户使用。
组, 也可称为卷。 同组内服务器上的文件是完全相同的 ,同一组内的storage server之间是对等的, 文件上传、 删除等操作可以在任意一台storage server上进行 。
流程:
Tracker相当于FastDFS的大脑,不论是上传还是下载都是通过tracker来分配资源;客户端一般可以使用Ngnix等静态服务器来调用或者做一部分的缓存;存储服务器内部分为卷(或者叫做组),卷于卷之间是平行的关系,可以根据资源的使用情况随时增加,卷内服务器文件相互同步备份,以达到容灾的目的。
首先客户端请求Tracker服务获取到存储服务器的ip地址和端口,然后客户端根据返回的IP地址和端口号请求上传文件,存储服务器接收到请求后生产文件,并且将文件内容写入磁盘并返回给客户端file_id、路径信息、文件名等信息,客户端保存相关信息上传完毕。
1、选择Tracker server
当集群中不止一个Tracker server时,由于Tracker之间是完全对等的关系,客户端在upload文件时可以任意选择一个trakcer。
2、选择Storage server
当选定Group后,Tracker会在Group内选择一个Storage Server给客户端
3、选择Storage path
当分配好Storage Server后,客户端将向Storage发送写文件请求,Storage将会为文件分配一个数据存储目录。
注意:
剩余存储空间最多的优先。
4、生成Fileid
选定存储目录之后,Storage会为文件生一个Fileid,由Storage Server Ip、文件创建时间、文件大小、文件crc32和一个随机数拼接而成,然后将这个二进制串进行base64编码,转换为可打印的字符串。
5、生成文件名
当文件存储到某个子目录后,即认为该文件存储成功,接下来会为该文件生成一个文件名,文件名由group、存储目录、两级子目录、fileid、文件后缀名(由客户端指定,主要用于区分文件类型)拼接而成。
客户端带上文件名信息请求Tracker服务获取到存储服务器的ip地址和端口,然后客户端根据返回的IP地址和端口号请求下载文件,存储服务器接收到请求后返回文件给客户端。
安装方式为yum安装(需网络):
yum install gcc-c++ perl-devel pcre-devel openssl-devel zlib-devel wget
wget https://github.com/happyfish100/fastdfs/archive/V6.06.tar.gz
wgethttps://github.com/happyfish100/libfastcommon/archive/V1.0.43.tar.gz
wget https://github.com/happyfish100/fastdfs/archive/V6.06.tar.gz
tar -zxvf V1.0.43.tar.gz -C /usr/local
tar -zxvf V6.06.tar.gz -C /usr/local
cd /usr/local/libfastcommon-1.0.43/
./make.sh && ./make.sh install
cd /usr/local/fastdfs-6.06
./make.sh && ./make.sh install
cd /etc/fdfs/
cp client.conf.sample client.conf
cp storage.conf.sample storage.conf
cp tracker.conf.sample tracker.conf
mkdir -p /data/fastdfs/tracker
vim /etc/fdfs/tracker.conf
disabled=false #启用配置文件
port=22122 #设置 tracker 的端口号
base_path=/data/fastdfs/tracker #设置 tracker 的数据文件和日志目录(需预先创建)
http.server_port=8888 #设置 http 端口号,指的是在tracker服务器上启动http服务进程,如:apache或者nginx 启动时所监听的端口
/etc/init.d/fdfs_trackerd start
netstat -lntup |grep fdfs
mkdir -p /data/fastdfs/base #日志
mkdir -p /data/fastdfs/storage #文件存储位置
vim /etc/fdfs/storage.conf
disabled=false #启用配置文件
group_name=group1 #组名,根据实际情况修改
port=23000 #设置 storage 的端口号
base_path=/data/fastdfs/base #设置 storage 的日志目录(需预先创建)
store_path_count=1 #存储路径个数,需要和 store_path 个数匹配
store_path0=/data/fastdfs/storage #存储路径
tracker_server = 192.168.66.100:22122 #tracker 服务器的 IP 地址和端口号
http.server_port=8888 #设置storage上启动的http服务的端口号,如安装的nginx的端口号
/etc/init.d/fdfs_storaged start
netstat -lntup |grep fdfs
mkdir -p /data/fastdfs/client
vim /etc/fdfs/client.conf
connect_timeout=30
network_timeout=60
base_path=/data/fastdfs/client # 日志路径
tracker_server=192.168.66.100:22122 # 追踪服务器的IP,有多个服务器可以另一行
ps -ef | grep fdfs
fdfs_upload_file [storage_ip:port] [store_path_index]
参数含义:
:客户端client配置文件路径 :要上传的文件的地址 - [storage_ip:port] :(可选参数)
- [store_path_index] :(可选参数)
示例:
fdfs_upload_file /etc/fdfs/client.conf ./pdx.jpg #将当前文件夹下的pdx.jpg文件上传到FastDFS
group1/M00/00/00/wKhCZGSzyi6ANZJJAANsTCZQKGY266.jpg #上传文件后会返回文件在FastDFS中的唯一文件标识,即卷名+文件名
在/data/fastdfs/storage/data/00/00可以查看当前上传的文件
fdfs_download_file [local_filename] [
参数含义:
:客户端配置文件路径 :文件在FastDFS中的唯一文件标识,即卷名+文件名 - [local_filename] :文件下载地址
:(可选参数)文件下载开始时间 :(可选参数)文件下载的字节数
示例:
#将文件下载到当前路径下
fdfs_download_file /etc/fdfs/client.conf group1/M00/00/00/wKhCZGSzyi6ANZJJAANsTCZQKGY266.jpg
fdfs_file_info
参数含义:
:客户端配置文件路径 :文件在FastDFS中的唯一文件标识,即卷名+文件名
示例:
#查看文件的信息
fdfs_file_info /etc/fdfs/client.conf group1/M00/00/00/wKhCZGSzyi6ANZJJAANsTCZQKGY266.jpg
fdfs_delete_file
参数含义:
:客户端配置文件路径 :文件在FastDFS中的唯一文件标识,即卷名+文件名
示例:
fdfs_delete_file /etc/fdfs/client.conf group1/M00/00/00/wKhCZGSzyi6ANZJJAANsTCZQKGY266.jpg
注意:
删除指令使用后,文件在该卷中的所有备份都会被删除,因为卷内的存储节点会相互同步,故慎用。
由GitHub大牛tobato在原作者YuQing与yuqih发布的JAVA客户端基础上进行了大量重构工作,并于GitHub上发布了FastDFS-Client1.26.5。
com.github.tobato
fastdfs-client
1.26.5
####分布式文件系统配置###########
fdfs:
so-timeout: 1500
connect-timeout: 600
thumb-image: #缩略图生成参数
width: 150
height: 150
tracker-list: #TrackerList参数,支持多个
- 192.168.66.100:22122
# - 192.168.66.101:22122
package com.zj;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.domain.proto.storage.DownloadByteArray;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.io.*;
@SpringBootTest
class FastdfsApplicationTests {
//通过FastDFS的客户端对象完成对文件系统的操作
@Resource
private FastFileStorageClient fastFileStorageClient;
//测试上传文件
@Test
public void upload() throws FileNotFoundException {
//1.先读取本地文件
File file = new File("D:\\aaa.jpg");
//2.创建传输文件输入流
FileInputStream fileInputStream = new FileInputStream(file);
//3.文件上传
/*
* 参数一:文件输入流
* 参数二:文件大小
* 参数三:文件拓展名
* 参数四:描述文件的元数据(指定文件上传的位置)
*/
StorePath storePath = fastFileStorageClient.uploadFile(fileInputStream, file.length(), "jpg", null);
//4.将卷名和文件名一起打印
System.out.println("上传文件的地址:"+storePath.getFullPath());
System.out.println("文件卷名:"+storePath.getGroup());
System.out.println("文件名:"+storePath.getPath());
}
//文件下载
@Test
public void download() throws IOException {
//1.下载文件
/*
* 参数一:文件处于存储节点的卷名
* 参数二:文件在存储节点的文件名
* 参数三:下载的回调函数
*/
byte[] downloadFile = fastFileStorageClient.downloadFile("group1", "M00/00/00/wKhCZGS2WGaAYKOuADcAPt_yJDw957.jpg", new DownloadByteArray());
//2.创建文件输出流,并指定文件下载的位置
FileOutputStream fileOutputStream = new FileOutputStream("d:\\aaa.jpg");
//3.将文件输出流写文件到磁盘
fileOutputStream.write(downloadFile);
//4.刷新
fileOutputStream.flush();
//5.关闭流
fileOutputStream.close();
}
}
com.github.tobato
fastdfs-client
1.26.5
org.springframework.boot
spring-boot-starter-thymeleaf
org.springframework.boot
spring-boot-starter-web
注意:
使用wangeditor富文本编辑器的前提是引入Thymeleaf模板。
欢迎使用 wangEditor 富文本编辑器
package com.zj.controller;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.IOException;
@RestController
public class uploadController {
@Resource
private FastFileStorageClient fastFileStorageClient;
//图片上传
@PostMapping("/upload")
public void upload(MultipartFile file) throws IOException {
//1.判断文件是否为空
if(file != null){
//2.获取上传的图片的名字
String originalFilename = file.getOriginalFilename();
//3.获取上传的图片的扩展名
String suffix = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
//4.上传图片
StorePath storePath = fastFileStorageClient.uploadFile(file.getInputStream(), file.getSize(), suffix, null);
System.out.println("上传的文件的路径:"+storePath.getFullPath());
//5.上传的文件路径需要保存到数据库中
//……
}
}
}
文件上传的请求方式必须是post
文件上传
欢迎使用 wangEditor 富文本编辑器
Nginx服务器是一个高性能的web服务器与反向代理服务器。
通过Nginx的web服务代理访问分布式文件系统的存储节点,从而实现通过http请求访问存储节点资源。
注意:
src 属性值图像文件的 URL。也就是引用该图像的文件的的绝对路径或相对路径。
由于FastDFS的同卷的存储节点之间需要同步,当文件尚未同步完成时,访问请求到达改节点,获取的数据将是未同步完的不完整数据,即为复制延迟问题。通过Nginx检测请求的存储节点的数据,若该存储节点的数据尚未同步完成,则将请求转发至数据的原存储节点,从而解决复制延迟问题。
#选择安装位置
cd /usr/local
#下载文件(或者使用本文章已经下载好的文件)
wget https://github.com/happyfish100/fastdfs-nginx-module/archive/V1.22.tar.gz
#解压文件
tar -zxvf V1.22.tar.gz
yum install -y gcc gcc-c++ zlib zlib-devel openssl openssl-devel pcre pcre-devel gd-devel epel-release
#建立Makefile文件,检查Linux系统环境以及相关的关键属性。添加fastdfs-nginx-module-1.22模块到nginx
./configure --add-module=/usr/local/fastdfs-nginx-module-1.22/src/
#编译项目,主要将gcc源代码编译成可执行的目标文件
make
#根据上一步骤编译完成的数据安装到预定的目录中。之前安装过ngxin的话不需要再安装
make install
注意:
- –add-module:为nginx添加一个fastdfs-nginx-module模块,值为该模块在当前系统的路径
- –prefix:指定nginx安装位置
将Fastdfs软件包里面的http.conf和mime.types拷贝到/etc/fdfs目录下
cp /usr/local/fastdfs-6.06/conf/mime.types /etc/fdfs/
cp /usr/local/fastdfs-6.06/conf/http.conf /etc/fdfs/
#拷贝文件
[root@localhost opt]cp /usr/local/fastdfs-nginx-module-1.22/src/mod_fastdfs.conf /etc/fdfs/
[root@localhost fdfs] vim mod_fastdfs.conf
#保存日志目录
base_path=/data/fastdfs/storage
#tracker 服务器的 IP 地址以及端口号
tracker_server=192.168.66.100:22122
#文件url中是否有group 名
url_have_group_name = true
#存储路径
store_path0=/data/fastdfs/storage
group_count = 1 #设置组的个数
#然后在末尾添加分组信息,目前只有一个分组,就只写一个
[group1]
group_name=group1
storage_server_port=23000
store_path_count=1
store_path0=/data/fastdfs/storage
server {
listen 80;
server_name localhost;
location ~ /group[1-3]/M00 {
alias /data/fastdfs/storage/data;
ngx_fastdfs_module;
}
# 根目录下返回403
location = / {
return 403;
}
# log file
access_log logs/img_access.log access;
}
# 进入sbin目录
[root@tracker nginx]# cd sbin/
# 启动服务 -c:指定配置文件
[root@tracker sbin]# ./nginx -c /usr/local/nginx/conf/nginx.conf
[root@tracker sbin]# ps -ef | grep nginx
[root@tracker sbin]# fdfs_trackerd /etc/fdfs/tracker.conf start
[root@tracker sbin]# fdfs_storaged /etc/fdfs/storage.conf start
将图片上传至linux系统后,使用指令上传至分布式文件系统
[root@localhost /]# fdfs_upload_file /etc/fdfs/client.conf pdx.jpg
group1/M00/00/00/wKhCZGS6zneAUxGKAANsTCZQKGY401.jpg
http://192.168.66.100/group1/M00/00/00/wKhCZGS6zneAUxGKAANsTCZQKGY401.jpg