首先得知道分布式文件系統的概念,一般的文件系統,比如一台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的上傳流程:
以上程序都完成后,可以用命令測試是否能成功上傳文件:
“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