FastDFS核心概念与架构原理解析
为什么要使用分布式文件系统
- 海量文件数据存储
- 文件数据高可用(冗余备份)
- 读写性能和负载均衡
- 以上3点都是我们之前使用tomcat或nginx所不能够实现的,这也是我们为什么要使用分布式文件系统的原因
FastDFS 与 HDFS
- Hadoop中的文件系统HDFS主要解决并行计算中分布式存储数据的问题。其单个数据文件通常很大,采用了分块(切分)存储的方式,所以是大数据大文件存储来使用的场景
- FastDFS主要用于互联网网站,为文件上传和下载提供在线服务。所以在负载均衡、动态扩容等方面都支持得比较好,FastDFS不会对文件进行分快存储。FastDFS用于存储中小文件都是不错的,比如用户头像啊,一些较小的音视频文件啊等等都行
FastDFS常见术语
- tracker:追踪者服务器,主要用于协调调度,可以起到负载均衡的作用,记录storage的相关状态信息。
- storage:存储服务器,用于保存文件以及文件的元数据信息。
- group:组,同组节点提供冗余备份,不同组用于扩容。
- mata data:文件的元数据信息,比如长宽信息,图片后缀,视频的帧数等。
FastDFS架构

FastDFS上传过程

FastDFS下载过程

FastDFS配置
配置FastDFS环境准备工作
参考文献
https://github.com/happyfish100/
https://github.com/happyfish100/fastdfs/wiki
https://www.cnblogs.com/leechenxiang/p/5406548.html
https://www.cnblogs.com/leechenxiang/p/7089778.html环境准备
- Centos7.x 两台,分别安装tracker与storage
下载安装包:
- libfatscommon:FastDFS分离出的一些公用函数包
- FastDFS:FastDFS本体
- fastdfs-nginx-module:FastDFS和nginx的关联模块
- nginx:发布访问服务
安装步骤(tracker和storage都要执行)
- 安装基础环境
yum install -y gcc gcc-c++yum -y install libevent
- 安装基础环境
-
安装libfatscommon函数库
# 解压tar -zxvf libfastcommon-1.0.42.tar.gz
-
进入libfastcommon文件夹,编译并且安装
./make.sh./make.sh install
-
安装fastdfs主程序文件
# 解压tar -zxvf fastdfs-6.04.tar.gz
进入到fastdfs目录,查看fastdfs安装配置
cd fastdfs-6.04/vim make.sh
TARGET_PREFIX=$DESTDIR/usrTARGET_CONF_PATH=$DESTDIR/etc/fdfsTARGET_INIT_PATH=$DESTDIR/etc/init.d
安装fastdfs
./make.sh./make.sh install
如上图,
-
/usr/bin 中包含了可执行文件;
-
/etc/fdfs 包含了配置文件;


-
拷贝配置文件如下
cp /home/software/FastDFS/fastdfs-6.04/conf/* /etc/fdfs/

配置tracker服务
说明
- tracker和storage都是同一个fastdfs的主程序的两个不同概念,配置不同的配置文件就可以设定为tracker或者storage
- 配置tracker
/etc/fdfs下都是一些配置文件,配置tracker即可vim tracker.conf

-
修改tracker配置文件,此为tracker的工作目录,保存数据以及日志
base_path=/usr/local/fastdfs/tracker
mkdir /usr/local/fastdfs/tracker -p
- 启动tracker服务
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf
检查进程如下:
ps -ef|grep tracker
- 停止tracker
/usr/bin/stop.sh /etc/fdfs/tracker.conf
配置storage服务
后续结合nginx的一个对外服务端口号
http.server_port=8888
-创建目录```nginxmkdir /usr/local/fastdfs/storage -p
- 启动storage
前提:必须首先启动tracker/usr/bin/fdfs_storaged /etc/fdfs/storage.conf
检查进程如下:
ps -ef|grep storage

测试上传
- 修改的client配置文件

base_path=/usr/local/fastdfs/clienttracker_server=192.168.1.153:22122
- 修改的client配置文件
mkdir /usr/local/fastdfs/client
-
测试:
wget https://www.imooc.com/static/img/index/logo.png./fdfs_test /etc/fdfs/client.conf upload /home/logo.png

- 配置nginx fastdfs实现文件服务器
引子
fastdfs安装好以后是无法通过http访问的,这个时候就需要借助nginx了,所以需要安装fastdfs的第三方模块到nginx中,就能使用了。
注:nginx需要和storage在同一个节点。
安装nginx插件
- 解压nginx的fastdfs压缩包
tar -zxvf fastdfs-nginx-module-1.22.tar.gz
- 解压nginx的fastdfs压缩包
- 复制配置文件如下:
cp mod_fastdfs.conf /etc/fdfs

- 修改/fastdfs-nginx-module/src/config文件,主要是修改路径,把
local删除,因为fastdfs安装的时候没有修改路径,原路径是/usr:
安装nginx(略)
- 其中配置如下:
./configure \--prefix=/usr/local/nginx \--pid-path=/var/run/nginx/nginx.pid \--lock-path=/var/lock/nginx.lock \--error-log-path=/var/log/nginx/error.log \--http-log-path=/var/log/nginx/access.log \--with-http_gzip_static_module \--http-client-body-temp-path=/var/temp/nginx/client \--http-proxy-temp-path=/var/temp/nginx/proxy \--http-fastcgi-temp-path=/var/temp/nginx/fastcgi \--http-uwsgi-temp-path=/var/temp/nginx/uwsgi \--http-scgi-temp-path=/var/temp/nginx/scgi \--add-module=/home/software/fdfs/fastdfs-nginx-module-1.22/src
- 其中配置如下:
- 主要新增一个第三方模块,修改 mod_fastdfs.conf 配置文件:
base_path=/usr/local/fastdfs/tmptracker_server=192.168.1.153:22122group_name=imoocurl_have_group_name = truestore0_path=/usr/local/fastdfs/storage
mkdir /usr/local/fastdfs/tmp
修改nginx.conf,添加如下虚拟主机:
server {listen 8888;server_name localhost;location /imooc/M00 {ngx_fastdfs_module;}}
FastDFS整合SpringBoot技术落地
- pom依赖
<!-- fastdfs依赖 --><dependency><groupId>com.github.tobato</groupId><artifactId>fastdfs-client</artifactId><version>1.26.7</version></dependency>
- 上传接口
public String upload(MultipartFile file, String fileExtName) throws Exception;
- 接口实现类 ```java @Autowired private FastFileStorageClient fastFileStorageClient;
@Override public String upload(MultipartFile file, String fileExtName) throws Exception {
StorePath storePath = fastFileStorageClient.uploadFile(file.getInputStream(),file.getSize(),fileExtName,null);String path = storePath.getFullPath();return path;
}
-上传controller```java@ApiOperation(value = "用户头像修改", notes = "用户头像修改", httpMethod = "POST")@PostMapping("uploadFace")public IMOOCJSONResult uploadFace(@ApiParam(name = "userId", value = "用户id", required = true)String userId,@ApiParam(name = "file", value = "用户头像", required = true)MultipartFile file,HttpServletRequest request,HttpServletResponse response) throws Exception {String path = "";// 开始文件上传if (file != null) {// 获得文件上传的文件名称String fileName = file.getOriginalFilename();if (StringUtils.isNotBlank(fileName)) {// 文件重命名 imooc-face.png -> ["imooc-face", "png"]String fileNameArr[] = fileName.split("\\.");// 获取文件的后缀名String suffix = fileNameArr[fileNameArr.length - 1];if (!suffix.equalsIgnoreCase("png") &&!suffix.equalsIgnoreCase("jpg") &&!suffix.equalsIgnoreCase("jpeg")) {return IMOOCJSONResult.errorMsg("图片格式不正确!");}path = fileService.upload(file, suffix);}} else {return IMOOCJSONResult.errorMsg("文件不能为空!");}if (StringUtils.isNotBlank(path)) {String finalUserFaceUrl = fileResource.getOssHost() + path;Users userResult = centerUserService.updateUserFace(userId, finalUserFaceUrl);userResult = setNullProperty(userResult);CookieUtils.setCookie(request, response, "user",JsonUtils.objectToJson(userResult), true);} else {return IMOOCJSONResult.errorMsg("上传头像失败");}return IMOOCJSONResult.ok();}
第三方云存储解决方案-OSS
使用OSS优点
- SDK使用简单
- 提供强大的文件处理功能
- 零运维成本
- 图形化管理控制台
- CDN加速
- OSS基本配置
file.host=http://192.168.1.156:8888/file.endpoint=oss-cn-beijing.aliyuncs.comfile.accessKeyId=LTAI4Fo5zZefile.accessKeySecret=uTVnXbuTTgfile.bucketName=imooctestfile.objectName=foodie-dev/imagesfile.ossHost=https://imooctest.oss-cn-beijing.aliyuncs.com/
OSS实现文件上传
@Overridepublic String uploadOSS(MultipartFile file, String userId, String fileExtName) throws Exception {// 构建ossClientOSS ossClient = new OSSClientBuilder().build(fileResource.getEndpoint(),fileResource.getAccessKeyId(),fileResource.getAccessKeySecret());InputStream inputStream = file.getInputStream();String myObjectName = fileResource.getObjectName() + "/" + userId + "/" + userId + "." + fileExtName;ossClient.putObject(fileResource.getBucketName(), myObjectName, inputStream);ossClient.shutdown();return myObjectName;}
```nginx