FastDFS 研究
什么是分布式文件系統
什么是文件系統
文件系統是負責管理和存儲文件的系統軟件,它是操作系統和硬件驅動之間的橋梁,操作系統通過文件系統
提供的接口去存取文件,用戶通過操作系統訪問磁盤上的文件。如下圖:
什么是分布式文件系統
為什么會有分布文件系統呢?
分布式文件系統是面對互聯網的需求而產生,互聯網時代對海量數據如何存儲?靠簡單的增加硬盤的個數已經滿足
不了我們的要求,因為硬盤傳輸速度有限但是數據在急劇增長,另外我們還要要做好數據備份、數據安全等。
采用分布式文件系統可以將多個地點的文件系統通過網絡連接起來,組成一個文件系統網絡,結點之間通過網絡進
行通信,一台文件系統的存儲和傳輸能力有限,我們讓文件在多台計算機上存儲,通過多台計算共同傳輸。如下
圖:
好處:
1、一台計算機的文件系統處理能力擴充到多台計算機同時處理。
2、一台計算機掛了還有另外副本計算機提供數據。
3、每台計算機可以放在不同的地域,這樣用戶就可以就近訪問,提高訪問速度。
什么是fastDFS
FastDFS是用c語言編寫的一款開源的分布式文件系統,它是由淘寶資深架構師余慶編寫並開源。FastDFS專為互聯
網量身定制,充分考慮了冗余備份、負載均衡、線性擴容等機制,並注重高可用、高性能等指標,使用FastDFS很
容易搭建一套高性能的文件服務器集群提供文件上傳、下載等服務。
為什么要使用fastDFS呢?
上邊介紹的NFS、GFS都是通用的分布式文件系統,通用的分布式文件系統的優點的是開發體驗好,但是系統復雜
性高、性能一般,而專用的分布式文件系統雖然開發體驗性差,但是系統復雜性低並且性能高。fastDFS非常適合
存儲圖片等那些小文件,fastDFS不對文件進行分塊,所以它就沒有分塊合並的開銷,fastDFS網絡通信采用
socket,通信速度很快。
fastDSF 架構
FastDFS架構包括 Tracker server和Storageserver。客戶端請求Tracker server進行文件上傳、下載,通過Tracker
server調度最終由Storage server完成文件上傳和下載。
1)Tracker
Tracker Server作用是負載均衡和調度,通過Tracker server在文件上傳時可以根據一些策略找到Storage server提
供文件上傳服務。可以將tracker稱為追蹤服務器或調度服務器。
FastDFS集群中的Tracker server可以有多台,Tracker server之間是相互平等關系同時提供服務,Tracker server
不存在單點故障。客戶端請求Tracker server采用輪詢方式,如果請求的tracker無法提供服務則換另一個tracker。
2)Storage
Storage Server作用是文件存儲,客戶端上傳的文件最終存儲在Storage服務器上,Storage server沒有實現自己
的文件系統而是使用操作系統的文件系統來管理文件。可以將storage稱為存儲服務器。
Storage集群采用了分組存儲方式。storage集群由一個或多個組構成,集群存儲總容量為集群中所有組的存儲容
量之和。一個組由一台或多台存儲服務器組成,組內的Storage server之間是平等關系,不同組的Storage server
之間不會相互通信,同組內的Storage server之間會相互連接進行文件同步,從而保證同組內每個storage上的文件
完全一致的。一個組的存儲容量為該組內的存儲服務器容量最小的那個,由此可見組內存儲服務器的軟硬件配置最
好是一致的。
采用分組存儲方式的好處是靈活、可控性較強。比如上傳文件時,可以由客戶端直接指定上傳到的組也可以由
tracker進行調度選擇。一個分組的存儲服務器訪問壓力較大時,可以在該組增加存儲服務器來擴充服務能力(縱向
擴容)。當系統容量不足時,可以增加組來擴充存儲容量(橫向擴容)。
3)Storage狀態收集
Storage server會連接集群中所有的Tracker server,定時向他們報告自己的狀態,包括磁盤剩余空間、文件同步
狀況、文件上傳下載次數等統計信息。
文件上傳流程
客戶端上傳文件后存儲服務器將 文件ID 返回給客戶端,此文件ID用於以后訪問該文件的索引信息。文件索引信息
包括:組名,虛擬磁盤路徑,數據兩級目錄,文件名。
- 組名:文件上傳后所在的 storage組名稱,在文件上傳成功后有 storage服務器返回,需要客戶端自行保存。
- 虛擬磁盤路徑: storage配置的虛擬路徑,與磁盤選項 store_path* 對應。如果配置了store_path0則是M00,如果配置了store_path1則是M01,以此類推。
- 數據兩級目錄: storage服務器在每個虛擬磁盤路徑下創建的兩級目錄,用於存儲數據文件。
- 文件名:與文件上傳時不同。是由存儲服務器根據特定信息生成,文件名包含:源存儲服務器 IP地址、文件創建時間戳、文件大小、隨機數和文件拓展名等信息。
文件下載流程
tracker根據請求的文件路徑即文件ID 來快速定義文件。
比如請求下邊的文件:
1.通過組名tracker能夠很快的定位到客戶端需要訪問的存儲服務器組是group1,並選擇合適的存儲服務器提供客
戶端訪問。
2.存儲服務器根據“文件存儲虛擬磁盤路徑”和“數據文件兩級目錄”可以很快定位到文件所在目錄,並根據文件名找到
客戶端需要訪問的文件。
FastDFS環境搭建
關於FastDfs的搭建過程,我這里就不寫出來了,我第一次也是專研一下午才弄明白。下面也把搭建好的成品Centos7分享出來,包括nginx的環境搭建。
fastDFS安裝時,./make.sh編譯時出錯---perl:未找到命令
做fastDFS的案例的時候,在搭建分布式集群的模塊的時候,使用 ./make.sh 編譯的時候報錯,錯誤如下:
錯誤原因:在執行make.sh的時候沒有找到相應的命令
解決辦法:安裝相應的命令即可。執行以下命令
yum -y install zlib zlib-devel pcre pcre-devel gcc gcc-c++ openssl openssl-devel libevent libevent-devel perl unzip net-tools wget
Centos7成品:
鏈接:https://pan.baidu.com/s/1-yxZ_SHoq5k9BymaosTU-w
提取碼:89ho
具體搭建過程完全按照這篇博客完成的:
https://www.cnblogs.com/yufeng218/p/8111961.html
感興趣的可以試着做做。
另外,使用我搭建好的Centos7有幾個地方需要注意一下。
配置和啟動storage
- cd切換目錄到: /etc/fdfs/ 目錄下
- 修改storage.conf ; vi storage.conf
#配置tracker服務器:IP
tracker_server=192.168.172.20:22122
#如果有多個則配置多個tracker
#tracker_server=192.168.101.4:22122
這里的storage.conf配置文件要成自己虛擬機的ip地址
3. vi /etc/fdfs/mod_fastdfs.conf,改成虛擬機ip地址(同上)
base_path=/home/fastdfs tracker_server=192.168.172.20:22122 #tracker_server=192.168.172.20:22122 #(多個tracker配置多行) url_have_group_name=true #url中包含group名稱 store_path0=/home/fdfs_storage #指定文件存儲路徑(上面配置的store路徑)
4.修改nginx配置文件,改iP地址(同上)
cd /usr/local/nginx/conf/
vi nginx.conf
我的Centos7默認配置tracker,storage和nginx默認開機自動啟動了
可以啟動完成后進入 /home/fdfs_storage/data 目錄下,可以看到已經啟動了。
nginx可以通過ps -ef | grep nginx查看進程,
上傳圖片測試
拷貝一張圖片1.jpg 到Centos服務器上的 root目錄下,輸入以下指令
/usr/bin/fdfs_test /etc/fdfs/client.conf upload /root/1.jpg
紅色既是url地址,在瀏覽器上輸入,可以看到上傳圖片成功!!
有問題的可以查看上面一篇博客,詳解。
上傳圖片開發
需求分析
在很多系統都有上傳圖片/上傳文件的需求,比如:上傳課程圖片、上傳課程資料、上傳用戶頭像等,為了提供系
統的可重用性專門設立文件系統服務承擔圖片/文件的管理,文件系統服務實現對文件的上傳、刪除、查詢等功能
進行管理。
各各子系統不再開發上傳文件的請求,各各子系統通過文件系統服務進行文件的上傳、刪除等操作。文件系統服務
最終會將文件存儲到fastDSF文件系統中。
下圖是各各子系統與文件系統服務之間的關系:
下圖是課程管理中上傳圖片處理流程:
執行流程如下:
1、管理員進入教學管理前端,點擊上傳圖片
2、圖片上傳至文件系統服務,文件系統請求fastDFS上傳文件
3、文件系統將文件入庫,存儲到文件系統服務數據庫中。
4、文件系統服務向前端返回文件上傳結果,如果成功則包括文件的Url路徑。
5、課程管理前端請求課程管理進行保存課程圖片信息到課程數據庫。
6、課程管理服務將課程圖片保存在課程數據庫。
Api接口
在api工程下創建com.xuecheng.api.filesystem包,
public interface FileSystemControllerApi { /** * 上傳文件 * @param multipartFile 文件 * @param filetag 文件標簽 * @param businesskey 業務key * @param metedata 元信息,json格式 * @return */ public UploadFileResult upload(MultipartFile multipartFile, String filetag, String businesskey, String metadata); }
Dao
將文件信息存入數據庫,主要存儲文件系統中的文件路徑。
public interface FileSystemRepository extends MongoRepository<FileSystem,String> { }
Service

@Service public class FileSystemService { private static final Logger LOGGER = LoggerFactory.getLogger(FileSystemService.class); @Value("${xuecheng.fastdfs.tracker_servers}") String tracker_servers; @Value("${xuecheng.fastdfs.connect_timeout_in_seconds}") int connect_timeout_in_seconds; @Value("${xuecheng.fastdfs.network_timeout_in_seconds}") int network_timeout_in_seconds; @Value("${xuecheng.fastdfs.charset}") String charset; @Autowired FileSystemRepository fileSystemRepository; //加載fdfs的配置 private void initFdfsConfig(){ try { ClientGlobal.initByTrackers(tracker_servers); ClientGlobal.setG_connect_timeout(connect_timeout_in_seconds); ClientGlobal.setG_network_timeout(network_timeout_in_seconds); ClientGlobal.setG_charset(charset); } catch (Exception e) { e.printStackTrace(); //初始化文件系統出錯 ExceptionCast.cast(FileSystemCode.FS_INITFDFSERROR); } } //上傳文件 public UploadFileResult upload(MultipartFile file, String filetag, String businesskey, String metadata){ if(file == null){ ExceptionCast.cast(FileSystemCode.FS_UPLOADFILE_FILEISNULL); } //上傳文件到fdfs 北京市昌平區建材城西路金燕龍辦公樓一層 電話:400-618-9090 String fileId = fdfs_upload(file); //創建文件信息對象 FileSystem fileSystem = new FileSystem(); //文件id fileSystem.setFileId(fileId); //文件在文件系統中的路徑 fileSystem.setFilePath(fileId); //業務標識 fileSystem.setBusinesskey(businesskey); //標簽 fileSystem.setFiletag(filetag); //元數據 if(StringUtils.isNotEmpty(metadata)){ try { Map map = JSON.parseObject(metadata, Map.class); fileSystem.setMetadata(map); } catch (Exception e) { e.printStackTrace(); } } //名稱 fileSystem.setFileName(file.getOriginalFilename()); //大小 fileSystem.setFileSize(file.getSize()); //文件類型 fileSystem.setFileType(file.getContentType()); fileSystemRepository.save(fileSystem); return new UploadFileResult(CommonCode.SUCCESS,fileSystem); } //上傳文件到fdfs,返回文件id public String fdfs_upload(MultipartFile file) { try { //加載fdfs的配置 initFdfsConfig(); //創建tracker client TrackerClient trackerClient = new TrackerClient(); //獲取trackerServer TrackerServer trackerServer = trackerClient.getConnection(); //獲取storage StorageServer storeStorage = trackerClient.getStoreStorage(trackerServer); //創建storage client StorageClient1 storageClient1 = new StorageClient1(trackerServer,storeStorage); //上傳文件 //文件字節 byte[] bytes = file.getBytes(); //文件原始名稱 String originalFilename = file.getOriginalFilename(); //文件擴展名 String extName = originalFilename.substring(originalFilename.lastIndexOf(".") + 1); //文件id String file1 = storageClient1.upload_file1(bytes, extName, null); return file1; } catch (Exception e) { e.printStackTrace(); } return null; } }
Controller

@RestController @RequestMapping("/filesystem") public class FileSystemController implements FileSystemControllerApi { @Autowired FileSystemService fileSystemService; @Override @PostMapping("/upload") public UploadFileResult upload(@RequestParam("file") MultipartFile file, @RequestParam(value = "filetag", required = true) String filetag, @RequestParam(value = "businesskey", required = false) String businesskey, @RequestParam(value = "metedata", required = false) String metadata) { return fileSystemService.upload(file,filetag,businesskey,metadata); } }
測試
使用swagger-ui或postman進行測試。
下圖是使用swagger-ui進行測試的界面: