FastDFS_分布式文件系统&python与fastdfs交互
一、FastDFS简介
FastDFS是一款用C语言实现的开源的轻量级分布式文件系统,功能主要包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,支持Linux、FreeBSD、MacOS等类UNIX系统。
FastDFS解决了大数据量存储和负载均衡等问题。特别适合以中小文件(建议范围:4KB < file_size <500MB)为载体的在线服务,如相册网站、视频网站等等。
FastDFS属于应用级文件系统,不是通用的文件系统,只能通过专有API访问,目前提供了C、Java和PHP API为互联网应用量身定做,解决大容量文件存储问题,追求高性能和高扩展性FastDFS可以看做是基于文件的key value pair存储系统,称作分布式文件存储服务更为合适。
FastDFS特性
- 分组存储,简单灵活
- 对等结构,不存在单点
- 文件ID由FastDFS生成,作为文件访问凭证。FastDFS不需要传统的name server或meta server
- 大、中、小文件均可以很好支持,可以存储海量小文件
- 一台storage支持多块磁盘,支持单盘数据恢复
- 提供了nginx扩展模块,可以和nginx无缝衔接
- 支持多线程方式上传和下载文件,支持断点续传
- 存储服务器上可以保存文件附加属性。
二、FastDFS架构说明
FastDFS系统由跟踪服务器(Tracker server)、存储服务器(Storage server)和客户端(Client)构成。
2.1 跟踪服务器(Tracker server)
Tracker server 主要做调度工作,起负载均衡的作用。在内存中记录集群中所有存储组和存储服务器的状态信息,但不记录文件索引信息,占用的内存量很少,是客户端和数据服务器交互的枢纽。
Tracker是FastDFS的协调者,负责管理所有的Storage server和group,每个Storage在启动后会连接Tracker,同步自己所属的group等信息,并保持周期性的心跳,tracker根据storage的心跳信息,建立group==>[storage server list]的映射表。
Tracker需要管理的元信息很少,会全部存储在内存中;另外tracker上的元信息都是由storage汇报的信息生成的,本身不需要持久化任何数据,这样使得tracker非常容易扩展,直接增加tracker机器即可扩展为Tracker cluster来服务,cluster里每个tracker之间是完全对等的,所有的tracker都接受stroage的心跳信息,生成元数据信息来提供读写服务。
2.2 存储服务器(Storage server)
Storage server 主要提供容量和备份服务,文件和文件属性(Meta Data)都保存到存储服务器上,Storage server直接利用OS的文件系统调用管理文件。 Storage server(后简称storage)以组(卷,group或volume)为单位组织,一个group内包含多台storage机器,数据互为备份,存储空间以group内容量最小的storage为准,所以建议group内的多个storage尽量配置相同,以免造成存储空间的浪费。 以group为单位组织存储能方便的进行应用隔离、负载均衡、副本数定制(group内Storage server数量即为该group的副本数),比如将不同应用数据存到不同的group就能隔离应用数据,同时还可根据应用的访问特性来将应用分配到不同的group来做负载均衡;缺点是group的容量受单机存储容量的限制,同时当group内有机器坏掉时,数据恢复只能依赖group内的其他机器,使得恢复时间会很长。 group内每个storage的存储依赖于本地文件系统,storage可配置多个数据存储目录,比如有10块磁盘,分别挂载在/data/disk1-/data/disk10,则可将这10个目录都配置为storage的数据存储目录。 storage接受到写文件请求时,会根据配置好的规则(后面会介绍),选择其中一个存储目录来存储文件。为了避免单个目录下的文件数太多,在storage第一次启动时,会在每个数据存储目录里创建2级子目录,每级256个,总共65536个文件,新写的文件会以hash的方式被路由到其中某个子目录下,然后将文件数据直接作为一个本地文件存储到该目录中。2.3 客户端(Client)
client 作为业务请求的发起方,通过专有接口,使用TCP/IP协议与跟踪器服务器或存储节点进行数据交互。FastDFS向使用者提供基本文件访问接口,比如upload、download、append、delete等,以客户端库的方式提供给用户使用。
2.4 上传流程
首先Clinet客户端请求Tracker服务获取到存储服务器的ip地址和端口,然后客户端根据返回的IP地址和端口号请求上传文件,存储服务器接收到请求后生产文件,并且将文件内容写入磁盘并返回给客户端file_id、路径信息、文件名等信息,客户端保存相关信息上传完毕。
内部机制如下:
1、选择tracker server
当集群中不止一个tracker server时,由于tracker之间是完全对等的关系,客户端在upload文件时可以任意选择一个trakcer。 选择存储的group 当tracker接收到upload file的请求时,会为该文件分配一个可以存储该文件的group,支持如下选择group的规则:
- Round robin,所有的group间轮询
- Specified group,指定某一个确定的group
- Load balance,剩余存储空间多多group优先
2、选择storage server
当选定group后,tracker会在group内选择一个storage server给客户端,支持如下选择storage的规则:
- Round robin,在group内的所有storage间轮询
- First server ordered by ip,按ip排序
- First server ordered by priority,按优先级排序(优先级在storage上配置)
3、选择storage path
当分配好storage server后,客户端将向storage发送写文件请求,storage将会为文件分配一个数据存储目录,支持如下规则:
- Round robin,多个存储目录间轮询
- 剩余存储空间最多的优先
4、生成Fileid
选定存储目录之后,storage会为文件生一个Fileid,由storage server ip、文件创建时间、文件大小、文件crc32和一个随机数拼接而成,然后将这个二进制串进行base64编码,转换为可打印的字符串。 选择两级目录 当选定存储目录之后,storage会为文件分配一个fileid,每个存储目录下有两级256*256的子目录,storage会按文件fileid进行两次hash(猜测),路由到其中一个子目录,然后将文件以fileid为文件名存储到该子目录下。
5、生成文件名
当文件存储到某个子目录后,即认为该文件存储成功,接下来会为该文件生成一个文件名,文件名由group、存储目录、两级子目录、fileid、文件后缀名(由客户端指定,主要用于区分文件类型)拼接而成。
2.5 下载机制
客户端带上文件名信息请求Tracker服务获取到存储服务器的ip地址和端口,然后客户端根据返回的IP地址和端口号请求下载文件,存储服务器接收到请求后返回文件给客户端。
跟upload file一样,在download file时客户端可以选择任意tracker server。tracker发送download请求给某个tracker,必须带上文件名信息,tracke从文件名中解析出文件的group、大小、创建时间等信息,然后为该请求选择一个storage用来服务读请求。由于group内的文件同步时在后台异步进行的,所以有可能出现在读到时候,文件还没有同步到某些storage server上,为了尽量避免访问到这样的storage,tracker按照如下规则选择group内可读的storage。
- 该文件上传到的源头storage - 源头storage只要存活着,肯定包含这个文件,源头的地址被编码在文件名中。
- 文件创建时间戳==storage被同步到的时间戳 且(当前时间-文件创建时间戳) > 文件同步最大时间(如5分钟) - 文件创建后,认为经过最大同步时间后,肯定已经同步到其他storage了。
- 文件创建时间戳 < storage被同步到的时间戳。 - 同步时间戳之前的文件确定已经同步了
- (当前时间-文件创建时间戳) > 同步延迟阀值(如一天)。 - 经过同步延迟阈值时间,认为文件肯定已经同步了。
2.6 FastDFS的FID
FastDFS的FID是客户端上传文件后存储服务器返回给客户端,用于以后访问该文件的索引信息。文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名。- 组名:文件上传后所在的存储组名称,在文件上传成功后有存储服务器返回,需要客户端自行保存。
- 虚拟磁盘路径:存储服务器配置的虚拟路径,与磁盘选项store_path*对应。
- 数据两级目录:存储服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据文件。
- 文件名:与文件上传时不同。是由存储服务器根据特定信息生成,文件名包含:源存储服务器IP地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息。
三、部署FastDFS
3.1 环境准备
2台linux7服务器:192.168.3.66/67 安装包:libfastcommon-master.zip
、fastdfs-master.zip
、nginx-1.8.1.tar.gz
、fastdfs-nginx-module-master.zip。安装包下载地址
服务器规划:tracker服务器:192.168.3.67 storage服务器:192.168.3.66
3.2 安装Fastdfs(所有服务器)
安装FastDFS和Nginx之前,需确保gcc、gcc-c++、 libstdc++-devel、make等依赖库和工具已经安装
安装libfastcommon类库
安装FastDFS必须先安装libfastcommon类库,否则会导致报错,安装步骤如下:
unzip libfastcommon-master.zip cd libfastcommon-master ./make.sh ./make.sh install
安装FastDFS
unzip fastdfs-master.zip cd fastdfs-master ./make.sh ./make.sh install
FastDFS安装好之后,在/usr/bin目录下,可以看fdfs开头的命令工具
所有配置文件全在/etc/fdfs目录下,tracker需要tracker.conf配置文件,storage需要storage.conf配置文件。
3.3 配置tracker(192.168.3.67)
创建存储数据和日志的目录mkdir -p /usr/local/fastdfs/tracker
将/etc/fdfs/tracker.conf.sample文件重命名为tracker.conf
cd /etc/fdfs
cp tracker.conf.sample tracker.conf
然后修改配置文件/etc/fdfs/tracker.conf
vi tracker.conf
base_path=/usr/local/fastdfs/tracker
配置文件中有这几个参数需要注意:
#启用配置文件 disabled=false #设置tracker的端口号 port=22122 #设置tracker的数据文件和日志目录(需手动创建) base_path=/usr/local/fastdfs/tracker #设置http端口号,默认8080 http.server_port=8080
启动tracker服务
service fdfs_trackerd start
查看端口22122是否开始监听,确认启动是否成功
也可以查看tracker的日志是否启动成功
cat /usr/local/fastdfs/tracker/logs/trackerd.log
至此,一个简单的的tracker配置就完成了,Tracker也成功启动~
如果tracker和storage部署在不同的服务器上,防火墙还需要开放22122端口
否则后面启动storage时,会报错: connect to tracker server 192.168.3.67:22122 fail, errno: 113, error info: No route to host
3.4 配置storage(192.168.3.66)
创建存储数据和日志的目录mkdir -p /usr/local/fastdfs/storage
将/etc/fdfs/tracker.conf.sample文件重命名为tracker.conf
cd /etc/fdfs
cp storage.conf.sample storage.conf
然后修改配置文件/etc/fdfs/storage.conf的base_path,store_path以及tracker的连接地址以及storage的http服务端口配置等。
主要有如下几个参数:
vi /etc/fdfs/storage.conf group_name=group1 # 组名(第一组为group1,第二组为group2,依次类推...),主要时在组集群时区分storage组 base_path=/usr/local/fastdfs/storage # 数据和日志文件存储根目录 store_path0=/usr/local/fastdfs/storage # 第一个存储目录,第二个存储目录起名为:store_path1=xxx,其它存储目录名依次类推... store_path_count=1 # 存储路径个数,需要和store_path个数匹配 tracker_server=192.168.66.67:22122 # tracker服务器IP和端口 tracker_server=192.168.66.xx:22122 # 如果是tracker集群就写多个tracker配置
启动storage服务
service fdfs_storaged start
查看端口或日志验证是否启动成功
在任意storage节点使用fdfs_monitor /etc/fdfs/storage.conf
,查看storage服务器是否已经登记到tracker服务器。
如果出现ip_addr = Active, 则表明storage服务器已经登记到tracker服务器,如下:
防火墙开放23000端口
否则上传文件时会提示
至此,tracker、storage等配置都完成并成功启动
3.5 在storage上安装nginx
注意:fastdfs-nginx-module模块只需要安装到storage上
在/usr/local/目录下解压 nginx-1.8.1.tar.gz 和 fastdfs-nginx-module-master.zip
cd /usr/local tar -zxvf nginx-1.8.1.tar.gz unzip fastdfs-nginx-module-master.zip
安装nginx
cd nginx-1.8.1 ./configure --prefix=/usr/local/nginx --add-module=/usr/local/fastdfs-nginx-module-master/src/ # 注意:--add-module的路径 make make install
注意:如果make时报错 [objs/Makefile:469: objs/src/core/ngx_murmurhash.o] Error ,打开./nginx-1.8.1/objs/Makefile文件,删除-Werror,重新执行make后的步骤即可。
安装成功,查看版本信息
/usr/local/nginx/sbin/nginx -V
配置fastdfs-nginx-module
进入fastdfs-nginx-module-master的src目录,将md_fastdfs.conf配置文件拷贝到/etc/fdfs/目录中
cd /usr/local/fastdfs-nginx-module-master/src/
cp mod_fastdfs.conf /etc/fdfs/
修改mod_fastdfs.conf配置一般只需改动以下几个参数即可:
base_path=/usr/local/fastdfs/storage #保存日志目录 tracker_server=192.168.3.67:22122 # tracker服务ip和端口 tracker_server=192.168.3.xx:22122 # 如果有多个tracker就配置多个 storage_server_port=23000 #storage服务器的端口号 group_name=group1 #当前服务器的group名 url_have_group_name=true #文件url中是否有group名 store_path_count=1 #存储路径个数,需要和store_path个数匹配 store_path0=/usr/local/fastdfs/storage #存储路径 group_count=1 #组数
在末尾增加组的具体信息
[group1] group_name=group1 storage_server_port=23000 store_path_count=1 store_path0=/usr/local/fastdfs/storage store_path1=/home/yuqing/fastdfs1
建立M00至存储目录的符号连接
ln -s /usr/local/fastdfs/storage/data /usr/local/fastdfs/storage/data/M00
配置nginx
编辑/usr/local/nginx/conf
配置文件目录下的nginx.conf,设置添加storage信息并保存。
vi /usr/local/nginx/conf/nginx.conf
将server段中的listen端口号改为8080,并在server段中添加:
location ~/group[0-9]/M00{ root /usr/local/fastdfs/storage/data; ngx_fastdfs_module; }
防火墙开放8080端口
复制 fastdfs-master解压文件目录中的onf下http.conf、mime.types文件到/etc/fdfs
至此,nginx以及FastDFS插件模块设置完成。
启动nginx
启动nginx,查看8080是否开始监听确认启动是否成功。
/usr/local/nginx/sbin/nginx
打开浏览器,直接访问http://192.168.3.66:8080,查看是否弹出nginx欢迎页面。
3.6 在tracker上安装nginx
在tracker上安装的nginx主要为了提供http访问的反向代理、负载均衡以及缓存服务。
在/usr/local/目录下解压 nginx-1.8.1.tar.gz
cd /usr/local
tar -zxvf nginx-1.8.1.tar.gz
安装nginx
cd nginx-1.8.1
./configure --prefix=/usr/local/nginx
make
make install
配置
编辑/usr/local/nginx/conf配置文件目录下的nginx.conf,设置负载均衡
vi /usr/local/nginx/conf/nginx.conf
修改下面配置
worker_processes 4; #根据CPU核心数而定 events { worker_connections 65535; #最大链接数 use epoll; #新版本的Linux可使用epoll加快处理性能 } http { #设置group1的服务器 upstream fdfs_group1 { # ip和port填写storage上部署的nginx信息 server 192.168.3.66:8080 weight=1 max_fails=2 fail_timeout=30s; } server { #设置服务器端口 listen 8080; #设置group1的负载均衡参数 location ~/group[0-9]/M00 { proxy_pass http://fdfs_group1; } } }
防火墙开放8080端口
至此,nginx设置完成。
启动nginx
启动nginx,查看8080是否开始监听确认启动是否成功。
/usr/local/nginx/sbin/nginx
打开浏览器,直接访问http://192.168.3.67:8080,查看是否弹出nginx欢迎页面。
3.7 上传图片并在浏览器查看图片
在tracker服务器上将/etc/fdfs/client.conf.sample文件重命名为client.conf
cd /etc/fdfs cp client.conf.sample client.conf
然后修改配置文件/etc/fdfs/client.conf
vi client.conf
base_path=/usr/local/fastdfs/tracker
tracker_server=192.168.3.67:22122 # tracker服务器ip和port
http.tracker_server_port=8080 # 默认80,需修改为tracker.conf配置文件中http.server_port的值
上传文件测试
fdfs_upload_file /etc/fdfs/client.conf 文件名称
如果返回类似group1/M00/00/00/wKgDQmKOQJqAafJFAADOnyAS7QE843.jpg的文件id则说明文件上传成功
因为tracker的nginx配置了反向代理,使用storage的ip或tracker的ip都可以在浏览器访问图片。
http://192.168.3.66:8080/group1/M00/00/00/wKgDQmKOQJqAafJFAADOnyAS7QE843.jpg
四、使用python上传图片
安装FastDFS的python模块
pip install fdfs-client-py3
创建fdfs_tracker.conf配置文件,添加tracker配置项
connect_timeout=30 network_timeout=60 tracker_server = 192.168.3.67:22122 # tracker节点的ip和port http.tracker_server_port = 8080 # tracker服务器上部署的nginx的端口
代码如下
from fdfs_client.client import Fdfs_client tracker_conf_path = "./fdfs_tracker.conf" # tracker配置文件的地址 client = Fdfs_client(client=tracker_conf_path) # 上传图片 ret = client.upload_by_filename("./20191023111957.png") print(ret) # 删除图片 file_id = ret["Remote file_id"] # 删除图片需要上传时返回的id ret = client.delete_file(remote_file_id=file_id.encode("utf-8")) print(ret)
执行结果如下