之前大学时搭建过一个FastDFS的图片服务器,当时只是抱着好奇的态度搭着玩一下,当时搭建采用了一台虚拟机,tracker和storage服务在一台机器上放着,最近翻之前的博客突然想着在两台机器上搭建试一下,顺便整合了SpringBoot实现了一下图片的上传服务。
新的阅读体验地址:http://www.zhouhong.icu/post/140
使用旧版本的在一台机器上搭建可以参考之前的那篇文章:https://www.cnblogs.com/Tom-shushu/p/10603723.html
一、传统文件上传问题:
如果我们现在用户使用的是第一胎服务器Tomcat1上传了文件,然后当用户访问Tomcat1时候可以访问到上传的文件、图片等等,但是如果当用户访问到Tomcat2和Tomcat3的时候,由于文件资源在Tomcat1上面,所以他是访问不到对应的资源的;这时就可以使用到分布式文件系统FastDFS了。
二、什么是分布式文件系统
- 随着文件数据的越来越多,通过tomcat或nginx虚拟化的静态资源文件在单一的一个服务器节点内是存不下的,如果用多个节点来存储也可以,但是不利于管理和维护,所以我们需要一个系统来管理多台计算机节点上的文件数据,这就是分布式文件系统。
- 分布式文件系统是一个允许文件通过网络在多台节点上分享的文件系统,多台计算机节点共同组成一个整体,为更多的用户提供分享文件和存储空间。比如常见的网盘,本质就是一个分布式的文件存储系统。虽然我们是一个分布式的文件系统,但是对用户来说是透明的,用户使用的时候,就像是访问本地磁盘一样。
- 分布式文件系统可以提供冗余备份,所以容错能力很高。 系统中有某些节点宕机,但是整体文件服务不会停止,还是能够为用户提供服务,整体还是运作的,数据也不会丢失。
- 分布式文件系统的可扩展性强,增加或减少节点都很简单,不会影响线上服务,增加完毕后会发布到线上,加入到集群中为用户提供服务。
- 分布式文件系统可以提供负载均衡能力,在读取文件副本的时候可以由多个节点共同提供服务,而且可以通过横向扩展来确保性能的提升与负载。
三、为什么要使用分布式文件系统
使用分布式文件系统可以解决如下几点问题:- 海量文件数据存储
- 文件数据高可用(冗余备份)
- 读写性能和负载均衡
四、FastDFS 与 HDFS
说到分布式文件存储,肯定会有人想到HDFS,他们两者主要定位和应用场景是不一样的。- Hadoop中的文件系统HDFS主要解决并行计算中分布式存储数据的问题。其单个数据文件通常很大,采用了分块(切分)存储的方式,所以是大数据大文件存储来使用的场景。
- FastDFS主要用于互联网网站,为文件上传和下载提供在线服务。所以在负载均衡、动态扩容等方面都支持得比较好,FastDFS不会对文件进行分快存储。FastDFS用于存储中小文件都是不错的,比如用户头像啊,一些较小的音视频文件啊等等都行。
五、FastDFS常见术语
- tracker:追踪者服务器,主要用于协调调度,可以起到负载均衡的作用,记录storage的相关状态信息。
- storage:存储服务器,用于保存文件以及文件的元数据信息
- group:组,同组节点提供冗余备份,不同组用于扩容
- mata data: 文件的元数据信息,比如长宽信息、图片后缀,视频帧数等
六、FastDFS架构
tracker和storage是有心跳信息的,需要先启动tracker
七、FasfDFS文件上传过程
八、FastDFS下载过程
九、FastDFS搭建:
准备:- 安装包准备
链接:https://pan.baidu.com/s/1Lic4JfUT4a8YdYmqJ5_vcQ 提取码:bm0a 复制这段内容后打开百度网盘手机App,操作更方便哦
两台服务器
- tracker服务:192.168.2.120 、storage服务:192.168.2.121,如下图:
1、基本环境搭建:
- 安装基础环境
yum install -y gcc gcc-c++ yum -y install libevent
- 安装libfastcommon函数库
# 1.解压 tar -zxvf libfastcommon-1.0.42.tar.gz
# 2.进入解压后的文件夹编译并安装 cd libfastcommon-1.0.42/ ./make.sh ./make.sh install
- 安装FastDFS主程序文件
# 1.解压 tar -zxvf fastdfs-6.04.tar.gz
# 2.进入到fastdfs目录,查看fastdfs安装配置 cd fastdfs-6.04/ vim make.sh
# 3.安装fastdfs ./make.sh ./make.sh install
# 4.将FastDFS中conf中的文件拷贝到 /etc/fdfs下 cp /software/FastDFS/fastdfs-6.04/conf/* /etc/fdfs/
2、配置tracker服务
进入 /etc/fdfs 修改配置文件 tracker.conf# 1.修改文件路径 base_path=/usr/local/fastdfs/tracker
# 2.创建文件路径 mkdir /usr/local/fastdfs/tracker -p
# 3.启动 /usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf
# 4.查看服务 ps -ef|grep tracker
# 5.停止tracker /usr/bin/stop.sh /etc/fdfs/tracker.conf
3.配置storage服务
进入 /etc/fdfs 修改配置文件 storage.conf# 1.修改配置文件 storage.conf # 修改组名 group_name=zhouhong # 修改storage的工作空间 base_path=/usr/local/fastdfs/storage # 修改storage的存储空间 store_path0=/usr/local/fastdfs/storage # 修改tracker的地址和端口号,用于心跳 tracker_server=192.168.2.120:22122 # 后续结合nginx的一个对外服务端口号 http.server_port=8888
# 2.创建目录 mkdir /usr/local/fastdfs/storage -p
# 3.启动 /usr/bin/fdfs_storaged /etc/fdfs/storage.conf
4.查看 ps -ef|grep storage
4、测试
修改 /etc/fdfs 下 client.conf文件# 1.修改client.conf文件 base_path=/usr/local/fastdfs/client tracker_server=192.168.2.120:22122
# 2.创建目录 mkdir /usr/local/fastdfs/client
# 3.准备一张图片测试 /usr/bin/fdfs_test /etc/fdfs/client.conf upload zhouhong.jpg成功!
5、配置 nginx fastdfs 实现文件服务器
Nginx需要跟storage安装在同一台服务器上面fastdfs安装好以后是无法通过http访问的,这个时候就需要借助nginx了,所以需要安装fastdfs的第三方模块到nginx中,就能使用了。
- 安装nginx插件
# 1.解压 tar -zxvf fastdfs-nginx-module-1.22.tar.gz
# 2.复制配置文件 cp /software/FastDFS/fastdfs-nginx-module-1.22/src/mod_fastdfs.conf /etc/fdfs/
# 3.修改/fastdfs-nginx-module/src/config文件 修改/fastdfs-nginx-module/src/config文件,主要是修改路径,把local删除, 因为fastdfs安装的时候我们没有修改路径,原路径是/usr
如图所示,将local删除即可
- 安装Nginx
# 1.环境安装 yum install -y pcre pcre-devel yum install -y zlib zlib-devel yum install -y gcc-c++ yum install -y openssl openssl-decel
# 2.解压 tar -zxvf nginx-1.16.1.tar.gz
# 3.创建目录 mkdir /var/temp/nginx -p
# 4.进入解压目录、最后一个为fastdfs-nginx-module-1.22解压目录 ./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=/software/FastDFS/fastdfs-nginx-module-1.22/src
# 5.安装 make make install
# 6.修改 /etc/fdfs/mod_fastdfs.conf base_path=/usr/local/fastdfs/tmp tracker_server=192.168.2.120:22122 group_name=zhouhong url_have_group_name = true store_path0=/usr/local/fastdfs/storage
# 7.创建目录 mkdir /usr/local/fastdfs/tmp
# 8.修改/usr/local/nginx/conf/nginx.conf server { listen 8888; server_name localhost; location /zhouhong/M00 { ngx_fastdfs_module; } }
- 访问
cd /usr/local/fastdfs/storage/data/00/00 ls
十、FastDFS与SpringBoot整合实现文件上传
1、引入依赖
<dependency> <groupId>com.github.tobato</groupId> <artifactId>fastdfs-client</artifactId> <version>1.26.7</version> </dependency>
2、配置文件
############################################################ # # fdfs 配置 # ############################################################ fdfs: connect-timeout: 30 # 连接的超时时间 so-timeout: 30 # 读取的超时时间 tracker-list: 192.168.2.120:22122 # tracker服务所在的ip地址和端口号
3、FileService主要逻辑代码
@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; }
4、FileController主要逻辑代码
@RestController @RequestMapping("fdfs") public class CenterUserController { @Autowired private FileResource fileResource; @Autowired private CenterUserService centerUserService; @Autowired private FileService fdfsService; @PostMapping("uploadFace") public JSONResult uploadFace( String userId, MultipartFile file, HttpServletRequest request, HttpServletResponse response) throws Exception { String path = ""; // 开始文件上传 if (file != null) { // 获得文件上传的文件名称 String fileName = file.getOriginalFilename(); if (StringUtils.isNotBlank(fileName)) { // 文件重命名 String fileNameArr[] = fileName.split("\\."); // 获取文件的后缀名 String suffix = fileNameArr[fileNameArr.length - 1]; if (!suffix.equalsIgnoreCase("png") && !suffix.equalsIgnoreCase("jpg") && !suffix.equalsIgnoreCase("jpeg") ) { return JSONResult.errorMsg("图片格式不正确!"); } path = fdfsService.upload(file, suffix); System.out.println(path); } } else { return JSONResult.errorMsg("文件不能为空!"); } if (StringUtils.isNotBlank(path)) { String finalUserFaceUrl = fileResource.getHost() + path; //更新图片地址到数据库 Users userResult = centerUserService.updateUserFace(userId, finalUserFaceUrl); UsersVO usersVO = conventUsersVO(userResult); CookieUtils.setCookie(request, response, "user", JsonUtils.objectToJson(usersVO), true); } else { return JSONResult.errorMsg("上传头像失败"); } return JSONResult.ok(); } }
5、映射
@Component @PropertySource("classpath:file.properties") @ConfigurationProperties(prefix = "file") public class FileResource { private String host; public String getHost() { return host; } public void setHost(String host) { this.host = host; } }