咱們在實際項目中經常遇到這樣的應用場景,用戶須要上傳圖片,小視頻或者其它文檔,這些文件的大小通常在10M之內。它們不少,並且對用戶來講可能還很重要,並且可能還要常常被訪問,被下載,如何妥善保存這些文件就是一個須要解決的問題。html
解決這個問題須要兩點:一個是文件冗餘備份,保證用戶的文件不會丟失,另外一個是高可用性,也就是說當文件服務器出現故障的時候,能夠馬上讓備份服務器爲用戶提供服務,使用戶感受不到有什麼異常。java
那麼咱們不妨分析下有哪幾種解決方案:nginx
1.粗放型:
直接做爲blob字段存數據庫裏,利用數據庫的容災備份和HA來保障文件安全。其實這種方案是最安全的,可是顯然數據庫不是用來作這個的,由於太佔數據庫空間。不過因爲其安全性最高,筆者在以前某個項目中曾經被要求這麼幹,由於保存的是客戶的合同文件。可是相似社交網絡的圖片文件是不必這麼作的。git
2.簡約型:
直接存文件系統。若是有多臺應用服務器同時提供文件上傳服務,那麼就準備一臺文件服務器,分別掛載到全部應用服務器的指定路徑下,實現多臺應用服務器的文件寫入,同時還能夠配置讀取靜態文件更高效的nginx或者lighttpd來負責文件的讀取。這樣的好處是配置簡單,管理方便(要不怎麼叫簡約型),不過缺點也很大,就是實現不了高可用性,雖然能夠按期對文件服務器進行備份,可是一旦故障,文件會有部分丟失,並且nfs協議對併發寫入的支持並很差。這種方案適合低併發,可靠性要求也不高的系統。github
3.專業型:
就是採用專業的分佈式文件系統了,方案其實蠻多的。spring
mongodb提供了gridfs模塊作文件的分佈式存儲,不過對於數據庫不是採用mongo的,不必爲了文件存儲專門上個mongodbmongodb
其它還有不少開源的解決方案,好比阿里開源的TFS,還有本文要介紹的Fastdfs。數據庫
(呼~~終於切入正題了)關於Fastdfs我就不介紹了,請看這篇簡介。安全
關於部署,網上介紹有一些,可是基本都有問題,建議以這篇爲參考如何部署。服務器
可是這篇一樣有問題,在啓動nginx和fastdfs以前需作以下修改:
編輯/etc/init.d/fdfs_storaged
和/etc/init.d/fdfs_trackerd
,這兩個腳本里全部的路徑都多了一層local,請把裏面的全部/local刪掉
必須在mod_fastdfs.conf文件最後加上一行#include http.conf,好讓nginx啓動的時候引入這個http.conf文件。
他的nginx配置也有點小問題,用這個吧(筆者是部署在192.168.6.46和192.168.6.47兩臺服務器上,server_name請自行修改)
server { listen 80; server_name 192.168.6.46; root /usr/local/nginx/html; index index.html index.htm; location / { if (!-e $request_filename) { rewrite ^/(.*)$ /index.html last; } location /group1/M00 { root /export/fastdfs/storage/data/; ngx_fastdfs_module; } location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|js)$ { fastcgi_cache_valid 200 10m; fastcgi_cache_valid 304 3m; fastcgi_cache_valid 301 302 1h; fastcgi_cache_valid any 1m; fastcgi_cache_min_uses 1; fastcgi_cache_use_stale error timeout invalid_header http_500; fastcgi_cache_key $host$request_uri; access_log off; } } access_log off; }
好了,分別啓動兩臺服務器的nginx和fastdfs的storage和tracker服務,部署完成。
測試一下上傳文件:
好了,返回的是fileId,前面加上ip就是下載文件的url了。
還沒完,接下來咱們探討下如何在java項目中使用fastdfs來幫咱們保存文件。
fastdfs的做者又爲咱們寫了一個java客戶端的sdk。github地址
可是,這個sdk沒有使用鏈接池,效率不是很高,編碼風格也傾向於C++工程師。
網上有達人寫了帶鏈接池的優化版,我在其基礎上又作了一些小的改進,一方面改掉了一些不兼容fastdfs5.05版本的bug,一方面使其更便於與spring結合。源碼地址。
咱們須要在spring中以下配置:
<bean id="fastdfsFactory" class="net.mikesu.fastdfs.FastdfsClientFactory"> <constructor-arg name="configFile" value="config/props/fastdfs.properties" /> </bean>
config/props/fastdfs.properties是與fastdfs相關配置文件。裏面填這三個配置項。
connect_timeout=5 network_timeout=30 tracker_server=192.168.6.68:22122
支持配置多個tracker_server,固然也能夠像筆者這樣用keepalived或者nginx爲多臺fastdfs服務器提供一個vip。
在咱們的項目中注入fastdfs的客戶端
@Autowired private FastdfsClientFactory fcf;
上傳文件
FastdfsClient fastdfsClient = fcf.getFastdfsClient(); String fileId = fastdfsClient.upload(file);
OK