分散式文件系統FastDFS簡介、搭建、與SpringBoot整合實現圖片上傳
之前大學時搭建過一個FastDFS的圖片伺服器,當時只是抱著好奇的態度搭著玩一下,當時搭建採用了一台虛擬機,tracker和storage服務在一台機器上放著,最近翻之前的部落格突然想著在兩台機器上搭建試一下,順便整合了SpringBoot實現了一下圖片的上傳服務。
新的閱讀體驗地址://www.zhouhong.icu/post/140
使用舊版本的在一台機器上搭建可以參考之前的那篇文章://www.cnblogs.com/Tom-shushu/p/10603723.html
一、傳統文件上傳問題:
如果我們現在用戶使用的是第一胎伺服器Tomcat1上傳了文件,然後當用戶訪問Tomcat1時候可以訪問到上傳的文件、圖片等等,但是如果當用戶訪問到Tomcat2和Tomcat3的時候,由於文件資源在Tomcat1上面,所以他是訪問不到對應的資源的;這時就可以使用到分散式文件系統FastDFS了。
二、什麼是分散式文件系統
- 隨著文件數據的越來越多,通過tomcat或nginx虛擬化的靜態資源文件在單一的一個伺服器節點內是存不下的,如果用多個節點來存儲也可以,但是不利於管理和維護,所以我們需要一個系統來管理多台電腦節點上的文件數據,這就是分散式文件系統。
- 分散式文件系統是一個允許文件通過網路在多台節點上分享的文件系統,多台電腦節點共同組成一個整體,為更多的用戶提供分享文件和存儲空間。比如常見的網盤,本質就是一個分散式的文件存儲系統。雖然我們是一個分散式的文件系統,但是對用戶來說是透明的,用戶使用的時候,就像是訪問本地磁碟一樣。
- 分散式文件系統可以提供冗餘備份,所以容錯能力很高。 系統中有某些節點宕機,但是整體文件服務不會停止,還是能夠為用戶提供服務,整體還是運作的,數據也不會丟失。
- 分散式文件系統的可擴展性強,增加或減少節點都很簡單,不會影響線上服務,增加完畢後會發布到線上,加入到集群中為用戶提供服務。
- 分散式文件系統可以提供負載均衡能力,在讀取文件副本的時候可以由多個節點共同提供服務,而且可以通過橫向擴展來確保性能的提升與負載。
三、為什麼要使用分散式文件系統
使用分散式文件系統可以解決如下幾點問題:
- 海量文件數據存儲
- 文件數據高可用(冗餘備份)
- 讀寫性能和負載均衡
以上3點都是我們之前使用tomcat或nginx所不能夠實現的,這也是我們為什麼要使用分散式文件系統的原因
四、FastDFS 與 HDFS
說到分散式文件存儲,肯定會有人想到HDFS,他們兩者主要定位和應用場景是不一樣的。
- Hadoop中的文件系統HDFS主要解決並行計算中分散式存儲數據的問題。其單個數據文件通常很大,採用了分塊(切分)存儲的方式,所以是大數據大文件存儲來使用的場景。
- FastDFS主要用於互聯網網站,為文件上傳和下載提供在線服務。所以在負載均衡、動態擴容等方面都支援得比較好,FastDFS不會對文件進行分快存儲。FastDFS用於存儲中小文件都是不錯的,比如用戶頭像啊,一些較小的音影片文件啊等等都行。
五、FastDFS常見術語
- tracker:追蹤者伺服器,主要用於協調調度,可以起到負載均衡的作用,記錄storage的相關狀態資訊。
- storage:存儲伺服器,用於保存文件以及文件的元數據資訊
- group:組,同組節點提供冗餘備份,不同組用於擴容
- mata data: 文件的元數據資訊,比如長寬資訊、圖片後綴,影片幀數等
六、FastDFS架構
tracker和storage是有心跳資訊的,需要先啟動tracker
七、FasfDFS文件上傳過程
八、FastDFS下載過程
九、FastDFS搭建:
準備:
- 安裝包準備
鏈接:https://pan.baidu.com/s/1Lic4JfUT4a8YdYmqJ5_vcQ 提取碼:bm0a 複製這段內容後打開百度網盤手機App,操作更方便哦
兩台伺服器
- tracker服務:192.168.2.120 、storage服務:192.168.2.121,如下圖:
1、基本環境搭建:
- 安裝基礎環境
yum install -y gcc gcc-c++
yum -y install libevent
- 安裝libfastcommon函數庫
# 1.解壓 tar -zxvf libfastcommon-1.0.42.tar.gz
# 2.進入解壓後的文件夾編譯並安裝 cd libfastcommon-1.0.42/ ./make.sh ./make.sh install
- 安裝FastDFS主程式文件
# 1.解壓 tar -zxvf fastdfs-6.04.tar.gz
# 2.進入到fastdfs目錄,查看fastdfs安裝配置 cd fastdfs-6.04/ vim make.sh
# 3.安裝fastdfs ./make.sh ./make.sh install
# 4.將FastDFS中conf中的文件拷貝到 /etc/fdfs下 cp /software/FastDFS/fastdfs-6.04/conf/* /etc/fdfs/
2、配置tracker服務
進入 /etc/fdfs 修改配置文件 tracker.conf
# 1.修改文件路徑 base_path=/usr/local/fastdfs/tracker
# 2.創建文件路徑 mkdir /usr/local/fastdfs/tracker -p
# 3.啟動 /usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf
# 4.查看服務 ps -ef|grep tracker
# 5.停止tracker /usr/bin/stop.sh /etc/fdfs/tracker.conf
3.配置storage服務
進入 /etc/fdfs 修改配置文件 storage.conf
# 1.修改配置文件 storage.conf # 修改組名 group_name=zhouhong # 修改storage的工作空間 base_path=/usr/local/fastdfs/storage # 修改storage的存儲空間 store_path0=/usr/local/fastdfs/storage # 修改tracker的地址和埠號,用於心跳 tracker_server=192.168.2.120:22122 # 後續結合nginx的一個對外服務埠號 http.server_port=8888
# 2.創建目錄 mkdir /usr/local/fastdfs/storage -p
# 3.啟動 /usr/bin/fdfs_storaged /etc/fdfs/storage.conf
4.查看 ps -ef|grep storage
4、測試
修改 /etc/fdfs 下 client.conf文件
# 1.修改client.conf文件 base_path=/usr/local/fastdfs/client tracker_server=192.168.2.120:22122
# 2.創建目錄 mkdir /usr/local/fastdfs/client
# 3.準備一張圖片測試 /usr/bin/fdfs_test /etc/fdfs/client.conf upload zhouhong.jpg
成功!
5、配置 nginx fastdfs 實現文件伺服器
Nginx需要跟storage安裝在同一台伺服器上面
fastdfs安裝好以後是無法通過http訪問的,這個時候就需要藉助nginx了,所以需要安裝fastdfs的第三方模組到nginx中,就能使用了。
- 安裝nginx插件
# 1.解壓 tar -zxvf fastdfs-nginx-module-1.22.tar.gz
# 2.複製配置文件 cp /software/FastDFS/fastdfs-nginx-module-1.22/src/mod_fastdfs.conf /etc/fdfs/
# 3.修改/fastdfs-nginx-module/src/config文件 修改/fastdfs-nginx-module/src/config文件,主要是修改路徑,把local刪除, 因為fastdfs安裝的時候我們沒有修改路徑,原路徑是/usr
如圖所示,將local刪除即可
- 安裝Nginx
# 1.環境安裝 yum install -y pcre pcre-devel yum install -y zlib zlib-devel yum install -y gcc-c++ yum install -y openssl openssl-decel
# 2.解壓 tar -zxvf nginx-1.16.1.tar.gz
# 3.創建目錄 mkdir /var/temp/nginx -p
# 4.進入解壓目錄、最後一個為fastdfs-nginx-module-1.22解壓目錄 ./configure \ --prefix=/usr/local/nginx \ --pid-path=/var/run/nginx/nginx.pid \ --lock-path=/var/lock/nginx.lock \ --error-log-path=/var/log/nginx/error.log \ --http-log-path=/var/log/nginx/access.log \ --with-http_gzip_static_module \ --http-client-body-temp-path=/var/temp/nginx/client \ --http-proxy-temp-path=/var/temp/nginx/proxy \ --http-fastcgi-temp-path=/var/temp/nginx/fastcgi \ --http-uwsgi-temp-path=/var/temp/nginx/uwsgi \ --http-scgi-temp-path=/var/temp/nginx/scgi \ --add-module=/software/FastDFS/fastdfs-nginx-module-1.22/src
# 5.安裝 make make install
# 6.修改 /etc/fdfs/mod_fastdfs.conf base_path=/usr/local/fastdfs/tmp tracker_server=192.168.2.120:22122 group_name=zhouhong url_have_group_name = true store_path0=/usr/local/fastdfs/storage
# 7.創建目錄 mkdir /usr/local/fastdfs/tmp
# 8.修改/usr/local/nginx/conf/nginx.conf server { listen 8888; server_name localhost; location /zhouhong/M00 { ngx_fastdfs_module; } }
- 訪問
找到剛才上傳的圖片
cd /usr/local/fastdfs/storage/data/00/00 ls
十、FastDFS與SpringBoot整合實現文件上傳
1、引入依賴
<dependency> <groupId>com.github.tobato</groupId> <artifactId>fastdfs-client</artifactId> <version>1.26.7</version> </dependency>
2、配置文件
############################################################ # # fdfs 配置 # ############################################################ fdfs: connect-timeout: 30 # 連接的超時時間 so-timeout: 30 # 讀取的超時時間 tracker-list: 192.168.2.120:22122 # tracker服務所在的ip地址和埠號
3、FileService主要邏輯程式碼
@Autowired private FastFileStorageClient fastFileStorageClient; @Override public String upload(MultipartFile file, String fileExtName) throws Exception { StorePath storePath = fastFileStorageClient.uploadFile(file.getInputStream(), file.getSize(), fileExtName, null); String path = storePath.getFullPath(); return path; }
4、FileController主要邏輯程式碼
@RestController @RequestMapping("fdfs") public class CenterUserController { @Autowired private FileResource fileResource; @Autowired private CenterUserService centerUserService; @Autowired private FileService fdfsService; @PostMapping("uploadFace") public JSONResult uploadFace( String userId, MultipartFile file, HttpServletRequest request, HttpServletResponse response) throws Exception { String path = ""; // 開始文件上傳 if (file != null) { // 獲得文件上傳的文件名稱 String fileName = file.getOriginalFilename(); if (StringUtils.isNotBlank(fileName)) { // 文件重命名 String fileNameArr[] = fileName.split("\\."); // 獲取文件的後綴名 String suffix = fileNameArr[fileNameArr.length - 1]; if (!suffix.equalsIgnoreCase("png") && !suffix.equalsIgnoreCase("jpg") && !suffix.equalsIgnoreCase("jpeg") ) { return JSONResult.errorMsg("圖片格式不正確!"); } path = fdfsService.upload(file, suffix); System.out.println(path); } } else { return JSONResult.errorMsg("文件不能為空!"); } if (StringUtils.isNotBlank(path)) { String finalUserFaceUrl = fileResource.getHost() + path; //更新圖片地址到資料庫 Users userResult = centerUserService.updateUserFace(userId, finalUserFaceUrl); UsersVO usersVO = conventUsersVO(userResult); CookieUtils.setCookie(request, response, "user", JsonUtils.objectToJson(usersVO), true); } else { return JSONResult.errorMsg("上傳頭像失敗"); } return JSONResult.ok(); } }
5、映射
@Component @PropertySource("classpath:file.properties") @ConfigurationProperties(prefix = "file") public class FileResource { private String host; public String getHost() { return host; } public void setHost(String host) { this.host = host; } }