FastDFS

1、介绍

FastDFS是基于http协议的分布式文件系统,其设计理念是一切从简。主要解决了海量数据存储的问题,特别适合系统中的中小文件的存储和在线服务。中小文件的范围大致为4KB-500MB之间。

2、 FastDFS的组件以及工作原理

在FastDFS分布式文件存储系统中,由三种角色组成,分别是:跟踪服务器(Tracker Server)、存储服务器(Storage Server)和客户端(Client)。

  • 跟踪服务器主要是做调度工作,担负起负载均衡的作用,跟踪服务器主要负责管理所有的存储服务器,以及服务器的分组情况,存储服务器启动后会与跟踪服务器保持链接,并进行周期性的信息同步。
  • 存储服务器,顾名思义就是用于存储数据的服务器,主要提供存储容量和备份服务,存储服务器为了保证数据安全,会多台服务器组成一个组,称为group,同一个组中的数据互相备份。
  • 客户端:主要负责上传和下载文件数据,客户端所部署的机器就是实际项目部署所在的机器。

    3、文件上传过程

    image.png
    (1)存储服务器会定期向跟踪服务器发送自己的存储信息。
    (2)当跟踪服务器收到客户端上传请求时,跟踪服务器会查询可用的存储服务器信息,并将查到的信息返回给客户端。
    (3)客户端收到信息后,进行连接存储服务器,并将文件上传到存储服务器上,存储服务器生成一个文件ID,并将文件进行存储。将文件ID,组名,路径信息等返回给客户端。
    (4)客户端自行保存存储信息,下载时候需要用。

    4、文件下载过程

    image.png
    (1)存储服务器会定期向跟踪服务器发送自己的存储信息。
    (2)客户端向跟踪器发起下载请求,跟踪器查询存储器,并将存储器的信息返回给客户端
    (3)客户端连接存储器,并将文件ID,组名,路径等等信息发送给存储器。
    (4)存储器查找文件,并将文件返回给客户端。

    5、FastDFS集群

    image.png
    每个 Tracker 节点地位平等,收集 Storage 集群的状态。 工作方式是轮询。为了避免单点故障。
    实际保存文件 Storage 分为多个组,每个组之间保存的文件是不同的,每个组内部可以有多个成员,组成员内部保存的内容是一样的,组成员的地位是一致的,没有主从的概念。不同组的主机之间不通讯。

    安装FastDFS

    1、下载libfastcommon并安装

    libfastcommon是由FastDFS官方提供的软件库,其中包含了运行FastDFS所需的一些基础库。
    git clone https://github.com/happyfish100/libfastcommon.git
    下载完成以后,进入libfastcommon目录,并运行make.sh脚本进行编译
    cd libfastcommon ./make.sh
    编译完成后,进行安装
    ./make.sh install

2、下载FastDFS并安装

git clone https://github.com/happyfish100/fastdfs.git
和上面的步骤相同,进入fastdfs目录,运行make.sh脚本进行编译
cd fastdfs/ ./make.sh
编译完成后,进行安装
./make.sh install

3、配置

在配置之前,我们需要在~目录下创建一个data目录,在data目录下分别创建fastdfs以及fastdfs_storage目录。
fastdfs目录主要存放生成的一些日志文件,fastdfs_storage目录主要存放我们的文件。
.
├── fastdfs
└── fastdfs_storage
fastDFS的配置文件默认存储目录: /etc/fdfs
.
├── client.conf.sample
├── storage.conf.sample
├── storage_ids.conf.sample
└── tracker.conf.sample
我们主要配置的是 client.conf.sample, storage.conf.sample,tracker.conf.sample这三个文件,我们分别进行对其复制并改名。
cp tracker.conf.sample tracker.conf cp client.conf.sample client.conf cp storage.conf.sample storage.conf

  • 配置tracker

vim tracker.conf

bind_addr = // 追踪器对应的主机的IP地址,如果不写,会自动绑定本机的ip,如果是云服务器,空着就行 port=22122 //追踪器绑定的端口,只要是一个空闲的没有被占用的端口就可以,这里采用默认 base_path=/root/data/fastdfs //追踪器存储log日志或者一些进程文件相关的目录,对应的路径必须要存在,这里填写我们创建的目录路径 http.server_port = 80 // http服务端口改成80

  • 配置storage

vim sorage.conf

group_name=group1 #当前存储节点所属的组,横向扩容还是纵向扩容, 是通过该属性控制的 bind_addr= #存储节点的IP地址,如果不写, 会自动绑定本机IP地址 port=23000 #客户端连接存储节点是时候使用的 base_path = /root/data/fastdfs_storage #存储节点存储log日志的目录,这个目录必须存在 store_path_count=2 #存储节点上, 存储文件的路径个数,一块硬盘对应一个存储路径就可以 store_path0=/root/data/fastdfs_storage # 存储文件的具体目录 tracker_server=123.56.243.64:22122 # 连接的追踪器的地址,这里填公网的ip tracker_server=123.56.243.64:22122 #追踪去集群的声明方式

  • 配置client

base_path = /root/data/fastdfs # 客户端写日志的地方 tracker_server = 123.56.243.64:22122 # 客户端要连接追踪器的地址

4、使用

  • tracker

fdfs_trackerd /etc/fdfs/tracker.conf # 启动 fdfs_trackerd /etc/fdfs/tracker.conf stop # 停止 fdfs_trackerd /etc/fdfs/tracker.conf restart # 重启

  • storage

fdfs_storaged /etc/fdfs/storage.conf # 启动 fdfs_storaged /etc/fdfs/storage.conf stop # 停止 fdfs_storaged /etc/fdfs/storage.conf restart # 重启
追踪服务器和存储服务器启动后,我们可以使用ps命令或者netstat命令进行查看
netstat -unltp|grep fdfs

tcp 0 0 0.0.0.0:22122 0.0.0.0: LISTEN 12980/fdfs_trackerd tcp 0 0 0.0.0.0:23000 0.0.0.0: LISTEN 13515/fdfs_storaged

  • client

上传,会返回文件ID

fdfs_upload_file /etc/fdfs/client.conf 文件名 fdfs_upload_file /etc/fdfs/client.conf timg.jfif #timg.jfif是我上传的文件,返回文件ID

group1/M00/00/00/ezjzQF_DoZ6ALKrwAACT29kipjA39.jfif

group1 文件上传到哪个组

MOO store_path0

下载

fdfs_download_file /etc/fdfs/client.conf 文件ID

Nginx和fastDFS整合

1、安装Nginx

git clone https://github.com/happyfish100/fastdfs-nginx-module.git # 下载配置模块 wget -c https://nginx.org/download/nginx-1.10.1.tar.gz # 下载nginx

安装nginx之前需要安装一些依赖环境

yum install -y gcc-c++ pcre pcre-devel zlib zlib-devel openssl openssl-devel

tar -zxvf nginx-1.10.1.tar.gz # 解压安装包 cd nginx-1.10.1 ./configure —add-module=/root/fastdfs-nginx-module/src/

make && make install

安装完成后,查看版本

/usr/local/nginx/sbin/nginx -V

2、配置fastdfs-nginx-module和Nginx

进入到fastdfs-nginx-module/src目录下,将mod_fastdfs.conf复制到/etc/fdfs目录下。并修改配置项。
cp mod_fastdfs.conf /etc/fdfs/ vim /etc/fdfs/mod_fastdfs.conf

tracker_server=123.56.243.64:22122 # 修改成最终服务器的地址 storage_server_port=23000 # 存储服务器端口 url_have_group_name = true # 可以使用url进行访问 store_path0=/root/data/fastdfs_storage # 文件存储路径
拷贝http.conf和mime.types文件到/etc/fdfs目录(需要从fastdfs源码安装目录中找)
cd fastdfs/conf cp http.conf /etc/fdfs/ cp mime.types /etc/fdfs/
修改Nginx的配置文件,配置Nginx
vim /usr/local/nginx/conf/nginx.conf

user root; … server { listen 80; server_name 123.56.243.64; # 此处写公网IP,如果是虚拟机,则使用默认localhost

  1. #charset koi8-r;
  2. #access_log logs/host.access.log main;
  3. location / {
  4. root html;
  5. index index.html index.htm;
  6. }
  7. location /group1/M00 {
  8. root /root/data/fastdfs_storage; # fastDFS存储文件目录
  9. ngx_fastdfs_module; # 与fastDFS存储节点进行通信
  10. }

… }

3、启动Nginx以及测试

/usr/local/nginx/sbin/nginx # 启动nginx

fdfs_test /etc/fdfs/client.conf upload timg.jfif # 上传文件进行测试,返回url,在浏览器上访问下载

Golang与FastDFS交互

我们可以使用代码实现上传,下载,删除功能

1、安装fastdfs的golang库

go get github.com/tedcy/fdfs_client

2、编写配置文件

tracker_server=123.56.243.64:22122 maxConns=100 http_server_port=http://123.56.243.64:80
说明:tracker_server就是我们跟踪服务器的地址(必须有)
maxConns 最大连接数(必须有)
http_server_port根据自己需求,此处为了方便拼接返回值。(返回一个可以下载文件的url)

3、代码

  1. package tool
  2. import (
  3. "bufio"
  4. "fmt"
  5. "github.com/tedcy/fdfs_client"
  6. "os"
  7. "strings"
  8. )
  9. // 上传文件到fastDFS系统
  10. func UploadFile(fileName string)string{
  11. client, err := fdfs_client.NewClientWithConfig("./config/fastdfs.conf")
  12. if err != nil{
  13. fmt.Println("打开fast客户端失败",err.Error())
  14. return ""
  15. }
  16. defer client.Destory()
  17. fileId, err := client.UploadByFilename(fileName)
  18. if err != nil{
  19. fmt.Println("上传文件失败",err.Error())
  20. return ""
  21. }
  22. return fileId
  23. }
  24. // 下载文件
  25. func DownLoadFile(fileId,tempFile string){
  26. client, err := fdfs_client.NewClientWithConfig("./config/fastdfs.conf")
  27. if err != nil{
  28. fmt.Println("打开fast客户端失败",err.Error())
  29. return
  30. }
  31. defer client.Destory()
  32. if err = client.DownloadToFile(fileId,tempFile,0,0);err != nil{
  33. fmt.Println("下载文件失败", err.Error())
  34. return
  35. }
  36. }
  37. // 删除
  38. func DeleteFile(fileId string){
  39. client, err := fdfs_client.NewClientWithConfig("./config/fastdfs.conf")
  40. if err != nil{
  41. fmt.Println("打开fast客户端失败",err.Error())
  42. return
  43. }
  44. defer client.Destory()
  45. if err = client.DeleteFile(fileId);err != nil{
  46. fmt.Println("删除文件失败", err.Error())
  47. return
  48. }
  49. }
  50. // 从配置文件中读取服务器的ip和端口配置
  51. func FileServerAddr() string{
  52. file,err := os.Open("./config/fastdfs.conf")
  53. if err != nil{
  54. fmt.Println(err)
  55. return ""
  56. }
  57. reader := bufio.NewReader(file)
  58. for{
  59. line, err := reader.ReadString('\n')
  60. line = strings.TrimSpace(line)
  61. if err != nil{
  62. return ""
  63. }
  64. line = strings.TrimSuffix(line,"\n")
  65. str := strings.SplitN(line,"=",2)
  66. switch str[0] {
  67. case "http_server_port":return str[1]
  68. }
  69. }
  70. }

Python与FastDFS交互

说明:Python与FastDFS交互是在Django框架下完成。

1、安装fastdfs库

pip install fdfs-client-py==1.2.6

2、修改setting.py文件

设置Django的文件存储类

DEFAULT_FILE_STORAGE = ‘utils.fdfs.storage.FDFSStorage’ # 具体以路径以及类名为主

设置fdfs使用的client.conf文件路径

FDFS_CLIENT_CONF = ‘./utils/fdfs/client.conf’ # 请根据自己实际路径编写

设置fdfs存储服务器上nginx的IP和端口号

FDFS_URL = ‘http://123.56.243.64:80

3、编写client配置文件

  1. # connect timeout in seconds
  2. # default value is 30s
  3. connect_timeout=30
  4. # network timeout in seconds
  5. # default value is 30s
  6. network_timeout=60
  7. # the base path to store log files
  8. base_path=E:\Pesticide\utils\fdfs
  9. # tracker_server can ocur more than once, and tracker_server format is
  10. # "host:port", host can be hostname or ip address
  11. tracker_server=10.35.166.81:22122
  12. #standard log level as syslog, case insensitive, value list:
  13. ### emerg for emergency
  14. ### alert
  15. ### crit for critical
  16. ### error
  17. ### warn for warning
  18. ### notice
  19. ### info
  20. ### debug
  21. log_level=info
  22. # if use connection pool
  23. # default value is false
  24. # since V4.05
  25. use_connection_pool = false
  26. # connections whose the idle time exceeds this time will be closed
  27. # unit: second
  28. # default value is 3600
  29. # since V4.05
  30. connection_pool_max_idle_time = 3600
  31. # if load FastDFS parameters from tracker server
  32. # since V4.05
  33. # default value is false
  34. load_fdfs_parameters_from_tracker=false
  35. # if use storage ID instead of IP address
  36. # same as tracker.conf
  37. # valid only when load_fdfs_parameters_from_tracker is false
  38. # default value is false
  39. # since V4.05
  40. use_storage_id = false
  41. # specify storage ids filename, can use relative or absolute path
  42. # same as tracker.conf
  43. # valid only when load_fdfs_parameters_from_tracker is false
  44. # since V4.05
  45. storage_ids_filename = storage_ids.conf
  46. #HTTP settings
  47. http.tracker_server_port=80
  48. #use "#include" directive to include HTTP other settiongs
  49. ##include http.conf

4、代码

  1. from django.core.files.storage import Storage
  2. from django.conf import settings
  3. from fdfs_client.client import Fdfs_client
  4. class FDFSStorage(Storage):
  5. '''fast dfs文件存储类'''
  6. def __init__(self, client_conf=None, base_url=None):
  7. '''初始化'''
  8. if client_conf is None:
  9. client_conf = settings.FDFS_CLIENT_CONF
  10. self.client_conf = client_conf
  11. if base_url is None:
  12. base_url = settings.FDFS_URL
  13. self.base_url = base_url
  14. def _open(self, name, mode='rb'):
  15. '''打开文件时使用'''
  16. pass
  17. def _save(self, name, content):
  18. '''保存文件时使用'''
  19. # name:你选择上传文件的名字
  20. # content:包含你上传文件内容的File对象
  21. # 创建一个Fdfs_client对象
  22. client = Fdfs_client(self.client_conf)
  23. # 上传文件到fastdfs系统中
  24. res = client.upload_by_buffer(content.read())
  25. # dict
  26. # {
  27. # 'Group name': group_name,
  28. # 'Remote file_id': remote_file_id,
  29. # 'Status': 'Upload successed.',
  30. # 'Local file name': '',
  31. # 'Uploaded size': upload_size,
  32. # 'Storage IP': storage_ip
  33. # }
  34. if res.get('Status') != 'Upload successed.':
  35. # 上传失败
  36. raise Exception('上传文件到fast dfs失败')
  37. # 获取返回的文件ID
  38. filename = res.get('Remote file_id')
  39. return filename
  40. def exists(self, name):
  41. '''Django判断文件名是否可用'''
  42. return False
  43. def url(self, name):
  44. '''返回访问文件的url路径'''
  45. return self.base_url+name