一含思、簡介和應用場景
1.1朋凉、簡介
FastDFS是一款使用純C語言實現的應用級別的分布式文件存儲服務
1.2望拖、架構
FastDFS系統(tǒng)由client(文件上傳下載客戶端)尺铣、tracker(協調服務器)训枢、storage(存儲服務器)三部分組成位迂。
tracker和storage可以進行集群部署琅拌,多個tracker之間并無聯系拄轻,所以tracker彼此間并不存在同步搅裙,僅僅是用做容災皱卓,防止一臺tracker宕機后無法繼續(xù)提供存儲服務。
storage服務啟動后會向配置的tracker server注冊自己部逮,向其報告自己的狀態(tài)信息娜汁,包括磁盤剩余空間、文件同步狀況兄朋、文件上傳下載次數等統(tǒng)計信息掐禁,這使得tracker可以協調多個storage共同工作。不同組的Storage server之間不會相互通信颅和,同組內的Storage server之間會相互連接進行文件同步傅事。
同步方式
Storage server采用binlog文件記錄文件上傳、刪除等更新操作峡扩。binlog中只記錄文件名蹭越,不記錄文件內容。
文件同步只在同組內的Storage server之間進行教届,采用push方式般又,即源頭服務器同步給目標服務器。
Storage server中由專門的線程根據binlog進行文件同步,Storage server對組內除自己以外的每臺服務器都會啟動一個線程來進行文件同步巍佑。
文件同步采用增量同步方式,系統(tǒng)記錄已同步的位置(binlog文件偏移量)到標識文件中寄悯。標識文件名格式:{dest storage IP}_{port}.mark萤衰,例如:192.168.1.1_23000.mark。
1.3猜旬、交互流程
上傳:
客戶端通過API向 tracker server發(fā)起請求脆栋,獲取當前可用的storage server 地址( 注意:由于多個tracker間并無關聯,此處的負載應由客戶端去處理洒擦〈徽客戶端應獲取所有可用的tracker server,按照一定的均衡策略從中選取一個可用鏈接熟嫩,若此鏈接在一段時間內都不可用秦踪,應將其暫時移除并重新獲取,而且要在一定條件下將其重新加入可選列表)。
客戶端從tracker server中成功獲取到可用的storage server地址椅邓,然后向此storage server發(fā)起上傳文件的請求柠逞。
storage server向客戶端返回此文件的path。
storage server向組內其他兄弟發(fā)起文件同步景馁。
下載:下載一般有兩種板壮,圖片和PDF等瀏覽器自身支持的文件類型,可通過nginx代理直接使用path訪問合住。其他關聯了業(yè)務的附件下載操作應通過應用服務器中轉下載绰精。
單機情況下若ng和storage server在同一臺服務器,可以通過文件path直接反向映射到本地磁盤文件透葛。
集群情況下需安裝fastdfs-nginx-module插件笨使,此插件可以自動尋址到上傳文件的源storage server上,防止同步時間差導致請求其他storage server 獲取不到此文件获洲。
1.4 阱表、缺點及應用場景
FastDFS以簡單、易用作為其設計原則贡珊,但這無法避免的產生了一些問題:
數據安全性
1.上傳文件到源服務器即成功最爬,若此時源服務器宕機且處于同步時間差,那么此文件數據會丟失门岔。
2.同步未對文件做正確性校驗爱致,這種同步方式僅適用單個集群點的局部內部網絡,如果在公網上使用寒随,肯定會出現損壞文件的情況糠悯,需要自行添加文件校驗機制(篡改和硬件損壞,幾率極低)妻往。
大文件處理
FastDFS沒有對文件做分塊存儲互艾,因此不太適合分布式計算場景。(不適合存儲大文件)
綜上所述讯泣,fastDFS適用于處理以小文件為載體纫普、文件安全性不是太苛刻的在線存儲服務,如相冊好渠、視頻等昨稼。
二、安裝及部署
fastdfs
所有服務安裝方式都為源碼編譯安裝拳锚,提供兩種方式下載源碼——github和sourceforge假栓,github上有最新的發(fā)布版本。
github
sourceforge
nginx 緩存插件
2.1霍掺、環(huán)境依賴
操作系統(tǒng)為4臺64位CentOS Linux release 7.5.1804
192.168.152.136 nginx tracker
192.168.152.139 tracker
192.168.152.134 storage2 ngx_fastdfs_module
192.168.152.135 storage1 ngx_fastdfs_module
依賴第三方工具:
zlib zlib-devel pcre pcre-devel gcc gcc-c++ openssl openssl-devel libevent libevent-devel perl unzip net-tools wget
2.2匾荆、整體架構
線上架構應為:用戶——》keepalived(虛擬IP)——》負載nginx(2+)——》tracker負載nginx(2+)——》
storage(2+)拌蜘,架構圖如下
本次部署只為模擬,進行了簡化,架構圖如下
2.2棋凳、安裝libfastcommon
解壓并安裝
tar -zxvf V1.0.7.tar.gz
cd libfastcommon-1.0.7
./make.sh
./make.sh isntall
軟鏈接動態(tài)鏈接庫到引用路徑
ln -s /usr/lib64/libfastcommon.so /usr/local/lib/libfastcommon.so
ln -s /usr/lib64/libfastcommon.so /usr/lib/libfastcommon.so
ln -s /usr/lib64/libfdfsclient.so /usr/local/lib/libfdfsclient.so
ln -s /usr/lib64/libfdfsclient.so /usr/lib/libfdfsclient.so
2.3拦坠、安裝FastDFS
解壓并安裝
tar -zxvf V5.05.tar.gz
cd fastdfs-5.05
./make.sh
./make.sh install
軟連接到腳本到引用路徑
ln -s /usr/bin/fdfs_trackerd /usr/local/bin
ln -s /usr/bin/fdfs_storaged /usr/local/bin
ln -s /usr/bin/stop.sh /usr/local/bin
ln -s /usr/bin/restart.sh /usr/local/bin
2.4、配置tracker和storage
192.168.152.135 192.168.152.134分別創(chuàng)建 tracker及storage目錄
mkdir -p /home/fdfs/trackerd
mkdir -p /home/fdfs/storaged
配置tracker
vi /etc/fdfs/tracker.conf
主要配置tracker的元數據和日志存儲路徑和均衡策略等
#存儲路徑
base_path=/home/fdfs/fdfs_trackerd
#下載文件如何選擇storage server
#0表示輪詢剩岳,1表示上傳的源服務器(避免同步時間差)
download_server=1
配置storage
vi /etc/fdfs/storage.conf
#分組名稱
group_name=group1
#數據及日志存儲路徑
base_path=/home/mandy/fdfs/fdfs_storaged
#數據存儲路徑贞滨,可以有多個(可以掛載多個磁盤)
store_path0=/home/fdfs/fdfs_storaged
#tracker server地址,多個寫成列表形式
tracker_server=192.168.152.136:22122
tracker_server = 192.168.152.134:22122
配置完畢啟動服務并驗證
service fdfs_trackerd start
service fdfs_storaged start
查看服務是否已開啟
netstat -unltp | grep fdfs
查看storage是否已經激活到tracker
/usr/bin/fdfs_monitor /etc/fdfs/storage.conf
storage sever狀態(tài)
# FDFS_STORAGE_STATUS_INIT :初始化拍棕,尚未得到同步已有數據的源服務器
# FDFS_STORAGE_STATUS_WAIT_SYNC :等待同步晓铆,已得到同步已有數據的源服務器
# FDFS_STORAGE_STATUS_SYNCING :同步中
# FDFS_STORAGE_STATUS_DELETED :已刪除,該服務器從本組中摘除(注:本狀態(tài)的功能尚未實現)
# FDFS_STORAGE_STATUS_OFFLINE :離線
# FDFS_STORAGE_STATUS_ONLINE :在線绰播,尚不能提供服務
# FDFS_STORAGE_STATUS_ACTIVE :在線骄噪,可以提供服務
2.5、nginx配置
2.5.1蠢箩、storage nginx配置
由于fastdfs在4.0.5之后的版本中將內置的http服務器移除链蕊,因此想通過http方式訪問storage server,需要在每個storage上配置 nginx和fastdfs-nginx-module;
安裝fastdfs-nginx-module
tar -zxf fastdfs-nginx-module-1.20.tar.gz
cd nginx-1.12.1
./configure --add-module=/home/download/fastdfs-nginx-module-master/src
make&&make install
安裝有可能失敗谬泌,如報如下錯誤 /usr/local/include/fastdfs/fdfs_define.h:15:27: 致命錯誤:common_define.h:沒有那個文件或目錄
解決方式
vim fastdfs-nginx-module-1.20/src/config
編輯
ngx_module_incs="/usr/include/fastdfs /usr/include/fastcommon/"
CORE_INCS="$CORE_INCS /usr/include/fastdfs /usr/include/fastcommon/"
./nginx -V 查看fastDFS模塊是否已經添加成功
配置nginx.conf
ng配置灰常簡單,如下:
server {
listen 80;
server_name lcoalhost;
location /M00 {
ngx_fastdfs_module;
}
}
從解壓的fastdfs-nginx-module-1.20.tar.gz src下拷貝 mod_fastdfs.conf到/etc/fdfs/下并編輯,目前只針對單個group進行配置
#日志存儲路徑
base_path=/home/fdfs
#url中是否需要組名滔韵,若未分組,可以置為false
url_have_group_name = false
#tracker地址掌实,多個寫成列表形式
tracker_server=192.168.152.134:22122
tracker_server = 192.168.152.136:22122,
重啟nginx即可.
2.5.2 負載nginx配置
安裝nginx插件 ngx_cache_purge
tracker添加一臺負載nginx(此處進行了簡化陪蜻,實際線上應多加一層代理)
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
sendfile on;
tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server_names_hash_bucket_size 128;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
client_max_body_size 300m;
proxy_redirect off;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 16k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;
proxy_cache_path /home/mandy/nginx/proxy_cache levels=1:2
keys_zone=http-cache:500m max_size=10g inactive=30d;
proxy_temp_path /home/mandy/nginx/proxy_cache/tmp;
upstream fdfs_group1 {
server 192.168.152.134:80 weight=1 max_fails=2 fail_timeout=30s;
server 192.168.152.135:80 weight=1 max_fails=2 fail_timeout=30s;
}
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location /M00 {
proxy_next_upstream http_502 http_504 error timeout invalid_header;
proxy_cache http-cache;
proxy_cache_valid 200 304 12h;
proxy_cache_key $uri$is_args$args;
proxy_pass http://fdfs_group1;
expires 30d;
}
location ~/purge(/.*) {
allow all;
proxy_cache_purge http-cache $1$is_args$args;
}
}
}
2.6、防盜鏈
fastDFS內置防盜鏈是在服務端開啟token驗證贱鼻,客戶端根據文件名宴卖、當前unix時間戳、秘鑰獲取token邻悬,在地址中帶上token參數即可通過http方式訪問文件症昏。
服務端開啟認證
拷貝fastdfs安裝包conf下的anti-steal.jpg mime.types http.conf文件到 /etc/fdfs/
編輯http.conf
#開啟token
http.anti_steal.check_token=true
#token有效期,單位秒(意味著客戶端時間要與服務器保持在此時間差以內)
http.anti_steal.token_ttl=900
#加密的key
http.anti_steal.secret_key=FastDFS1234567890
同時需要在 mod_fastdfs.conf中配置認證失敗后跳轉的403頁面
客戶端token生成
public static void main(String[] args){
#file_path不帶分組名,時間為unix時間父丰,key與服務器http.conf配置的key保持一致
getToken("M00/00/00/wKiYhluV1heAAJDLAAnTlA5XnbM950.pdf",(int) Instant.now().getEpochSecond(),"FastDFS1234567890");
}
public static String md5(byte[] source) throws NoSuchAlgorithmException {
char[] hexDigits = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(source);
byte[] tmp = md.digest();
char[] str = new char[32];
int k = 0;
for(int i = 0; i < 16; ++i) {
str[k++] = hexDigits[tmp[i] >>> 4 & 15];
str[k++] = hexDigits[tmp[i] & 15];
}
return new String(str);
}
public static String getToken(String remote_filename, int ts, String secret_key) throws UnsupportedEncodingException, NoSuchAlgorithmException {
final String charSet = "UTF-8";
byte[] bsFilename = remote_filename.getBytes(charSet);
byte[] bsKey = secret_key.getBytes(charSet);
byte[] bsTimestamp = (new Integer(ts)).toString().getBytes(charSet);
byte[] buff = new byte[bsFilename.length + bsKey.length + bsTimestamp.length];
System.arraycopy(bsFilename, 0, buff, 0, bsFilename.length);
System.arraycopy(bsKey, 0, buff, bsFilename.length, bsKey.length);
System.arraycopy(bsTimestamp, 0, buff, bsFilename.length + bsKey.length, bsTimestamp.length);
return md5(buff);
}
三齿兔、客戶端集成
目前客戶端使用連接池方式進行調用,首先進行配置:
新建config類并繼承GenericKeyedObjectPoolConfig础米,樣例如下:
@Component
@ConfigurationProperties(prefix = "fastdfs.pool")
public class FastdfsPoolConfig extends GenericKeyedObjectPoolConfig {
}
FastDFSConfig添加對FastdfsExecutor的配置,樣例如下:
@Configuration
public class FastDFSConfig {
@Resource
private FastdfsPoolConfig fastdfsPoolConfig;
@Bean
public FastdfsExecutor fastdfsExecutor() {
FastdfsExecutor executor = new FastdfsExecutor();
executor.setPoolConfig(fastdfsPoolConfig);
return executor;
}
@Bean
public SimpleFastdfsClient simpleFastdfsClient(FastdfsExecutor fastdfsExecutor, @Value("${fastdfs.tracker.host}") String trackerServerAddr) {
return new SimpleFastdfsClient(fastdfsExecutor, trackerServerAddr);
}
}
默認開啟對每次獲取的連接的校驗testOnBorrow =true,若需改為輪詢方式添诉,在spring配置文件中添加如下配置:
fastdfs.pool.testOnBorrow=false
fastdfs.pool.testWhileIdle=true #開啟定時任務校驗空閑連接
fastdfs.pool.timeBetweenEvictionRunsMillis=30000 #任務間隙屁桑,單位為毫秒
fastdfs.pool.maxTotalPerKey=10 #每個key最大連接數
fastdfs.pool.minIdlePerKey=3 #每個key最小空閑連接
fastdfs.pool.numTestsPerEvictionRun=3 #每次檢測空閑連接數
上傳樣例:
simpleFastdfsClient.upload(new File("E://data//1.pdf"));
四、遺留問題
使用nginx做文件下載服務器存在一個問題:
文件被刪除后栏赴,由于nginx服務器對已經訪問過的文件進行了緩存蘑斧,那么此文件在一定時間內還是可以被成功下載,即便fastDFS服務已經關閉。
此文題已經解決竖瘾,安裝ngx_cache_purge 插件沟突,訪問“~/purge/資源”即可刪除此文件