最近公司业务要做了一个报表管理系统,这就涉及到了海量文件存储问题。对于文件存储来说,一般情况下简单的处理就是在Django配置文件中配置存储目录,按照规则对文件进行上传或者下载。
实际上,当文件较少的时候,Django是可以应付的过来的。但当文件以海量形式出现的时候,Django就并不是那么好用了,于是Fast DFS应运而出。
FastDFS是一个开源的分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。可以说它就是为互联网而生,为大数据而生的。
FastDFS服务端有两个角色:跟踪器(tracker)和存储节点(storage)。跟踪器主要做调度工作,在访问上起负载均衡的作用。 存储节点存储文件,完成文件管理的所有功能:存储、同步和提供存取接口,FastDFS同时对文件的meta data进行管理。跟踪器和存储节点都可以由多台服务器构成。跟踪器和存储节点中的服务器均可以随时增加或下线而不会影响线上服务。其中跟踪器中的所有服务器都是对等的,可以根据服务器的压力情况随时增加或减少。
用FastDfs的理由:
1 解决海量存储,同时存储容量扩展方便。
2 解决文件内容重复,如果用户上传的文件重复(文件指纹一样),那么系统只有存储一份数据,值得一提的是,这项技术目前被广泛应用在网盘中。
3 结合Nginx提高网站读取图片的效率。
如果我们从头搭建fastdfs服务器那么就太low了,网上有大把的docker镜像供你选择,所以又到了利用docker优越性的时候了。
1、下载fastdfs镜像
sudo docker pull delron/fastdfs
2、查看下载好的镜像
sudo docker images
区区四百多兆就承载了nginx和fastdfs服务
3、然后使用docker镜像构建tracker容器(跟踪服务器,起到调度的作用),这里tracker服务将会自动映射到宿主机上
docker run -d --network=host --name tracker -v /root:/var/root delron/fastdfs tracker
使用docker镜像构建storage容器(存储服务器,提供容量和备份服务),这里storage容器需要依赖tracker服务,传入你的tracker服务的ip地址,端口默认是22122,ip地址也就是你宿主机的ip
docker run -d --network=host --name storage -e TRACKER_SERVER=192.168.99.100:22122 -v /root:/var/root -e GROUP_NAME=group1 delron/fastdfs storage
此时,命令行输入 sudo docker ps 就可以看到两套服务都已经启动
4、这时已经部署完成,我们进入正在后台运行的storage容器,测试一下
sudo docker exec -it storage /bin/bash
随便下载一张图片,这个不用担心,因为在容器中如果不提交仓库的话,该图片是不会保存的
wget https://upload-images.jianshu.io/upload_images/11693390-a26b21909429f7d2.png
5、 将该图片通过命令上传到分布式系统中
/usr/bin/fdfs_upload_file /etc/fdfs/client.conf 11693390-a26b21909429f7d2.png
这时该图片已上传至文件系统,并在执行该语句后返回图片存储的网络地址
最后通过浏览器访问以下存储在Fastdfs的图片,这张图片是通过nginx代理的静态资源,默认nginx监听8888端口,所以需要加上端口号,如果是在阿里云上部署,则需要暴露外部端口8888
可以看到,没有任何问题,同理,如果是视频资源,同样可以上传到fastdfs中,搞定。
至此,在宿主机中上传文件已经搞定,而python同样也可以在命令行中执行命令,我们可以从命令中得到URL的做法来实现django与fastdfs的交流,这里利用的是python中的os.popen方法,可以非常简单的在命令行中获取返回的fastdfs网络地址,从而避开了必须要安装fastdfs的python客户端,因为该客户端对python3并不十分友好。代码如下:
import os
import re
std = os.popen("docker exec -i storage /usr/bin/fdfs_upload_file /etc/fdfs/client.conf /var/root/test.mp4").read()
print('*********** fastdfs excute start ***********')
print(std.strip())
print('*********** fastdfs excute end ***********')
这样,在django中上传文件时,就可以通过命令的方式上传到fastdfs中,获取返回地址后入库就可以了。