戰(zhàn):從雙Tracker到雙Storage的完整指南)
文件存儲(chǔ)這種基礎(chǔ)設(shè)施平時(shí)不起眼一到容量滿了或者節(jié)點(diǎn)宕了就容易雞飛狗跳。我前后用FastDFS搭過(guò)好幾次文件集群從單機(jī)玩具到帶實(shí)際流量的生產(chǎn)環(huán)境一點(diǎn)一點(diǎn)把坑踩平這篇筆記就是圍繞FastDFS高可用集群部署整理的。重點(diǎn)不是讓你背命令而是把每一步為什么這么做講透順便把那些網(wǎng)上教程里經(jīng)常一筆帶過(guò)的坑標(biāo)出來(lái)。這篇內(nèi)容適合誰(shuí)看準(zhǔn)備把文件存儲(chǔ)從單機(jī)搬到多機(jī)、需要撐住一定并發(fā)上傳下載的運(yùn)維和開(kāi)發(fā)或者被領(lǐng)導(dǎo)一句話安排“搞個(gè)高可用文件存儲(chǔ)”但自己還沒(méi)有完整實(shí)戰(zhàn)過(guò)的人。你對(duì)FastDFS的基本概念有點(diǎn)印象但沒(méi)在真實(shí)環(huán)境里完整搭過(guò)一套那這篇文章的實(shí)操價(jià)值會(huì)比較直接。你還要清楚一點(diǎn)高可用不是某個(gè)參數(shù)開(kāi)一下就能有的它是“控制面冗余 數(shù)據(jù)面冗余 客戶端正確配置 運(yùn)維監(jiān)控”共同作用的結(jié)果。FastDFS恰好把這幾個(gè)維度的分工做得非常清晰理解了這個(gè)模型后面所有部署動(dòng)作都不會(huì)跑偏。1. 為什么自建文件存儲(chǔ)要糾結(jié)高可用1.1 從“一臺(tái)機(jī)器存文件”的痛說(shuō)起單機(jī)文件存儲(chǔ)你平時(shí)根本感受不到問(wèn)題上傳下載都正常磁盤(pán)也夠大一切歲月靜好。但只要磁盤(pán)壞道、系統(tǒng)分區(qū)滿、進(jìn)程被OOM殺掉、機(jī)房斷電業(yè)務(wù)方立刻就會(huì)收到一堆“圖片裂了”“附件打不開(kāi)”“上傳失敗”的反饋。更難受的是單機(jī)模式下沒(méi)有第二個(gè)副本數(shù)據(jù)損壞了就是真沒(méi)了恢復(fù)成本極高。MySQL要搞主從Kafka要搞多副本Redis要搞哨兵但很多團(tuán)隊(duì)在文件存儲(chǔ)上卻默認(rèn)“先能用就行”。等到文件量上去再想從單機(jī)平滑遷到集群中間要處理存量數(shù)據(jù)遷移、目錄結(jié)構(gòu)調(diào)整、客戶端指向變更遠(yuǎn)比一開(kāi)始就按集群來(lái)部署麻煩。所以我建議如果你判斷這個(gè)文件服務(wù)未來(lái)半年不會(huì)下線就直接按高可用模型設(shè)計(jì)別給自己留返工的量。1.2 高可用到底要覆蓋哪些故障高可用不是說(shuō)“多買(mǎi)幾臺(tái)機(jī)器裝一遍”就完事你得先列清楚要對(duì)抗哪些故障進(jìn)程級(jí)別的故障tracker或storage進(jìn)程意外退出可能是代碼bug也可能是內(nèi)存不足被系統(tǒng)殺掉。節(jié)點(diǎn)級(jí)別的故障整臺(tái)服務(wù)器宕機(jī)、硬件故障、機(jī)房斷電這個(gè)級(jí)別最考驗(yàn)架構(gòu)。網(wǎng)絡(luò)層面的故障網(wǎng)卡異常、交換機(jī)端口兜住、iptables策略誤改節(jié)點(diǎn)的服務(wù)還活著但相互之間已經(jīng)不通。磁盤(pán)層面的故障磁盤(pán)損壞導(dǎo)致文件系統(tǒng)只讀或者壞道導(dǎo)致讀寫(xiě)IO卡住。對(duì)應(yīng)到FastDFS里tracker負(fù)責(zé)解決調(diào)度面的故障storage配合group機(jī)制解決數(shù)據(jù)面的故障而客戶端配置多個(gè)tracker_server則是你使用層面必須補(bǔ)上的最后一環(huán)。四者缺一個(gè)你對(duì)外宣稱(chēng)“高可用”都是心虛的。2. FastDFS集群的幾個(gè)關(guān)鍵設(shè)計(jì)2.1 tracker和storage不是主從關(guān)系很多人剛接觸FastDFS會(huì)下意識(shí)套用MySQL主從那種思維覺(jué)得tracker也要搞主備。實(shí)際上tracker和storage之間完全不是主從關(guān)系多個(gè)tracker之間地位平等沒(méi)有選主、沒(méi)有數(shù)據(jù)同步。storage啟動(dòng)時(shí)會(huì)把自己注冊(cè)到配置文件里列出的所有tracker上之后每隔一段時(shí)間持續(xù)上報(bào)心跳。這種設(shè)計(jì)的優(yōu)勢(shì)是簡(jiǎn)單可靠任何一臺(tái)tracker掛了剩下的tracker繼續(xù)提供調(diào)度服務(wù)客戶端換一個(gè)地址就行。缺點(diǎn)也很明顯所有tracker都不可用時(shí)整個(gè)集群的上傳下載入口會(huì)斷掉但已經(jīng)落盤(pán)的文件數(shù)據(jù)不會(huì)因此丟失。所以生產(chǎn)環(huán)境我至少會(huì)放兩臺(tái)tracker讓“調(diào)度可用性”和“數(shù)據(jù)可用性”解耦。2.2 group才是數(shù)據(jù)冗余的基本單位FastDFS的“組”概念很多人一開(kāi)始理解不到位。一個(gè)group下面放多個(gè)storage節(jié)點(diǎn)同一個(gè)group里的storage節(jié)點(diǎn)會(huì)互相同步文件不同group之間沒(méi)有任何自動(dòng)同步??梢院?jiǎn)單類(lèi)比成group是一個(gè)備份域文件傳到了group1那group1里的所有storage都會(huì)有這份文件的副本而group2完全不知道這份文件的存在。這帶來(lái)兩個(gè)直接結(jié)論一個(gè)group里只能有一個(gè)storage時(shí)不管外面有多少tracker這個(gè)group的數(shù)據(jù)冗余度依舊是1沒(méi)有高可用。想把文件同時(shí)放到兩個(gè)不同group比如group1和group2各存一份FastDFS本身不會(huì)替你做必須由上層應(yīng)用雙寫(xiě)或者靠外部同步任務(wù)。所以最基礎(chǔ)的高可用方案不是“5臺(tái)機(jī)器亂配”而是至少兩個(gè)tracker加一個(gè)雙storage的group。2.3 容量規(guī)劃與副本率怎么定同group的storage數(shù)量就是文件的副本數(shù)。兩臺(tái)storage等于雙副本三臺(tái)是三副本。副本率越高磁盤(pán)有效容量越低因?yàn)橐环菸募级喾菘臻g。我整理了一個(gè)簡(jiǎn)單的參考關(guān)系group內(nèi)storage數(shù)實(shí)際副本數(shù)有效容量占比建議11100%只建議測(cè)試環(huán)境2250%一般生產(chǎn)環(huán)境最低配置3333%重要數(shù)據(jù)或?qū)σ恢滦砸蟾邥r(shí)使用很多人一上來(lái)就三副本覺(jué)得副本越多越安全。其實(shí)FastDFS的同步是異步的三副本和雙副本都解決不了短時(shí)間窗口內(nèi)的數(shù)據(jù)不一致問(wèn)題盲目堆副本只會(huì)讓磁盤(pán)成本和同步壓力一起上漲。我的習(xí)慣是基礎(chǔ)業(yè)務(wù)雙副本兜底特別重要的文件額外做離線冷備或傳一份到對(duì)象存儲(chǔ)。3. 環(huán)境準(zhǔn)備與版本選型3.1 操作系統(tǒng)和基礎(chǔ)依賴近幾年新建服務(wù)器一般都會(huì)選AlmaLinux、Rocky Linux這類(lèi)系統(tǒng)熱詞里提到Rocky Linux 9我也是在Rocky Linux 9上操作的。FastDFS官方文檔雖然老很多例子還停留在CentOS 6/7但代碼本身的兼容性沒(méi)那么差內(nèi)核版本和系統(tǒng)庫(kù)對(duì)它的影響不大。編譯之前先裝好依賴否則后面一堆“缺頭文件”的報(bào)錯(cuò)會(huì)把你折磨壞dnf install -y gcc gcc-c make cmake libevent libevent-devel openssl-devel pcre-devel zlib-devel git wget這里有個(gè)容易忽略的點(diǎn)libevent和pcre是fastdfs-nginx-module編譯時(shí)的硬依賴。如果只裝FastDFS本體不裝這兩個(gè)開(kāi)發(fā)包也能編譯但等到你集成nginx模塊時(shí)才補(bǔ)裝就得重新編譯一遍nginx白白浪費(fèi)時(shí)間。3.2 源碼版本匹配是個(gè)大坑FastDFS本體和libfastcommon是分開(kāi)維護(hù)的兩個(gè)倉(cāng)庫(kù)都在GitHub上。編譯時(shí)必須保證版本匹配否則會(huì)出現(xiàn)結(jié)構(gòu)體字段對(duì)不上、編譯失敗或者能編譯但運(yùn)行時(shí)崩潰的問(wèn)題。fastdfs-nginx-module也存在同樣的匹配問(wèn)題它的版本不能太舊我見(jiàn)過(guò)有人拿著好幾年前的分支去配新版FastDFS編到一半直接報(bào)錯(cuò)。我的建議是全部選官方release中的較新版本不要圖新鮮拉master分支。具體版本號(hào)可根據(jù)你下載當(dāng)天的release來(lái)確定只要三者用同一時(shí)期的版本即可。下載命令示例wget https://github.com/happyfish100/libfastcommon/archive/refs/tags/V1.0.53.tar.gz wget https://github.com/happyfish100/fastdfs/archive/refs/tags/V6.06.tar.gz wget https://github.com/happyfish100/fastdfs-nginx-module/archive/refs/tags/V1.22.tar.gz如果GitHub下載慢可以找國(guó)內(nèi)鏡像站但一定要核對(duì)壓縮包里的版本號(hào)別拿錯(cuò)。3.3 目錄和磁盤(pán)規(guī)劃FastDFS的tracker和storage都通過(guò)base_path指定基礎(chǔ)路徑用來(lái)放日志和運(yùn)行數(shù)據(jù)。storage還要單獨(dú)指定store_path也就是真實(shí)文件存儲(chǔ)目錄。我習(xí)慣把所有數(shù)據(jù)盤(pán)統(tǒng)一掛載到/data/fastdfs下再按角色區(qū)分子目錄。規(guī)劃時(shí)記住兩個(gè)禁忌tracker的base_path不要和storage的store_path放在同一個(gè)目錄免得日志和數(shù)據(jù)互相干擾。storage的base_path和store_path也不要指向同一個(gè)路徑啟動(dòng)時(shí)FastDFS會(huì)明確拒絕。磁盤(pán)選型上大量小文件場(chǎng)景對(duì)機(jī)械盤(pán)的隨機(jī)IO非常不友好。如果是相冊(cè)、頭像、附件這類(lèi)海量小文件建議至少用SSD如果只是存一些較大的視頻、壓縮包機(jī)械盤(pán)還可以接受。FastDFS本身沒(méi)有內(nèi)置壓縮和加密能力磁盤(pán)的吞吐上限就是整個(gè)文件服務(wù)的性能上限。4. 部署步驟tracker多節(jié)點(diǎn)4.1 編譯安裝FastDFS本體先編譯安裝libfastcommon再編譯FastDFS本體順序不能反。FastDFS的make腳本會(huì)自動(dòng)找libfastcommon的安裝目錄如果先裝本體再裝依賴運(yùn)行時(shí)就會(huì)缺符號(hào)。tar zxvf libfastcommon-V1.0.53.tar.gz cd libfastcommon-V1.0.53 ./make.sh ./make.sh install看到install完成之后繼續(xù)tar zxvf fastdfs-V6.06.tar.gz cd fastdfs-V6.06 ./make.sh ./make.sh install安裝完成后可執(zhí)行文件會(huì)放到/usr/bin下比如fdfs_trackerd、fdfs_storaged、fdfs_upload_file都在這里。默認(rèn)配置目錄是/etc/fdfs你可以從源碼目錄里的conf下拷貝一份模板過(guò)去mkdir -p /etc/fdfs cp /path/to/fastdfs-V6.06/conf/* /etc/fdfs/啟動(dòng)程序時(shí)如果報(bào)找不到libfastcommon.so多半是動(dòng)態(tài)庫(kù)路徑?jīng)]生效。解決方法是執(zhí)行一次ldconfig或者把動(dòng)態(tài)庫(kù)所在目錄加進(jìn)/etc/ld.so.conf。4.2 tracker.conf關(guān)鍵參數(shù)說(shuō)明修整/etc/fdfs/tracker.conf這一步很關(guān)鍵。以我的模板為例bind_addr port22122 base_path/data/fastdfs/tracker work_threads4 store_lookup0 store_groupgroup1bind_addr留空表示監(jiān)聽(tīng)所有網(wǎng)卡地址如果機(jī)器有多個(gè)IP想指定內(nèi)網(wǎng)網(wǎng)卡可以填具體IP。work_threads控制網(wǎng)絡(luò)處理線程數(shù)生產(chǎn)環(huán)境一般不開(kāi)太低4到8都是常見(jiàn)值。store_lookup和store_group決定了新文件寫(xiě)入哪個(gè)group。store_lookup0表示輪詢所有g(shù)roup1表示強(qiáng)制寫(xiě)入store_group指定的group2表示按每個(gè)group剩余空間比例分配。如果你的集群只有一個(gè)group這三個(gè)值怎么配結(jié)果都一樣。當(dāng)你有多個(gè)group且希望不同類(lèi)型的文件寫(xiě)入不同group時(shí)可以用store_lookup1配合store_group指定。4.3 啟動(dòng)tracker并驗(yàn)證編譯安裝后配置模板里有一堆參數(shù)但你實(shí)際要改的并不多。改完base_path、store_lookup這些關(guān)鍵項(xiàng)就可以啟動(dòng)了mkdir -p /data/fastdfs/tracker fdfs_trackerd /etc/fdfs/tracker.conf start啟動(dòng)后確認(rèn)進(jìn)程存在ps -ef | grep fdfs_trackerdtracker的日志在base_path/logs/trackerd.log啟動(dòng)報(bào)錯(cuò)看日志比猜原因靠譜得多。多節(jié)點(diǎn)tracker的操作很簡(jiǎn)單把配置文件和可執(zhí)行文件同步到另一臺(tái)機(jī)器改一下base_path啟動(dòng)即可。tracker之間不需要互填對(duì)方地址它們不是靠互相通信來(lái)工作的。5. storage節(jié)點(diǎn)部署與group規(guī)劃5.1 storage.conf關(guān)鍵參數(shù)說(shuō)明storage的配置重點(diǎn)是group_name、store_path和tracker_server列表。我的模板如下group_namegroup1 port23000 base_path/data/fastdfs/storage store_path_count1 store_path0/data/fastdfs/storage/data tracker_server192.168.10.11:22122 tracker_server192.168.10.12:22122同一group下的所有storage節(jié)點(diǎn)group_name必須一致否則它們各自為政不會(huì)互相同步。tracker_server這一項(xiàng)可以配置多行把全部tracker地址都列上。storage啟動(dòng)后會(huì)依次向這些tracker發(fā)心跳達(dá)到“一臺(tái)tracker掛了其他tracker仍然知道這個(gè)storage存在”的效果。store_path_count是存儲(chǔ)路徑數(shù)量如果只有一塊數(shù)據(jù)盤(pán)就填1有多塊盤(pán)就按順序繼續(xù)加store_path1、store_path2。每一路store_path必須是獨(dú)立的磁盤(pán)掛載點(diǎn)FastDFS會(huì)盡量把文件分布到不同store_path上。5.2 同組多storage怎么配對(duì)最簡(jiǎn)單的生產(chǎn)拓?fù)涫莾膳_(tái)storage同屬group1形成雙副本。我做容量評(píng)估時(shí)看得比較重的一個(gè)點(diǎn)是同一group里的storage節(jié)點(diǎn)磁盤(pán)容量最好基本一致。因?yàn)槲募闹鞲北緯?huì)均衡分發(fā)到每個(gè)storage如果某臺(tái)機(jī)器磁盤(pán)特別小它很容易先被寫(xiě)滿后續(xù)同步就會(huì)一直失敗拖累整個(gè)group的健康度。我在實(shí)際項(xiàng)目里見(jiàn)過(guò)這種情況一個(gè)group里一臺(tái)機(jī)器4TB另一臺(tái)只有1TB結(jié)果1TB那臺(tái)很快就滿了tracker按剩余空間分配文件時(shí)又優(yōu)先把新文件分到4TB那臺(tái)導(dǎo)致小盤(pán)節(jié)點(diǎn)的同步任務(wù)積壓日志里全是同步失敗。后來(lái)我干脆把小盤(pán)機(jī)器換掉問(wèn)題立刻消失。高可用設(shè)計(jì)里容量不齊比性能不齊更要命。5.3 啟動(dòng)storage和等待同步storage啟動(dòng)方式和tracker類(lèi)似mkdir -p /data/fastdfs/storage/data fdfs_storaged /etc/fdfs/storage.conf start啟動(dòng)后會(huì)有個(gè)初始化過(guò)程首次啟動(dòng)會(huì)創(chuàng)建256個(gè)一級(jí)目錄和對(duì)應(yīng)的二級(jí)目錄文件量大的時(shí)候這個(gè)過(guò)程可能要等一會(huì)兒。啟動(dòng)成功后用fdfs_monitor檢查集群狀態(tài)fdfs_monitor /etc/fdfs/client.conf輸出里會(huì)看到tracker列表和storage列表。重點(diǎn)看storage狀態(tài)正常應(yīng)該是ACTIVE。如果狀態(tài)是OFFLINE先查防火墻和端口通不通再看storage日志。同組兩臺(tái)storage都處于ACTIVE后FastDFS開(kāi)始自動(dòng)同步同步速度和文件總大小、磁盤(pán)IO直接相關(guān)。6. 對(duì)外文件訪問(wèn)Nginx和fastdfs-nginx-module6.1 命令行先驗(yàn)證上傳流程配置好storage之后先不用急著上Nginx用命令行跑一次全流程。創(chuàng)建client.confbase_path/data/fastdfs/client tracker_server192.168.10.11:22122 tracker_server192.168.10.12:22122上傳測(cè)試文件fdfs_upload_file /etc/fdfs/client.conf /tmp/test.jpg正常會(huì)返回類(lèi)似group1/M00/00/00/wKg...jpg的字符串。這一串里M00表示store_path000/00是兩級(jí)目錄后面是文件ID。如果這個(gè)環(huán)節(jié)失敗問(wèn)題基本出在tracker和storage的連通性上先不要碰Nginx免得排查范圍變大。6.2 編譯nginx時(shí)加載模塊FastDFS原生不提供HTTP下載能力必須用fastdfs-nginx-module配合Nginx。模塊編譯是常見(jiàn)重災(zāi)區(qū)我建議把nginx源碼和模塊源碼放到一起統(tǒng)一編譯wget https://nginx.org/download/nginx-1.24.0.tar.gz tar zxvf nginx-1.24.0.tar.gz cd nginx-1.24.0 ./configure --add-module/path/to/fastdfs-nginx-module/src make make install如果configure階段報(bào)pcre、openssl相關(guān)的錯(cuò)說(shuō)明前面開(kāi)發(fā)包裝少了補(bǔ)齊之后再重新configure。模塊編譯進(jìn)nginx后需要在nginx.conf里增加locationlocation /group1/M00 { ngx_fastdfs_module; }同時(shí)還要確保/etc/fdfs下有mod_fastdfs.conf通常從fastdfs-nginx-module源碼目錄拷貝模板后修改。重點(diǎn)要改group_name和tracker_server其他參數(shù)保持模板默認(rèn)即可。6.3 Nginx和storage是否同機(jī)部署fastdfs-nginx-module有兩種工作模式。Nginx和storage在同一臺(tái)機(jī)器時(shí)模塊直接讀本地磁盤(pán)文件性能最好Nginx在獨(dú)立節(jié)點(diǎn)時(shí)模塊會(huì)通過(guò)tracker查到文件實(shí)際所在的storage然后回源拉文件相當(dāng)于多了一層代理轉(zhuǎn)發(fā)。如果量不大獨(dú)立Nginx節(jié)點(diǎn)也沒(méi)問(wèn)題但要注意從Nginx到storage的23000端口必須放通。流量一旦上來(lái)回源鏈路的網(wǎng)絡(luò)帶寬和延遲就會(huì)被放大所以我更推薦Nginx與storage同機(jī)部署前面再掛一層負(fù)載均衡或CDN。這樣本地讀盤(pán)路徑最短高并發(fā)下載時(shí)能明顯減少瓶頸。6.4 一個(gè)讓新手抓狂的M00目錄問(wèn)題很多人在上傳成功后用瀏覽器訪問(wèn)Nginx時(shí)得到404直接用curl檢查返回的是“404 Not Found”。這時(shí)候先確認(rèn)兩件事mod_fastdfs.conf里的storage_path是否指向了正確的store_path0。Nginx進(jìn)程是否真的用了帶模塊的二進(jìn)制執(zhí)行nginx -V看有沒(méi)有--add-module記錄。常見(jiàn)原因還有一個(gè)模塊按URL里的M00匹配store_path0但如果你在nginx.conf里的location寫(xiě)的是/group1/M00/后面又加了alias就會(huì)二次拼接路徑很容易錯(cuò)。直接用官方推薦的location /group1/M00 { ngx_fastdfs_module; }不要畫(huà)蛇添足加alias。7. 高可用驗(yàn)證與故障演練7.1 驗(yàn)證tracker調(diào)度面的高可用配置兩個(gè)tracker后先把client.conf里的tracker_server只留第一個(gè)停掉第一臺(tái)tracker再執(zhí)行上傳命令。如果你只配置了一個(gè)地址這時(shí)會(huì)直接報(bào)連接失敗。把第二個(gè)tracker_server補(bǔ)上再試上傳就能成功因?yàn)榭蛻舳嗽诘谝粋€(gè)tracker不可用時(shí)會(huì)自動(dòng)嘗試下一個(gè)。這個(gè)測(cè)試的意義是提醒你tracker本身再多如果客戶端、storage端沒(méi)有把全部tracker_address都配上高可用就是空談。我在交付項(xiàng)目時(shí)檢查項(xiàng)目里所有FastDFS客戶端配置和storage.conf看的就是tracker_server列表是否完整。7.2 驗(yàn)證storage數(shù)據(jù)面的高可用storage層面的驗(yàn)證稍微講究一點(diǎn)。上傳一個(gè)文件后立刻停掉其中一臺(tái)storage再?gòu)牧硪慌_(tái)訪問(wèn)文件是有可能失敗的因?yàn)镕astDFS的文件同步是異步的剛上傳到主storage還沒(méi)同步給同組其他節(jié)點(diǎn)你就把主storage停了數(shù)據(jù)自然取不到。正確做法是先等同步完成。用fdfs_monitor觀察待同步文件數(shù)變成0再停節(jié)點(diǎn)做驗(yàn)證。生產(chǎn)環(huán)境里你要接受這個(gè)同步窗口的存在不能把FastDFS當(dāng)成強(qiáng)一致系統(tǒng)。如果業(yè)務(wù)對(duì)剛剛上傳的文件有一致性要求要么應(yīng)用層雙寫(xiě)要么在文件上傳后加一個(gè)短暫不可讀的容忍期。7.3 從故障演練反推監(jiān)控項(xiàng)故障演練不是演給別人看的練完要反過(guò)來(lái)檢查監(jiān)控覆蓋。我會(huì)在演練前后看tracker日志和storage日志確認(rèn)故障切換過(guò)程是否對(duì)客戶端有感知、同步線程是否正?;謴?fù)。監(jiān)控項(xiàng)至少要有三個(gè)tracker上活躍storage數(shù)量少于預(yù)期就告警。storage磁盤(pán)剩余空間低于閾值就告警。storage同步狀態(tài)出現(xiàn)大量未同步文件時(shí)就告警。這三項(xiàng)cover住了絕大多數(shù)FastDFS故障都能在用戶感知之前被發(fā)現(xiàn)。8. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄8.1 編譯安裝階段的問(wèn)題我在編譯階段遇到最多的問(wèn)題就是libfastcommon安裝后找不到庫(kù)文件。表現(xiàn)為fdfs_trackerd啟動(dòng)時(shí)提示error while loading shared libraries: libfastcommon.so。這其實(shí)是動(dòng)態(tài)鏈接庫(kù)路徑?jīng)]刷新執(zhí)行l(wèi)dconfig之后即可解決。另一個(gè)問(wèn)題是fastdfs-nginx-module和新版FastDFS源碼版本不兼容。報(bào)錯(cuò)信息往往指向某個(gè)結(jié)構(gòu)體里沒(méi)有某某字段。出現(xiàn)這種問(wèn)題先說(shuō)結(jié)論換新版本的模塊源碼別自己在源代碼里改字段名因?yàn)槟氵€得同步改模塊邏輯很容易引入隱藏bug。8.2 啟動(dòng)與注冊(cè)失敗的原因storage啟動(dòng)后在fdfs_monitor里看不到或者狀態(tài)是OFFLINE常見(jiàn)原因按優(yōu)先級(jí)排查防火墻沒(méi)放行tracker的22122和storage的23000端口。很多人在本機(jī)能ping通但TCP不通一查就是firewalld默認(rèn)區(qū)域規(guī)則沒(méi)放行。storage.conf里的tracker_server配置有誤或者漏寫(xiě)了某個(gè)tracker地址。端口被占用比如有一臺(tái)機(jī)器同時(shí)裝了storage和tracker又把端口都配成23000必然沖突。服務(wù)器時(shí)間不一致。FastDFS雖然對(duì)時(shí)間同步要求不算苛刻但偏差太大時(shí)心跳和同步會(huì)變得很奇怪建議所有節(jié)點(diǎn)統(tǒng)一裝chrony。8.3 上傳成功但下載失敗怎么定位上傳成功說(shuō)明tracker和storage的鏈路是通的問(wèn)題集中在Nginx模塊或網(wǎng)絡(luò)回源兩處。我按步驟來(lái)排查curl -I http://nginx-host/group1/M00/00/00/wKg...jpg先看HTTP狀態(tài)碼。403或404優(yōu)先檢查mod_fastdfs.conf的group_name、storage_path是否配置正確。連接超時(shí)或502優(yōu)先檢查Nginx節(jié)點(diǎn)到storage的23000端口以及tracker_server是否能訪問(wèn)到。還有個(gè)容易被忽略的細(xì)節(jié)模塊的error_log要打開(kāi)日志里會(huì)直接記錄它嘗試訪問(wèn)的物理路徑看到路徑后基本一眼就能定位問(wèn)題。8.4 同步狀態(tài)異常和存儲(chǔ)節(jié)點(diǎn)DELETED如果同組storage之間同步一直不完成先看storage日志里的同步錯(cuò)誤。最常見(jiàn)的是目標(biāo)節(jié)點(diǎn)磁盤(pán)滿了或者網(wǎng)絡(luò)IO異常導(dǎo)致同步線程反復(fù)重試。這種問(wèn)題處理起來(lái)并不難但一定要趁早因?yàn)橥椒e壓越多數(shù)據(jù)窗口越危險(xiǎn)。如果你曾經(jīng)在tracker上用fdfs_monitor delete刪除過(guò)某個(gè)storage它的狀態(tài)會(huì)變成DELETED。之后即使節(jié)點(diǎn)還活著tracker也不會(huì)再讓它參與同步。恢復(fù)方式是在該storage上重新啟動(dòng)或重置狀態(tài)必要時(shí)清空data目錄再重新加入。清空data目錄前要確認(rèn)該節(jié)點(diǎn)上沒(méi)有未同步到其他節(jié)點(diǎn)的獨(dú)有文件否則數(shù)據(jù)就真的丟了。8.5 常見(jiàn)問(wèn)題速查現(xiàn)象排查方向常見(jiàn)解法上傳返回錯(cuò)誤28磁盤(pán)空間不足擴(kuò)容或清理文件storage狀態(tài)OFFLINE防火墻/端口/配置放行端口核對(duì)tracker_server上傳成功但Nginx 404模塊配置路徑錯(cuò)誤檢查mod_fastdfs.conf和locationNginx日志找不到物理文件storage_path錯(cuò)誤修正store_path指向同步進(jìn)度一直不動(dòng)目標(biāo)磁盤(pán)滿或網(wǎng)絡(luò)異?;謴?fù)空間或網(wǎng)絡(luò)后重啟storage時(shí)間導(dǎo)致的怪問(wèn)題節(jié)點(diǎn)時(shí)間漂移部署chrony統(tǒng)一時(shí)間同步9. 部署之后還要想清楚的事9.1 高可用不等于數(shù)據(jù)絕對(duì)安全FastDFS的同組復(fù)制解決的是“單節(jié)點(diǎn)故障”問(wèn)題不是“誤刪和邏輯損壞”問(wèn)題。文件被誤刪或覆蓋時(shí)同組另一臺(tái)storage的副本會(huì)被同步刪除你沒(méi)有機(jī)會(huì)反悔。我在生產(chǎn)環(huán)境里會(huì)把FastDFS當(dāng)成“高性能可用存儲(chǔ)”真正的災(zāi)備依賴另外一套離線備份機(jī)制比如定期把文件冷備到對(duì)象存儲(chǔ)。9.2 容器化部署要謹(jǐn)慎熱詞里有Kubernetes相關(guān)的內(nèi)容但FastDFS本身并不是為云原生設(shè)計(jì)的。用Docker單跑一個(gè)storage簡(jiǎn)單真正麻煩的是把storage做成StatefulSet、掛PVC、管理擴(kuò)縮容。如果團(tuán)隊(duì)已經(jīng)有K8s基礎(chǔ)設(shè)施且網(wǎng)絡(luò)、存儲(chǔ)插件都比較完整可以考慮容器化如果只是想省事裸機(jī)或虛擬機(jī)二進(jìn)制部署反而更穩(wěn)。我個(gè)人經(jīng)驗(yàn)是沒(méi)有強(qiáng)烈的“必須容器化”訴求別把FastDFS硬塞進(jìn)K8s里給自己找活干。9.3 最后的實(shí)用習(xí)慣我每次部署完FastDFS都會(huì)寫(xiě)一個(gè)巡檢腳本定時(shí)抓取fdfs_monitor的輸出解析出已同步數(shù)量、待同步數(shù)量和磁盤(pán)使用率。巡檢腳本不復(fù)雜但非常能救命它的作用就是讓你在用戶反饋“圖裂了”之前先一步發(fā)現(xiàn)storage同步積壓或磁盤(pán)寫(xiě)滿的問(wèn)題。另一個(gè)建議是改動(dòng)任何配置之前先備份conf目錄。FastDFS的配置文件不多但每個(gè)參數(shù)都能影響集群行為改完忘了備份出了事連回滾的參照都沒(méi)有。把整套部署過(guò)程沉淀成文檔或者Ansible腳本下次擴(kuò)容新節(jié)點(diǎn)時(shí)能少踩一半坑。這個(gè)小習(xí)慣也是我后來(lái)每次搭建文件存儲(chǔ)集群時(shí)效率能提升不少的原因。