首先得知道分布式文件系统的概念,一般的文件系统,比如一台windows主机下的C盘、D盘、F盘,他们构成一个文件系统。而分布式文件系统的全部,不在一台主机上,分布在很多主机上。主机的个数可以无限增加。

  fastDFS是分布式文件系统中的一种。他是一个开源的分布式文件系统,可以在github下载;大的方面来说,fastDFS由客户端和服务器两大部分组成。客户端(client)通常指我们写的程序,目前fastDFS提供了像C、JAVA、PHP等语言的API用来访问文件系统。而服务器由追踪器(tracker)和存储结点(storage)组成。以上客户端(client)、追踪器(tracker)、存储结点(storage)就是FastDFS里的三大角色。

  追踪器(tracker)主要用来记录存储结点(storage)中状态信息,是客户端和存储结点通信的媒介。因为相关信息都存储在内存中,所以tracker的性能很高,一个tracker足以调度一个较大的集群。存储结点(storage)用来完成文件管理,包括文件存储、文件同步(冗余备份)、文件访问。

  他们三者之间的关系:storage和client主动连接tracker,storage连接tracker单独开启一个线程,是为了向它汇报当前这个存贮节点剩余的空间多大、存储了哪些文件;client想要上传或者下载文件的时候它并不知到存储节点的IP地址,需要连接tracker,比如:如果客户端上传文件,tracker会找到一个有足够空间的存储节点,并把IP和端口返回给client,client根据这个地址结构去连接storage,然后把要上传的文件上传到这个storage中。

  这个三个角色可以部署在多台主机上,也可以部署在一台主机上。

  fastDFS的一些配置:

  默认配置文件的位置:/etc/fdfs

    1、tracker配置文件:   

1 bind_addr=192.168.31.119       //当前主机的IP
2 
3 port=22122         //绑定端口
4 
5 base_path=/home/kitty/fastDFS/tracker    //存放log日志

      启动tracker,fdfs_trackerd在/usr/bin/下 

1 sudo fdfs_trackerd   /etc/fdfs/tracker.conf        
2 
3 sudo fdfs_trackerd  /etc/fdfs/racker.conf   restart    //重启
4 
5 sudo fdfs_trackerd  /etc/fdfs/racker.conf   stop   //停止服务

    2、storage的配置文件

 1 group_name=group1 
 2  #存储节点所属的组
 3 bind_addr=192.168.31.119
 4 #存储节点绑定的IP
 5 port=23000
 6 #绑定的端口
 7 base_path=/home/kitty/fastDFS/storage
 8 #存储日志文件的目录
 9 store_path_count=1 
10 #存储目录的个数
11 store_path0=/home/kitty/fastDFS/storage
12 #配置具体的存储目录
13 tracker_server=192.168.31.119:22122
14 #连接tracker的时候使用的IP和端口

    storage服务的启动

1 sudo fdfs_storaged /etc/fdfs/storage.conf
2 sudo fdfs_storaged /etc/fdfs/storage.conf  restart
3 sudo fdfs_storaged /etc/fdfs/storage.conf  stop

    查看tracker和storage是否启动成功

    3、客户端配置文件

1 base_path=/home/kitty/fastDFS/client
2 #log日志目录
3 tracker_server=192.168.31.119:22122
4 #连接tracker时候需要的iP和端口信息  

   fastDFS的上传流程:

fastDFS的下载流程

 

  以上程序都完成后,可以用命令测试是否能成功上传文件:

  “group1/M00/00/00/wKgfd19zXJOAGU8rAAAAXdwKmQY729.rdb”是命令执行的结果,group1是组名,M00是磁盘虚拟路径,对应storag.conf中base_path=/home/kitty/fastDFS/storage,00/00 是二级目录 , 存储上传文件的目录。          wKgfd19zXJOAGU8rAAAAXdwKmQY729.rdb是文件名。

  下载

  删除:

  在fastDFS的软件包中有上传的示例程序和API,以下是修改后的程序:

 1 //main.c
 2 #include"stdio.h"
 3 #include"stdlib.h"
 4 #include"fdfs_api.h"
 5  
 6 int main(int argc,char* argv[])
 7  {
 8    char fileid[1024];
 9    fdfs_upload_file("/etc/fdfs/client.conf",argv[1],fileid);
10    printf("fifleID=%s\n",fileid);
11  }
12    
//.h
  1 #ifndef _FDFS_API_H_
  2 #define _FDFS_API_H_
  3 int fdfs_upload_file(const char*,const char*,char*);
  4 #endif
          
  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 #include<errno.h>
  5 #include<sys/types.h>
  6 #include<sys/stat.h>
  7 #include"fdfs_client.h"
  8 #include"logger.h"
  9 int fdfs_upload_file(const char*conf_file,const char*local_file,char* fileid )
 10 {
 11     char group_name[FDFS_GROUP_NAME_MAX_LEN+1];
 12     ConnectionInfo *pTrackerServer;//追踪器指针
 13     int result;
 14     int store_path_index;            //存储路径
 15     ConnectionInfo storageServer;   //存储器
 16 
 17 
 18 
 19     if ((result=fdfs_client_init(conf_file)) != 0)//通过客户端的配置文件初始化一些信息
 20     {
 21         return result;
 22     }
 23     //通过配置文件中的信息,去连接追踪器,得到一个地址
 24     //访问追踪器
 25     pTrackerServer = tracker_get_connection();
 26     if (pTrackerServer == NULL)//失败
 27     {
 28         fdfs_client_destroy();
 29         return errno != 0 ? errno : ECONNREFUSED;
 30     }
 31 
 32     *group_name = '\0';
 33     //通过追踪器得到可用的存储节点信息
 34     if ((result=tracker_query_storage_store(pTrackerServer,\
 35                     &storageServer,group_name,&store_path_index))!=0)
 36     {
 37         fdfs_client_destroy();
 38         fprintf(stderr,"strcker_query_storage fail,"\
 39                 "error no:%d,error info:%s\n",
 40                 result,STRERROR(result));
 41         return result;
 42     }
          //开始上传,得到一个fileid
 43     result=storage_upload_by_filename1(pTrackerServer,\
 44             &storageServer,store_path_index,\
 45             local_file,NULL,\
 46             NULL,0,group_name,fileid
 47             );
 48     if(0==result)
 49     {
 50         printf("%s\n",fileid);
 51     }
 52     else
 53     {
 54         fprintf(stderr,"upload fifle fail,"\
 55                 "error no :%d,error info:%s\n",\
 56                 result ,STRERROR(result)
 57                 );
 58     }
 59     tracker_disconnect_server_ex(pTrackerServer,true);//和tracker断开连接
 60     fdfs_client_destroy();
 61 
 62     return result;
 63 
 64 }

   还可以通过管道的方法,实现文件的上传

 1 //filename是要上传的文件名,fileid是传入参数,上传后得到的文件ID
 2  void upload_to_storage(char *filename,char *fileid)
 3  {
 4      pid_t pid;
 5      int fd[2];
 6      //创建管道
 7      int ret = pipe(fd);
 8      if(ret==-1)
 9      {
10          perror("pipe error\n");
11          exit(1);
12      }
13      //创建子进程
14      pid = fork();
15      if(pid<0)
16      {
17          perror("fork error\n");
18          exit(1);
19      }
20      else if(pid==0)  //子进程关闭读端
21      {
22          close(fd[0]);
23          dup2(fd[1],STDOUT_FILENO); //把标准输出重定向给管道的写端
24          //开始执行上传操作
25          execlp("fdfs_upload_file","fdfs_upload_file","/etc/fdfs/client.conf",filename,NULL);
26          close(fd[1]); //关闭写端
27      }
28      else  //父进程关闭写端
29      {
30          close(fd[1]);
31          read(fd[0],fileid,255);  //从管道读端写数据,写到fileid中
32          wait(NULL); //回收子进程
33          close(fd[0]);
34     }
35  }

   FastDFS的集群

  

  tracker集群:Tracker server之间是相互平等关系同时提供服务,客户端请求Tracker server采用轮询方式,如果请求的 tracker无法提供服务则换另一个tracker。 

  storage集群:Storage集群采用了分组存储方式, 由一个或多个组构成;集群存储总容量为集群中所有组的存储容量之和;一个组由一台或多台存储服务器组成,组内的Storage server 之间是平等关系,相互备份,组内存储容量遵循木桶效应,所以同一组内的结点容量尽量差不多; 不同组的Storage server之间不会相互通信,同组内的 Storage server之间会相互连接进行文件同步,从而保证同组内每个storage上的文件完全一致的。

  这里衍生出一个问题,同组内的storage是如何做到同步?

  当有一个client向某一个组中storage服务器写数据,该服务器就被称为“源服务器”,这台源服务器向同组内的其他storage server以发广播形式同步。当有一台新的storage加入,会从原来的storage中选择一台作为源服务,同步给目标服务器,也就是新加入的storage