从零开始使用FastDFS搭建个人文件存储服务器

从零开始使用FastDFS搭建个人文件存储服务器

前言:
本文初衷是想搭建个人文件存储服务器, 解决方案有阿里云OSS对象存储服务,有NextCloud等私有网盘搭建,尝试过nextcloud之后, 决定尝试一下FastDFS搭建自己的文件存储服务器

技术点:

  • 硬件方面: 使用一台 Raspberry 4b作为服务器
  • 系统: 使用 Raspberry 量身定制的 基于Debian的Raspbian操作系统
  • 软件: 使用FastDFS分布式文件存储系统搭建
  • 网络: 使用FRP内网穿透解决无公网ip问题

关于本文使用的一些东西:

图床:图片上传后长时间不使用会不显示,需要重新打开后才能正常显示,这也是本文中图片有时候不显示的原因,
FDM下载工具
Xshell
Xftp

服务器系统准备:

以raspberry 4b为例

  • 下载raspbian系统镜像(raspbian官方镜像)

    贴一个raspberry系统站, 包含了大部分raspberry可用镜像
  • 下载zip压缩包解压后为img镜像文件(本次选择的是2019-07-10那一版)1569128711_1_.png
  • 解压完成之后,使用SDFormart格式化工具格式化一张不小于8G的SD卡(作为raspberry系统盘使用,推荐为U3 Class10高速卡)
    1569128871_1_.png
  • 格式化完成之后,再使用deskImager将镜像烧录到SD卡中
    1569129009_1_.png
    1569129311_1_.png
  • 接入显示屏,开机
    0e1880e9cccf367813392f685e994ce.jpg
  • 由于raspbian默认分辨率较高,需要修改分辨率
    显示屏驱动, 修改分辨率
    分辨率设置完成等待重启,根据系统提示设置基本信息(归属地,语言,密码,wifi等)
  • 开启ssh服务
    由于raspbian-bluster版本系统默认安装了ssh服务,因此只需要设置为开机自启即可
    插上键盘,ctrl+alt+t打开命令行,修改开机启动配置文件
sudo nano /etc/rc.local

在exit0上一行输入/etc/init.d/ssh start然后crtl+o,回车保存,ctrl+x退出

/etc/init.d/ssh start
exit0

重启raspberry,查看raspberry的ip地址,使用ssh远程连接进行操作(raspberry默认账户为pi,密码为之前设置的密码)

  • 修改系统源为国内源,解决官方源下载速度过慢问题
    1.安装vim编辑器sudo apt-get install vim 按提示键入Y进行安装
sudo apt-get install vim

2.进入源文件目录

cd /etc/apt

3.修改源文件权限为可读可写可执行
sudo chomd 777 source.list

sudo chomd 777 source.list

4.编辑源文件
vim /etc/apt/source.list

vim /etc/apt/source.list

5.按y进入编辑模式,将默认的源信息注释掉,并写入buster版本的国内源(此处为中科大源):

deb http://mirrors.ustc.edu.cn/raspbian/raspbian/ buster main contrib non-free rpi

6.esc退出编辑模式,shift+zz保存退出
7.重启,然后更新软件源信息:
sudo apt-get update

sudo apt-get update

8.更新软件至最新版本:
sudo apt-get upgrade

sudo apt-get upgrade

本次使用的fastdfs相关包

###内网穿透准备
frp是一种利用处于内网或防火墙后的机器,对外网环境提供http或https服务的技术
市面上知名的的有花生壳等提供商, 也有公益性的Sakura Frp提供内网穿透服务, 也可以自行使用frp软件配合有公网ip的服务器搭建穿透服务.
本次采用frp开源软件配合阿里云ECS服务器搭建穿透服务:raspberry做frp客户端,云服务器做frp服务端

  • frp穿透有多种方式: 为保证稳定性, 不使用点对点穿透, 流量经服务器转发

  • 下载客户端frp(raspberry使用arm版)和服务端frp(根据使用的云服务器版本选择,本次使用的云服务器为amd64位)
    frp客户端下载地址
    image.png

  • 先配置服务端frp

  1. 使用xftp将客户端传到云服务器,或者使用wget命令直接下载客户端到云服务器
  2. 解压frp软件,删除frpc、frpc_full.ini和frpc.ini三个客户端文件
sudo tar -zxvf frp_0.29.0_linux_amd64.tar
sudo rm -rf frpc frpc.ini frpc_full.ini
  1. frps.init默认配置端口为7000,可以不修改, 如需加密,可以配置用于frp客户端连接的秘钥
  2. 启动服务端(此命令意思是根据frps.init配置文件启动frps服务端)
./frps -c frps.ini

image.png
可以看到frp服务端启动成功

  • 配置客户端frp
  1. 使用xftp将客户端传到raspberry,或者使用wget命令直接下载客户端到raspberry
    image.png
  2. 解压客户端
sudo tar -zxvf frp_0.29.0_linux_arm.tar.gz
  1. 首先,删除frps、frps.ini和frps_full.ini三个服务端文件,表明这是一个客户端frp
sudo rm -rf frps frps.ini frps_full.ini

image.png
FRP 默认也给出两个客户端配置文件,一个是简版的 frpc.ini,另一个是完整版本 frpc_full.ini
4. 然后编辑frpc.ini文件
(端口保持与服务端端口一致,我的理解是服务端与客户端通过common配置中的7000端口进行通信和代理, 而ssh配置中则指定服务端6000端口映射到客户端的22端口)

vim frpc.ini

image.png
其中设置6000端口为访问客户端ssh的端口,即通过服务端的6000端口可以访问客户端的22端口(因此还要在云服务器控制台开启6000端口),如果frp服务端配置了秘钥,则客户端也需要配置秘钥
5. 启动frp客户端

./frpc -c frpc.ini

image.png
可以看到,frp客户端启动成功
6. 测试穿透
image.png
可以看到,通过云服务器的6000端口成功ssh到raspberry客户端

  • 使用screen将服务端和客户端的穿透服务作为后台窗口
  • 由于ssh窗口的即时性,一旦关闭当前ssh窗口,通道中断后,此通道正在进行的服务都会终止,因此需要screen解决这一问题
  1. 客户端和服务端安装screen
sudo apt-get install screen
  1. 创建窗口
    screen -S 自定义一个服务名称
    这里使用的是screen -S frp
screen -S frp

当需要切换回这个服务窗口时,使用screen -r 服务名
3. 在创建的frp窗口中打开frp服务
客户端:
切换到frp安装目录,执行./frpc -c frpc.ini

./frpc -c frpc.ini

服务端:
切换到frp安装目录.执行./frps -c frps.ini

./frps -c frps.ini
  1. 此时,即使关闭ssh窗口,frp服务也不会中断
  • 设置frp开机自启
    服务器端(阿里云服务器):
    1.在/lib/systemd/system/目录下创建开机启动脚本frps.service
sudo vim /lib/systemd/system/frps.service

2.写入脚本内容
image.png
3.重新加载systemctl配置文件

sudo systemctl daemon-reload

4.将创建的frps.service设为开机自启

sudo systemctl enable frps

客户端(raspberry):
1.在/lib/systemd/system/目录下创建开机启动脚本frpc.service

sudo vim /lib/systemd/system/frpc.service

2.写入脚本内容, 由于raspberry使用wifi,网卡在系统之后, 因此需要等待时间

[Unit]
Description=frpc service
After=network.target network-online.target syslog.target
Wants=network.target network-online.target
[Service]
Type=simple
#启动之前先等待一分钟
ExecStartPre=sleep 60
#启动服务的命令 frps的实际安装目录
ExecStart=/zack/frp/frp_0290_linux_arm/frpc -c /zack/frp/frp_0290_linux_arm/frpc.ini
[Install]
WantedBy=multi-user.target

3.重新加载systemctl配置文件

sudo systemctl daemon-reload

4.将创建的frpc.service设为开机自启

sudo systemctl enable frpc

FastDFS

  • FastDFS:
    淘宝设计开发的开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站、新闻网站(文字+图片 图文分离:图,文件系统中)等等
  • 使用FastDFS的优点:
    fastdfs的tracker server(跟踪服务器, 用于负载均衡,将文件平均存储到存储服务器)和storage server(存储服务器) 的集群策略和组策略决定了它不会出现单点故障;
    相比文件存储在tomcat中,fastdfs可以扩容,响应速度更快(直接请求文件服务器,对tomcat等容器压力更小)
  • FastDFS架构:
    image.png
    由图可知,它有两个角色:tracker server 和storage server, 不需要存储文件索引信息;
    tracker之间完全平级,storage之间完全平级;
    每个storage都分组,每组内的存储服务器存储内容完全一致,但不存在主从关系,其存储能力由组内下限决定(磁盘最小的服务器);
    storage的每个组之间不存在联系, tracker之间也不存在联系, 由storage server主动向tracker server报告信息;
  • 其文件上传流程:
    客户端询问tracker server,获取某个storage组中的一台可用的存储服务器, 客户端直接和此存储服务器通信,完成文件上传,存储服务器返回此文件的id
  • 其文件下载流程:
    客户端询问tracker server 要下载的文件的存储服务器(参数为上传完成时存储服务器返回的id), tracker server 返回存储此文件的storage组中的一台可用的存储服务器, 客户端直接和此服务器通信,完成下载;

FastDFS的安装:

进入一个目录

cd /zack/fastdfs

下载文件:
fastdfs三个安装文件:libfastcommon, fastdfs, fastdfs-nginx-module

wget https://github.com/happyfish100/libfastcommon/archive/V1.0.39.tar.gz -SO libfastcommon.tar.gz
wget https://github.com/happyfish100/fastdfs/archive/V5.11.tar.gz -SO fastdfs.tar.gz
wget https://github.com/happyfish100/fastdfs-nginx-module/archive/V1.20.tar.gz -SO fastdfs-nginx-module.tar.gz

下载完成之后,解压这三个文件

tar -zxvf 文件名.tar.gz
  • 安装libfastcommon:
cd /zack/fastdfs/libfastcommon-1.0.39/
sudo ./make.sh
sudo ./make.sh install
  • 安装fastdfs:
    本次使用一台服务器即作为tracker server, 又作为storage server, 为单机版(集群版一般tracker和storage分布于不同服务器)
cd /zack/fastdfs/fastdfs-5.11/
sudo ./make.sh
sudo ./make.sh install

安装完成之后,查找安装目录

sudo which fdfs_trackerd
/usr/bin/fdfs_trackerd

可以看到,fastdfs安装在/usr/bin/目录下
除此之外, 一般情况下, fastdfs的配置文件位于/etc/fdfs/目录下

ls /etc/fdfs\nclient.conf.sample storage_ids.conf.sample  tracker.conf.sample storage.conf.sample

这些配置文件并不全, 需要从解压目录复制配置文件到这里

sudo cp /zack/fdfs-package/fastdfs-5.11/conf/* /etc/fdfs/

修改tracker server配置文件

# 修改base_path的下载,并保证这个目录已存在
base_path=/zack/fdfs/FastDFS_Data/
# HTTP port on this tracker server
# 修改此tracker server的端口号
http.server_port=9270

修改storage server配置文件

# 修改base_path的下载路径,并保证这个目录已存在
base_path=/zack/fdfs/FastDFS_Data/
# 修改store_path0的上传路径,并保证此目录已存在
store_path0=/zack/fastdfs/FastDFS_Data
# 修改storage server的ip,由于此storage server和tracker server 处于同一台服务器,ip相同,只能填写此ip所在的局域网ip
tracker_server=192.168.1.3:22122

修改client配置文件

# 修改base_path的下载路径,并保证这个目录已存在
base_path=/zack/fdfs/FastDFS_Data/
# 同样,修改client的ip
tracker_server=191.168.1.3:22122
# 给client指定此client使用的tracker的端口
http.tracker_server_port=9270

启动tracker server

sudo /etc/fdfs/fdfs_trackerd /etc/fdfs/tracker.conf start
# 或者使用sudo service fdfs_trackerd start

启动storage server

sudo /etc/fdfs/fdfs_storaged /etc/fdfs/storage.conf start
# 或者使用sudo service fdfs_storaged start

查看启动日志,检查是否启动成功

# 检查tracker启动情况
sudo tail /zack/fastdfs/FastDFS_Data/logs/trackerd.log
# 检查storage启动情况
sudo tail /zack/fastdfs/FastDFS_Data/logs/storaged.log
# 或者使用sudo netstat -unltp|grep fdfs检查fdfs的tracker和storage启动情况

测试上传文件,可以看到上传成功之后,tracker server 会返回一个文件下载地址, 由于此时还没有配置nginx,还无法下载(fastdfs的group内进行备份的机制决定了它不能直接下载,避免组内同步未完成造成无法下载)

# 上传一个/zack/fastdfs/目录下的压缩包试一下
sudo /usr/bin/fdfs_upload_file /etc/fdfs/client.conf /java/fastdfs/fastdfs.tar.gz
# 可以看到返回一个地址group1/M00/00/00/wKgBC12XFRuAWctbAAUkK6yqBFI.tar.gz

设置tracker server 和storage server开机自启

sudo vim /etc/rc.local
# 在exit0上一行添加内容:
service fdfs_trackerd start
service fdfs_storaged start
cd /zack/fastdfs
sudo tar -zxvf nginx-1.12.0.tar.gz

由于安装nginx需要依赖ssl,zlib和pcre,因此需要先安装这些依赖

sudo apt-get install openssl libssl-dev
sudo apt-get install libpcre3 libpcre3-dev
sudo apt-get install zlib1g-dev

再解压fastdfs-nginx-module安装包

cd /zack/fastdfs
sudo tar -zxvf fastdfs-nginx-module-1.20.tar.gz

将fastdfs-nginx-module添加为ngnix组件

cd /zack/fastdfs/ngnix-1.12.0/
sudo ./configure --prefix=/usr/local/nginx --add-module=/zack/fastdfs/fastdfs-nginx-module-1.20/src

等待添加完成之后,开始编译

cd /zack/fastdfs/nginx-1.12.0/
sudo make\nsudo make install

如果编译过程中报错all warnings being treaded as errors, 说明编译规则过于严格,将警告作为错误进行处理了, 解决办法: 修改ngnix目录下的objs/MakeFile文件,将CFLAGS中的-Werror去除,然后重新编译ngnix
开始配置nginx
nginx默认安装路径为/usr/local/nginx

# 修改nginx的配置文件
cd /usr/local/nginx/conf/
sudo vim nginx.conf
# 在server项中添加新的localtion
server {
        # 修改nginx监听端口为80
        listen       80;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }
        # 添加location配置
        location /group1/M00 {
            # 指定文件存储位置
            root /zack/fastdfs/FastDFS_Data/data;
            ngx_fastdfs_module;
        }

进入fastdfs的解压目录, 复制http.conf和mime.types拷贝到/etc/fdfs目录下

sudo cp /zack/fastdfs/fastdfs-5.11/conf/http.conf /etc/fdfs/
sudo cp /zack/fastdfs/fastdfs-5.11/conf/mime.types /etc/fdfs/

修改fastdfs-nginx-module配置文件

cd /zack/fastdfs/fastdfs-nginx-module-1.20/src/
sudo vim mod_fastdfs.conf
# 修改配置内容
base_path=/zack/fastdfs/FastDFS_Data/
tracker_server=192.168.1.3:22122
url_have_group_name = true
store_path0=/zack/fastdfs/FastDFS_Data/

复制此配置文件到/etc/fdfs/目录下

sudo cp /zack/fastdfs/fastdfs-nginx-module-1.20/src/mod_fastdfs.conf /etc/fdfs

启动nginx

sudo /usr/local/nginx/sbin/nginx

访问之前上传图片后tracker返回的地址(由于nginx监听80端口转发/group1/M00的请求,所以需要填写完整路径)

http://192.168.1.3/group1/M00/00/00/wKgBB12OFR6AdeQHAAUkK6yqBFI_big.jpg

如果直接访问raspberryip地址192.168.1.3可以看到nginx页面,但是访问文件地址404,检查配置tracker,storage,client,fastdfs-nginx-module以及nginx配置文件是否正确,如果检查无误,查看/usr/local/nginx/logs/目录下的nginx日志文件,检查是否为nginx转发错误.
至此,已经可以进行文件上传和下载,但是上传还是以命令行进行上传

编写fastdfs的java客户端, 使用web页面上传

  • 创建springboot工程,引入fdfs依赖
<dependency>
      <groupId>org.csource.fastdfs</groupId>
      <artifactId>fastdfs</artifactId>
      <version>1.2</version>
</dependency>
  • 创建fdfs_client.conf配置文件,配置tracker server的地址信息```markdown
    tracker_server=192.168.1.3:22122
- 编写文件上传逻辑
```java
public String uploadFile(MultipartFile file) {
        try {
            // 获取上传文件的字节数组
            byte[] bytes = file.getBytes();
            // 取文件后缀名
            String fileType = "";
            // 排除tar.gz压缩包文件 (todo 排除其他特殊类型文件)
            if (originalFilename.endsWith(".tar.gz")) {
                fileType = "tar.gz";
            } else {
                // 非tar.gz文件,截取后缀名
                int i = originalFilename.lastIndexOf(".");
                if (i != -1) {
                    fileType = originalFilename.substring(i + 1);
                }
            }
            // 初始化fdfs_client.conf配置文件路径
            ClientGlobal.init("fdfs_client.conf配置文件地址");
            // 创建跟踪服务器客户端
            TrackerClient trackerClient = new TrackerClient();
            // 根据跟踪服务器客户端创建跟踪服务器
            TrackerServer trackerServer = trackerClient.getConnection();
            // 创建存储服务器客户端
            StorageClient1 storageClient1 = new StorageClient1();
            // 上传文件
            String filePath = storageClient1.upload_file1(bytes, fileType, null);

	    // 上传成功,返回文件的地址
            return filePath;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("文件上传失败");
            return "ERROR";
        }
    }

测试fastdfs文件存储服务器上传和下载

image.png

  • 可以看到, 上传成功后, 得到文件存储路径
    image.png
  • 可以直接访问到此文件
    image.png

将文件存储服务器穿透到公网

  • 到此为止,fastdfs文件存储服务器搭建完成, 但是只能在此局域网内访问,需要frp穿透到公网提供服务
  • 编辑阿里云服务器上的frps.ini服务端配置文件
root@iZbp19avc72hef0pmt4u02Z:~# cd /java/frp/frp_0290_linux_amd64/
root@iZbp19avc72hef0pmt4u02Z:/java/frp/frp_0290_linux_amd64# sudo vim frps.ini 

添加http穿透服务端点6001, 如需加密,可以在这里指定秘钥,用于frp客户端连接使用

[common]bind_port = 7000
#访问内网web服务的公网端口
vhost_http_port = 6001
  • 编辑用于搭建fastdfs的raspberry 4b上的frpc.ini客户端配置文件
pi@raspberrypi:$ cd /zack/frp/frp_0290_linux_arm/
pi@raspberrypi:/zack/frp/frp_0290_linux_arm $ sudo vim frpc.ini 

其中,
一个web服务用于文件上传,以jar包形式部署在raspberry 81端口,frp穿透访问域名为file.zack.net.cn,端口为frp服务端指定的6001
一个web服务用于文件下载,以nginx转发的形式监听raspberry 80端口,frp穿透访问域名为www.zack.net.cn,端口为frp服务端指定的6001
image.png

  • 重启服务端和客户端的frp服务即可

待优化:

  • todo
    由于采用tcp穿透,文件上传下载速度受限于阿里云服务器带宽(流量经阿里云服务器转发), 待采用xtcp模式进行p2p穿透,可跳过frp服务端带宽限制,由fastdfs所在服务器带宽和使用者的带宽决定
  • todo
    文件上传添加hash校验, 同一文件不再重复上传,直接返回此文件地址