本文會(huì)搭建一個(gè)適合低業(yè)務(wù)訪問業(yè)務(wù)量的高可用的FastDFS集群環(huán)境:兩個(gè)Tracker服務(wù),一個(gè)storage group中兩個(gè)storage服務(wù)節(jié)點(diǎn);該方案僅適用于業(yè)務(wù)訪問量較低的環(huán)境下。對(duì)于大量業(yè)務(wù)系統(tǒng)的高并發(fā)訪問,為了保證存儲(chǔ)系統(tǒng)正常工作一般的架構(gòu)思路:安裝多個(gè)Tracker服務(wù)(至少兩個(gè),根據(jù)業(yè)務(wù)量調(diào)整),搭建多個(gè)storage group(至少兩個(gè),根據(jù)業(yè)務(wù)量調(diào)整),每個(gè)storage group中多個(gè)storage node(至少兩個(gè),做數(shù)據(jù)的冗余備份,進(jìn)行容災(zāi)機(jī)制,而且node必須在不同的機(jī)器上)
創(chuàng)新互聯(lián)致力于互聯(lián)網(wǎng)品牌建設(shè)與網(wǎng)絡(luò)營銷,包括網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)、SEO優(yōu)化、網(wǎng)絡(luò)推廣、整站優(yōu)化營銷策劃推廣、電子商務(wù)、移動(dòng)互聯(lián)網(wǎng)營銷等。創(chuàng)新互聯(lián)為不同類型的客戶提供良好的互聯(lián)網(wǎng)應(yīng)用定制及解決方案,創(chuàng)新互聯(lián)核心團(tuán)隊(duì)10多年專注互聯(lián)網(wǎng)開發(fā),積累了豐富的網(wǎng)站經(jīng)驗(yàn),為廣大企業(yè)客戶提供一站式企業(yè)網(wǎng)站建設(shè)服務(wù),在網(wǎng)站建設(shè)行業(yè)內(nèi)樹立了良好口碑。
一、FastDFS簡(jiǎn)介
FastDFS是一個(gè)開源的輕量級(jí)分布式文件系統(tǒng),它對(duì)文件進(jìn)行管理,功能包括:文件存儲(chǔ)、文件同步、文件訪問(文件上傳、文件下載)等,解決了大容量存儲(chǔ)和負(fù)載均衡的問題。特別適合以文件為載體的在線服務(wù),如相冊(cè)網(wǎng)站、視頻網(wǎng)站等等。
FastDFS為互聯(lián)網(wǎng)量身定制,充分考慮了冗余備份、負(fù)載均衡、線性擴(kuò)容等機(jī)制,并注重高可用、高性能等指標(biāo),使用FastDFS很容易搭建一套高性能的文件服務(wù)器集群提供文件上傳、下載等服務(wù)。
FastDFS服務(wù)端有兩個(gè)角色:跟蹤器(tracker)和存儲(chǔ)節(jié)點(diǎn)(storage)。跟蹤器主要做調(diào)度工作,在訪問上起負(fù)載均衡的作用。
存儲(chǔ)節(jié)點(diǎn)存儲(chǔ)文件,完成文件管理的所有功能:就是這樣的存儲(chǔ)、同步和提供存取接口,F(xiàn)astDFS同時(shí)對(duì)文件的metadata進(jìn)行管理。所謂文件的meta data就是文件的相關(guān)屬性,以鍵值對(duì)(key value)方式表示,如:width=1024,其中的key為width,value為1024。文件metadata是文件屬性列表,可以包含多個(gè)鍵值對(duì)。
跟蹤器和存儲(chǔ)節(jié)點(diǎn)都可以由一臺(tái)或多臺(tái)服務(wù)器構(gòu)成。跟蹤器和存儲(chǔ)節(jié)點(diǎn)中的服務(wù)器均可以隨時(shí)增加或下線而不會(huì)影響線上服務(wù)。其中跟蹤器中的所有服務(wù)器都是對(duì)等的,可以根據(jù)服務(wù)器的壓力情況隨時(shí)增加或減少。
為了支持大容量,存儲(chǔ)節(jié)點(diǎn)(服務(wù)器)采用了分卷(或分組)的組織方式。存儲(chǔ)系統(tǒng)由一個(gè)或多個(gè)卷組成,卷與卷之間的文件是相互獨(dú)立的,所有卷的文件容量累加就是整個(gè)存儲(chǔ)系統(tǒng)中的文件容量。一個(gè)卷可以由一臺(tái)或多臺(tái)存儲(chǔ)服務(wù)器組成,一個(gè)卷下的存儲(chǔ)服務(wù)器中的文件都是相同的,卷中的多臺(tái)存儲(chǔ)服務(wù)器起到了冗余備份和負(fù)載均衡的作用。
在卷中增加服務(wù)器時(shí),同步已有的文件由系統(tǒng)自動(dòng)完成,同步完成后,系統(tǒng)自動(dòng)將新增服務(wù)器切換到線上提供服務(wù)。
當(dāng)存儲(chǔ)空間不足或即將耗盡時(shí),可以動(dòng)態(tài)添加卷。只需要增加一臺(tái)或多臺(tái)服務(wù)器,并將它們配置為一個(gè)新的卷,這樣就擴(kuò)大了存儲(chǔ)系統(tǒng)的容量。
FastDFS中的文件標(biāo)識(shí)分為兩個(gè)部分:卷名和文件名,二者缺一不可。
———簡(jiǎn)介摘自百度百科
二、FastDFS原理介紹
1.文件上傳
FastDFS以客戶端庫的方式提供基本的文件訪問接口如upload、download、append、delete等,Storage 服務(wù)會(huì)定時(shí)的向Tracker服務(wù)發(fā)送自己的存儲(chǔ)信息。當(dāng)Tracker 服務(wù)集群中的Tracker 服務(wù)是多個(gè)時(shí),各個(gè)Tracker服務(wù)之間的關(guān)系是對(duì)等的,因此客戶端上傳時(shí)會(huì)任意選擇一個(gè)Trackre服務(wù)。當(dāng)Tracker服務(wù)收到客戶端上傳文件請(qǐng)求時(shí),會(huì)為該文件分配一個(gè)可以存儲(chǔ)文件的group,當(dāng)選定了group后就要決定給客戶端分配group中的哪一個(gè)storage服務(wù)。當(dāng)分配好storage 服務(wù)后,客戶端向storage發(fā)送寫文件請(qǐng)求,storage將會(huì)為文件分配一個(gè)數(shù)據(jù)存儲(chǔ)目錄。然后為文件分配一個(gè)文件ID標(biāo)示,然后根據(jù)以上的信息生成文件名存儲(chǔ)文件。
2.文件同步
上傳文件后,客戶端將文件寫到group內(nèi)的一個(gè)storage 服務(wù)即為上傳文件成功,storage服務(wù)寫完文件后,會(huì)由后臺(tái)線程將文件同步至同group內(nèi)的其他的storage 服務(wù)節(jié)點(diǎn)上。?每個(gè)storage服務(wù)寫文件后,會(huì)同時(shí)寫一份binlog,binlog里不包含文件數(shù)據(jù),只包含文件名等元信息,這份binlog用于后臺(tái)同步,storage會(huì)記錄向group內(nèi)其他storage同步的進(jìn)度,以便重啟后能接上次的進(jìn)度繼續(xù)同步;進(jìn)度以時(shí)間戳的方式進(jìn)行記錄,所以最好能保證集群內(nèi)的所有server的始終保持同步。最后Storage服務(wù)的同步進(jìn)度會(huì)作為元數(shù)據(jù)的一部分匯報(bào)到tracker服務(wù)上,tracker服務(wù)在選擇讀storage的時(shí)候會(huì)以同步進(jìn)度作為參考指標(biāo)。
3.下載文件
當(dāng)下載文件時(shí),客戶端先詢問tracker服務(wù)下載文件的storage,參數(shù)為文件標(biāo)識(shí)(卷名和文件名);然后tracker向客戶端返回一臺(tái)可用的storage;最后客戶端直接和storage通訊完成文件下載。
三、部署環(huán)境準(zhǔn)備
1.環(huán)境說明
操作系統(tǒng)CentOS7.6
fastdfs版本:6.01
nginx版本:1.16.1
keepalived版本:2.0.19
2.系統(tǒng)依賴
?gcc?gcc-c++ perl pcre?pcre-devel?zlib?zlib-devel?openssl?openssl-devel libnl libnl-devel
3.軟件環(huán)境
libevent下載地址:http://libevent.org/
nginx下載地址:http://nginx.org/en/download.html
keepalived下載地址:https://www.keepalived.org/software/
fastdfs下載地址:https://github.com/happyfish200/fastdfs/releases
libfasttcommon下載地址:https://github.com/happyfish200/libfastcommon/releases
fastdfs-nginx-module下載地址:https://github.com/happyfish200/fastdfs-nginx-module/releases
4.機(jī)器及網(wǎng)絡(luò)環(huán)境規(guī)劃
Fdfs?Server?VIP:?????????192.168.100.110Tracker?Server1:?????????192.168.100.111Tracker?Server2:?????????192.168.100.112Storage?Group1?Node1:????192.168.100.111Storage?Group1?Node2:????192.168.100.112
5.防火墻設(shè)置
關(guān)閉系統(tǒng)防火墻:sudo systemctl stop firewalld && systemctl disable firewalld
四、Keepalived服務(wù)安裝配置
1.下載Keepalived源碼包
官網(wǎng)地址:https://www.keepalived.org/
下載地址:https://www.keepalived.org/software/keepalived-2.0.19.tar.gz
2.上傳并解壓Keepalived源碼包
tar -zxvf keepalived-2.0.19.tar.gz
3.編譯Keepalived準(zhǔn)備
進(jìn)入解壓目錄:cd keepalived-2.0.19
執(zhí)行編譯準(zhǔn)備:./configure --prefix=/work/keepalived
注意:一定要有g(shù)cc和openssl編譯相關(guān)的依賴
4.編譯安裝Keepalived
make && make install
5.安裝配置Keepalived
keepalived啟動(dòng)時(shí)會(huì)從/etc/keepalived/中相關(guān)的目錄下查找keepalived.conf配置文件,因此將keepalived安裝錄/usr/local/keepalived/etc/keepalived.conf 拷貝到/etc/keepalived/中。
mkdir /etc/keepalived/
cp /work/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf
cp /work/keepalived/etc/sysconfig/keepalived /etc/sysconfig/keepalived
6.設(shè)置Keepalived開機(jī)啟動(dòng)項(xiàng)
systemctl enable keepalived
然后就能使用systemctl start/stop/status keepalived管理keepalived了
7.配置Keepalived服務(wù)
192.168.100.111機(jī)器上配置:vi /etc/keepalived/keepalived.conf
vrrp_script?check_nginx?{ ???????interval?3 ???????script?"/work/script/check_nginx.sh"} ?vrrp_instance?fdfs_server?{ ???????state?MASTER ???????interface?enp0s3 ???????virtual_router_id?110 ???????priority?100 ???????advert_int?3 ???????authentication?{ ????????????auth_type?PASS ????????????auth_pass?password ???????} ???????virtual_ipaddress?{ ????????????192.168.100.110 ???????} ???????track_script?{ ????????????check_nginx ???????}}
192.168.100.112機(jī)器上配置:vi /etc/keepalived/keepalived.conf
vrrp_script?check_nginx?{ ???????interval?3 ???????script?"/work/script/check_nginx.sh"} ?vrrp_instance?fdfs_server?{ ???????state?BACKUP ???????interface?enp0s3 ???????virtual_router_id?110 ???????priority?90 ???????advert_int?3 ???????authentication?{ ????????????auth_type?PASS ????????????auth_pass?password ???????} ???????virtual_ipaddress?{ ????????????192.168.100.110 ???????} ???????track_script?{ ????????????check_nginx ???????}}
8.編寫nginx服務(wù)檢測(cè)腳本
vi /work/script/check_nginx.sh
#!/bin/bashactive_status=`netstat?-lntp|grep?nginx|wc?-l`if?[?$active_status?-gt?0?];?then ????exit?0else ????exit?1fi
?然后給腳本賦予執(zhí)行權(quán)限:chmod +x /work/script/check_nginx.sh
9.修改內(nèi)核參數(shù)
vi /etc/sysctl.conf
增加如下內(nèi)容:
net.ipv4.ip_nonlocal_bind?=?1??#允許忽視VIP的存在net.ipv4.ip_forward?=?1??#允許轉(zhuǎn)發(fā)
sysctl --system 使配置生效
五、安裝FastDFS依賴庫
1.安裝libevent依賴
解壓libevent源碼包:tar -zxvf libevent-2.1.11-stable.tar.gz
進(jìn)入源碼目錄:cd libevent-2.1.11-stable
編譯安裝前配置:./configure?
編譯安裝:make && make install
默認(rèn)安裝位置:/usr/local/lib
2.安裝libfasttcommon依賴
解壓libfasttcommon源碼包:tar -zxvf libfastcommon-1.0.41.tar.gz
進(jìn)入源碼目錄:cd libfastcommon-1.0.41
編譯安裝:./make.sh && ./make.sh install
默認(rèn)安裝位置:/usr/lib64
六、安裝部署Tracker服務(wù)和Storage服務(wù)
1.安裝fastdfs服務(wù)
解壓fastdfs源碼包:tar -zxvf fastdfs-6.01.tar.gz
進(jìn)入fastdfs源碼包:cd fastdfs-6.01
編譯安裝:./make.sh && ./make.sh install
2.fastdfs服務(wù)目錄信息
安裝完成后服務(wù)及腳本拷貝到/usr/bin 目錄,配置文件拷貝到/etc/fdfs目錄,啟動(dòng)腳本拷貝到/etc/init.d/目錄
3.注冊(cè)開機(jī)啟動(dòng)
chkconfig --add fdfs_trackerd
chkconfig fdfs_trackerd on
chkconfig --add fdfs_storaged
chkconfig fdfs_storaged on
4.數(shù)據(jù)目錄規(guī)劃
創(chuàng)建fdfs數(shù)據(jù)主目錄:mkdir /work/fdfs
創(chuàng)建tracker數(shù)據(jù)目錄:mkdir /work/fdfs/tracker
創(chuàng)建storage數(shù)據(jù)目錄:mkdir /work/fdfs/storage
5.配置tracker服務(wù)
將/etc/fdfs目錄下的tracker.conf.sample改為tracker.conf:mv tracker.conf.sample ?tracker.conf修改內(nèi)容如下:
將base_path=/home/yuqing/fastdfs 改為:/work/fdfs/tracker(該目錄為上面定義創(chuàng)建)
啟動(dòng)Tracker服務(wù):systemctl start fdfs_trackerd
6.配置storage服務(wù)
將/etc/fdfs目錄下的storage.conf.sample改為storage.conf:mv storage.conf.sample storage.conf修改內(nèi)容如下:
base_path=/home/yuqing/fastdfs 改為:base_path=/work/fdfs/storage(該目錄為上面定義創(chuàng)建)
store_path0=/home/yuqing/fastdfs 改為:store_path0=/work/fdfs/storage(該目錄為上面定義創(chuàng)建)
tracker_server=192.168.209.121:22122 改為:tracker_server=192.168.100.111:22122和tracker_server=192.168.100.112:22122
將/etc/fdfs/torage_ids.conf.sample 為storage_ids.conf,內(nèi)容修改為當(dāng)前group的storage節(jié)點(diǎn)信息:
100001? ? group1? ? 192.168.100.111
100002? ? group1? ? 192.168.100.112
啟動(dòng)Storage服務(wù):systemctl start fdfs_storaged
七、Nginx服務(wù)安裝配置
1.下載Nginx源碼包
官網(wǎng)地址:http://nginx.org/
下載地址:http://nginx.org/en/download.html
2.上傳并解壓Nginx源碼包及fastdfs插件包
tar -zxvf nginx-1.16.1.tar.gz
tar -zxvf fastdfs-nginx-module-1.21.tar.gz
3.編譯Nginx準(zhǔn)備
進(jìn)入解壓目錄:cd nginx-1.16.1
拷貝fastdfs插件包到nginx源碼目錄:mv ../fastdfs-nginx-module-1.21 .
執(zhí)行編譯準(zhǔn)備:./configure --prefix=/work/nginx \--with-stream \--add-module=fastdfs-nginx-module-1.21/src
注意:一定要有g(shù)cc和openssl編譯相關(guān)的依賴
4.編譯安裝Nginx
make && make install
5.注冊(cè)到系統(tǒng)服務(wù)
vi /usr/lib/systemd/system/nginx.service
[Unit]Description=nginxDocumentation=http://nginx.org/en/docs/After=network.target[Service]Type=forkingPIDFile=/work/nginx/logs/nginx.pidExecStartPre=/work/nginx/sbin/nginx?-t?-c?/work/nginx/conf/nginx.confExecStart=/work/nginx/sbin/nginx?-c?/work/nginx/conf/nginx.confExecReload=/bin/kill?-s?HUP?$MAINPIDExecStop=/bin/kill?-s?QUIT?$MAINPIDPrivateTmp=true[Install]WantedBy=multi-user.target
6.設(shè)置Nginx開機(jī)啟動(dòng)項(xiàng)
systemctl enable nginx
然后就能使用systemctl start/stop/status nginx管理nginx了
7.修改Nginx配置
vi /work/nginx/conf/nginx.conf
#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;}stream?{ ????upstream?tracker?{ ?????????server?192.168.100.111:22122?weight=1?max_fails=2?fail_timeout=10s; ?????????server?192.168.100.112:22122?weight=1?max_fails=2?fail_timeout=10s; ????} ????server?{ ????????listen???????7777; ????????proxy_timeout?5m; ????????proxy_pass?tracker; ????????proxy_connect_timeout?10s; ????}}http?{ ????include???????mime.types; ????default_type??application/octet-stream; ????sendfile????????on; ????keepalive_timeout??65; ????upstream?storage?{ ?????????server?192.168.100.111:8888?weight=1?max_fails=2?fail_timeout=10s; ?????????server?192.168.100.112:8888?weight=1?max_fails=2?fail_timeout=10s; ????} ????server?{ ????????listen???????80; ????????server_name??localhost; ???????? ????????location?/group1?{ ????????????proxy_pass?????????http://storage; ????????????proxy_set_header???Host?????????????$host; ????????????proxy_set_header???X-Real-IP????????$remote_addr; ????????????proxy_set_header???X-Forwarded-For??$proxy_add_x_forwarded_for; ????????} ???????? ????????error_page???500?502?503?504??/50x.html; ????????location?=?/50x.html?{ ????????????root???html; ????????} ????} ????server?{ ????????listen???????8888; ????????server_name??localhost; ????????location?/?{ ????????????alias?/work/fdfs/storage/data/; ????????????ngx_fastdfs_module; ????????} ????}}
8.配置nginx的fdfs插件
將/etc/fdfs下的http.conf.sample和mime.types.sample重命名為:http.conf和mime.types
將fastdfs-nginx-module-1.21/src下的mod_fastdfs.conf拷貝到/etc/fdfs下
修改mod_fastdfs.conf如下:
連接超時(shí)時(shí)間: connect_timeout=5
Tracker服務(wù)地址:tracker_server=192.168.100.111:22122? 和tracker_server=192.168.100.112:22122
Storage服務(wù)端口:storage_server_port=23000
如果文件ID的uri中包含/group**,則要設(shè)置為true:url_have_group_name = true
Storage配置的store_path0路徑,必須和storage.conf中的一致:store_path0=/work/fdfs/storage
其他詳細(xì)配置如下:
#?connect?timeout?in?seconds#?default?value?is?30sconnect_timeout=5#?network?recv?and?send?timeout?in?seconds#?default?value?is?30snetwork_timeout=10#?the?base?path?to?store?log?filesbase_path=/work/fdfs/storage#?if?load?FastDFS?parameters?from?tracker?server#?since?V1.12#?default?value?is?falseload_fdfs_parameters_from_tracker=true#?storage?sync?file?max?delay?seconds#?same?as?tracker.conf#?valid?only?when?load_fdfs_parameters_from_tracker?is?false#?since?V1.12#?default?value?is?86400?seconds?(one?day)storage_sync_file_max_delay?=?86400#?if?use?storage?ID?instead?of?IP?address#?same?as?tracker.conf#?valid?only?when?load_fdfs_parameters_from_tracker?is?false#?default?value?is?false#?since?V1.13use_storage_id?=?false#?specify?storage?ids?filename,?can?use?relative?or?absolute?path#?same?as?tracker.conf#?valid?only?when?load_fdfs_parameters_from_tracker?is?false#?since?V1.13storage_ids_filename?=?storage_ids.conf#?FastDFS?tracker_server?can?ocur?more?than?once,?and?tracker_server?format?is#??"host:port",?host?can?be?hostname?or?ip?address#?valid?only?when?load_fdfs_parameters_from_tracker?is?truetracker_server=192.168.100.111:22122tracker_server=192.168.100.112:22122#?the?port?of?the?local?storage?server#?the?default?value?is?23000storage_server_port=23000#?the?group?name?of?the?local?storage?servergroup_name=group1#?if?the?url?/?uri?including?the?group?name#?set?to?false?when?uri?like?/M00/00/00/xxx#?set?to?true?when?uri?like?${group_name}/M00/00/00/xxx,?such?as?group1/M00/xxx#?default?value?is?falseurl_have_group_name?=?true#?path(disk?or?mount?point)?count,?default?value?is?1#?must?same?as?storage.confstore_path_count=1#?store_path#,?based?0,?if?store_path0?not?exists,?it's?value?is?base_path#?the?paths?must?be?exist#?must?same?as?storage.confstore_path0=/work/fdfs/storage#?standard?log?level?as?syslog,?case?insensitive,?value?list:###?emerg?for?emergency###?alert###?crit?for?critical###?error###?warn?for?warning###?notice###?info###?debuglog_level=info#?set?the?log?filename,?such?as?/usr/local/apache2/logs/mod_fastdfs.log#?empty?for?output?to?stderr?(apache?and?nginx?error_log?file)log_filename=#?response?mode?when?the?file?not?exist?in?the?local?file?system##?proxy:?get?the?content?from?other?storage?server,?then?send?to?client##?redirect:?redirect?to?the?original?storage?server?(HTTP?Header?is?Location)response_mode=proxy#?the?NIC?alias?prefix,?such?as?eth?in?Linux,?you?can?see?it?by?ifconfig?-a#?multi?aliases?split?by?comma.?empty?value?means?auto?set?by?OS?type#?this?paramter?used?to?get?all?ip?address?of?the?local?host#?default?values?is?emptyif_alias_prefix=#?use?"#include"?directive?to?include?HTTP?config?file#?NOTE:?#include?is?an?include?directive,?do?NOT?remove?the?#?before?include#include?http.conf#?if?support?flv#?default?value?is?false#?since?v1.15flv_support?=?true#?flv?file?extension?name#?default?value?is?flv#?since?v1.15flv_extension?=?flv#?set?the?group?count#?set?to?none?zero?to?support?multi-group?on?this?storage?server#?set?to?0??for?single?group?only#?groups?settings?section?as?[group1],?[group2],?...,?[groupN]#?default?value?is?0#?since?v1.14group_count?=?1#?group?settings?for?group?#1#?since?v1.14#?when?support?multi-group?on?this?storage?server,?uncomment?following?section[group1]group_name=group1storage_server_port=23000store_path_count=1store_path0=/work/fdfs/storage#?group?settings?for?group?#2#?since?v1.14#?when?support?multi-group,?uncomment?following?section?as?neccessary#[group2]#group_name=group2#storage_server_port=23000#store_path_count=1#store_path0=/home/yuqing/fastdfs
八、服務(wù)啟動(dòng)及驗(yàn)證
分別啟動(dòng)keepalive、nginx、tracker、storage服務(wù)
查看服務(wù)是否正常服務(wù):
在任意Storage機(jī)器上查看集群狀態(tài):fdfs_monitor /etc/fdfs/storage.conf
九、Java客戶端測(cè)試
1.java項(xiàng)目Maven依賴
項(xiàng)目地址:https://github.com/tobato/FastDFS_Client目前客戶端主要依賴于SpringBoot,因此必須引入:??? FastDFS?依賴包:org.springframework.boot ???spring-boot-starter-parent ???2.0.0.RELEASE ??????? 將FastDFS引入項(xiàng)目:@Import(FdfsClientConfig.class)在application.yml當(dāng)中配置Fdfs相關(guān)參數(shù):fdfs: ??pool: ????#連接池最大數(shù)量 ????max-total:?200 ????#每個(gè)tracker地址的最大連接數(shù) ????max-total-per-key:?50 ????#連接耗盡時(shí)等待獲取連接的最大毫秒數(shù) ????max-wait-millis:?5000 ??so-timeout:?1500 ??connect-timeout:?600 ??thumb-image: ????width:?150 ????height:?150 ??tracker-list: ????-?192.168.100.110:7777或者fdfs: ??pool: ????#連接池最大數(shù)量 ????max-total:?200 ????#每個(gè)tracker地址的最大連接數(shù) ????max-total-per-key:?50 ????#連接耗盡時(shí)等待獲取連接的最大毫秒數(shù) ????max-wait-millis:?5000 ??so-timeout:?1500 ??connect-timeout:?600 ??thumb-image: ????width:?150 ????height:?150 ??tracker-list: ????-?192.168.100.111:22122 ????-?192.168.100.112:22122使用接口服務(wù)對(duì)Fdfs服務(wù)端進(jìn)行操作,主要接口包括:TrackerClient?-?TrackerServer接口GenerateStorageClient?-?一般文件存儲(chǔ)接口?(StorageServer接口)FastFileStorageClient?-?為方便項(xiàng)目開發(fā)集成的簡(jiǎn)單接口(StorageServer接口)AppendFileStorageClient?-?支持文件續(xù)傳操作的接口?(StorageServer接口)com.github.tobato ????fastdfs-client ????1.26.7
2.代碼測(cè)試
package?com.maxbill;import?com.github.tobato.fastdfs.FdfsClientConfig;import?com.github.tobato.fastdfs.domain.fdfs.MetaData;import?com.github.tobato.fastdfs.domain.fdfs.StorePath;import?com.github.tobato.fastdfs.domain.proto.storage.DownloadByteArray;import?com.github.tobato.fastdfs.service.FastFileStorageClient;import?lombok.extern.log4j.Log4j2;import?org.apache.commons.lang3.StringUtils;import?org.springframework.beans.factory.annotation.Autowired;import?org.springframework.context.annotation.Import;import?org.springframework.stereotype.Component;import?javax.annotation.PostConstruct;import?java.io.File;import?java.io.FileInputStream;import?java.text.DateFormat;import?java.text.SimpleDateFormat;import?java.util.*;@Log4j2@Component@Import(FdfsClientConfig.class)public?class?FdfsClientUtil?{????private?static?final?String?BASE_URL?=?"http://192.168.100.110:8888/";????@Autowired ????private?FastFileStorageClient?storageClient;????private?static?FdfsClientUtil?fdfsClientUtil;????@PostConstruct ????public?void?init()?{ ????????fdfsClientUtil?=?this; ????}????/** ?????*?文件上傳 ?????* ?????*?@param?file????文件信息 ?????*?@param?infoMap?文件擴(kuò)展信息 ?????*?@return?上傳路徑 ?????*/ ????public?static?Map?uploadFile(File?file,?Map ?infoMap)?{????????try?{????????????String?fileName?=?file.getName();????????????String?fileType?=?fileName.substring(fileName.lastIndexOf("\\")?+?1);????????????//String?fileType?=?FilenameUtils.getExtension(file.getName()) ????????????log.info("[fdfs-upload]-start?upload?file?...?"); ????????????log.info("[fdfs-upload]-request?upload?file?name:?{}",?fileName); ????????????log.info("[fdfs-upload]-request?upload?file?info:?{}",?infoMap); ????????????StorePath?path?=?fdfsClientUtil.storageClient.uploadFile(new?FileInputStream(file),?file.length(),?fileType,?getMetaData(infoMap)); ????????????log.info("[fdfs-upload]-upload?success?path:?{}",?path.getFullPath());????????????return?getResultMap(BASE_URL.concat(path.getFullPath()),?null); ????????}?catch?(Exception?e)?{ ????????????log.error("[fdfs-upload]-upload?file?exception?info:?{}",?e.getMessage());????????????return?getResultMap(null,?e.getMessage()); ????????} ????}????/** ?????*?下載文件 ?????* ?????*?@param?filePath?文件路徑標(biāo)識(shí) ?????*?@return?文件字節(jié) ?????*/ ????public?static?Map ?downloadFile(String?filePath)?{????????try?{ ????????????filePath?=?filePath.replace(BASE_URL,?""); ????????????StorePath?storePath?=?StorePath.parseFromUrl(filePath);????????????String?group?=?storePath.getGroup();????????????String?path?=?storePath.getPath(); ????????????log.info("[fdfs-download]-start?download?file?...?"); ????????????log.info("[fdfs-download]-request?download?file?group:?{}",?group); ????????????log.info("[fdfs-download]-request?download?file?path:?{}",?path); ????????????byte[]?data?=?fdfsClientUtil.storageClient.downloadFile(group,?path,?new?DownloadByteArray()); ????????????log.info("[fdfs-download]-request?download?file?success?...?");????????????return?getResultMap(data,?null); ????????}?catch?(Exception?e)?{ ????????????log.error("[fdfs-download]-download?file?exception?info:?{}",?e.getMessage());????????????return?getResultMap(null,?e.getMessage()); ????????} ????}????/** ?????*?刪除文件 ?????* ?????*?@param?filePath?文件路徑標(biāo)識(shí) ?????*?@return?操作結(jié)果 ?????*/ ????public?static?boolean?deleteFile(String?filePath)?{????????try?{ ????????????filePath?=?filePath.replace(BASE_URL,?""); ????????????StorePath?storePath?=?StorePath.parseFromUrl(filePath);????????????String?group?=?storePath.getGroup();????????????String?path?=?storePath.getPath(); ????????????log.info("[fdfs-delete]-start?delete?file?...?"); ????????????log.info("[fdfs-delete]-request?delete?file?group:?{}",?group); ????????????log.info("[fdfs-delete]-request?delete?file?path:?{}",?path); ????????????fdfsClientUtil.storageClient.deleteFile(storePath.getGroup(),?storePath.getPath()); ????????????log.info("[fdfs-delete]-request?delete?file?success?...?");????????????return?true; ????????}?catch?(Exception?e)?{ ????????????log.error("[fdfs-delete]-delete?file?exception?info:?{}",?e.getMessage());????????????return?false; ????????} ????}????/** ?????*?查看文件元信息 ?????* ?????*?@param?filePath?文件路徑標(biāo)識(shí) ?????*?@return?文件信息 ?????*/ ????public?static?Map ?getFileInfo(String?filePath)?{????????try?{ ????????????filePath?=?filePath.replace(BASE_URL,?""); ????????????StorePath?storePath?=?StorePath.parseFromUrl(filePath);????????????String?group?=?storePath.getGroup();????????????String?path?=?storePath.getPath(); ????????????log.info("[fdfs-meta]-start?meta?file?...?"); ????????????log.info("[fdfs-meta]-request?meta?file?group:?{}",?group); ????????????log.info("[fdfs-meta]-request?meta?file?path:?{}",?path); ????????????Map ?infoMap?=?new?HashMap<>(); ????????????infoMap.put("createPath",?filePath); ????????????Set ?metaData?=?fdfsClientUtil.storageClient.getMetadata(storePath.getGroup(),?storePath.getPath()); ????????????log.info("[fdfs-meta]-request?meta?file?success?...?");????????????if?(null?!=?metaData?&&?!metaData.isEmpty())?{ ????????????????metaData.forEach(meta?->?{ ????????????????????infoMap.put(meta.getName(),?meta.getValue()); ????????????????}); ????????????}????????????return?getResultMap(infoMap,?null); ????????}?catch?(Exception?e)?{ ????????????log.error("[fdfs-meta]-meta?file?exception?info:?{}",?e.getMessage());????????????return?getResultMap(null,?e.getMessage()); ????????} ????}????/** ?????*?封裝附件元信息 ?????* ?????*?@param?infoMap?自定義數(shù)據(jù) ?????*?@return?附件元信息 ?????*/ ????private?static?Set ?getMetaData(Map ?infoMap)?{????????if?(null?!=?infoMap?&&?!infoMap.isEmpty())?{ ????????????Set ?metaDataSet?=?new?HashSet<>();????????????for?(String?key?:?infoMap.keySet())?{ ????????????????metaDataSet.add(new?MetaData(key,?infoMap.get(key))); ????????????}????????????return?metaDataSet; ????????}?else?{ ????????????DateFormat?df?=?new?SimpleDateFormat("yyyy-MM-dd?HH:mm:ss"); ????????????Set ?metaDataSet?=?new?HashSet<>(); ????????????metaDataSet.add(new?MetaData("createUser",?"MaxBill")); ????????????metaDataSet.add(new?MetaData("createDate",?df.format(new?Date())));????????????return?metaDataSet; ????????} ????}????/** ?????*?封裝結(jié)果信息 ?????* ?????*?@param?data?數(shù)據(jù) ?????*?@param?info?信息 ?????*?@return?操作結(jié)果 ?????*/ ????private?static?Map ?getResultMap(Object?data,?String?info)?{ ????????Map ?resultMap?=?new?HashMap<>();????????if?(StringUtils.isEmpty(info))?{ ????????????resultMap.put("flag",?true); ????????????resultMap.put("data",?data); ????????????resultMap.put("info",?"success"); ????????}?else?{ ????????????resultMap.put("flag",?false); ????????????resultMap.put("info",?info); ????????????resultMap.put("data",?null); ????????}????????return?resultMap; ????} }