需要搭建一個高性能的文件系統(tǒng)?我推薦你試試它.....(上)
前語
今天給咱們介紹的是FastDFS,一個開源的分布式文件體系,也是入職之后觸摸到的一個技能,因為公司項目事務需求,服務器里存了上億量級的文件,所以運用了這么一項技能來存儲這些文件,我也就隨之開端了解這項技能,并且在這兒和咱們一同從0到1地開端了解它。
FastDFS介紹
FastDFS是一個以C言語開發(fā)的開源輕量級分布式文件體系,由阿里巴巴開發(fā)并開源。它對文件進行辦理,功用包含:文件存儲、文件同步、文件拜訪(上傳、下載)等。處理了大容量存儲和負載均衡的問題。特別合適以文件為載體的在線服務,如相冊網(wǎng)站、視頻網(wǎng)站等等。
FastDFS為互聯(lián)網(wǎng)量身定制,充分考慮了冗余備份、負載均衡、線性擴容等機制,并注重高可用、高性能等目標,運用FastDFS很容易建立一套高性能的文件服務器集群供給文件上傳、下載等服務。
從0,自己的一些疑問:FastDFS過期了嗎?
信任這也是許多同學想要問的一些問題,我還沒有了解這個技能的時分,也相同有這樣的疑問。
首要,現(xiàn)在有許多文件存儲都會挑選像七牛云、阿里云OSS等云服務,為什么要自己搭一套文件服務器添加維護本錢呢?
其次,這并不是面試的熱點,乃至在入職之前自己都沒有觸摸過,乃至乃至,沒有聽說過,反倒是那些搶手的技能,就算自己不主動去了解,當遇到的時分,大致也能知道是用來干嘛的。
那么我來說說我的理解,首要這個技能一定是還沒有過期的,因為有些特別的文件,因為信息安全顧忌等原因,不會挑選公有云服務器,還有依據(jù)本錢考慮,還有許多的中型互聯(lián)網(wǎng)公司仍然是依據(jù)FastDFS來做自己的文件服務器的。別的,F(xiàn)astDFS作為一個分布式服務器,對輕量級、橫向擴展、容災備份、高可用、高性能、負載均衡都有著充分的考慮,依舊是一個文件服務器的不貳之選。
那么為什么這樣一項技能在現(xiàn)在卻很少有人了解呢?
榜首,我以為是需求所致,與其它事務相比,需求存儲許多文件的事務相對之下仍是比較少。假如文件存儲量不大,依照傳統(tǒng)的文件存儲方法也不會有什么大的問題。
第二,現(xiàn)在有七牛云、阿里云OSS等公司供給對象存儲,加之國內(nèi)關于”上云“的追捧,就很少有人樂意自己搭服務器來做文件存儲服務了。
當然關于一個技能人來說,各式各樣的技能都得去學習,去適應,所以這篇文章期望能夠協(xié)助到感興趣的同學,或是在作業(yè)中遇到高量級文件存儲的同學,F(xiàn)astDFS是不錯的挑選。
傳統(tǒng)文件存儲方法
這是傳統(tǒng)文件存儲的方法,服務器上乃至不需求裝任何的應用,只需求有SFTP服務,咱們就能夠?qū)憣拇a,完結(jié)文件的CRUD。
這樣的優(yōu)點便是很便利,只需求一臺機器,幾行代碼就能搞定文件的存儲,可是這種方法的瓶頸和缺點是很明顯的。
首要,關于單體服務器來說,不考慮宕機的情況,單體文件服務器的帶寬、磁盤容量是有上限的,那么當文件的體積占滿了整個磁盤,咱們只能挑選擴展,可是這種單體服務器的方法,關于擴容就不太友好了,咱們能夠想想,難道咱們要將原有的硬盤數(shù)據(jù)拷到一個更大的硬盤里,然后替換硬盤嗎?
除了擴展以外,咱們還需求面對一個問題,便是文件的查找,假如咱們將一切文件都寄存到一同,文件的數(shù)量假如到了一定的數(shù)量,就會面對磁盤IO速度瓶頸,不知道咱們有沒有遇到過下圖中這種場景:
假如咱們需求在一個磁盤中找到某個文件,假如沒有一個途徑,或許途徑下有許多文件,那么體系就會掃描磁盤,咱們都知道,計算機體系結(jié)構中,關于速度,CPU>內(nèi)存>硬盤,假如在出產(chǎn)環(huán)境下,真的需求存儲許多的文件,假定存儲的是用戶的頭像,那么用戶每次打開APP,就需求等待個十幾秒,自己的頭像才會顯示,那這個app估計沒有人會運用吧。
有同學可能會說,那咱們能夠運用緩存啊,Redis的String類型是能夠存儲二進制數(shù)據(jù)的,并且Redis的String類型是一個Key對應一個值,查詢功率會很高。確實這樣在查詢功率上能夠到達,可是咱們依照一張圖片1M來計算,緩存又能存多少張圖片呢?很顯然這是一個十分貴重的方法。
方才咱們考慮的都是服務器不宕機的狀況,那么假定服務器宕機,那么咱們就無法再供給數(shù)據(jù)存儲服務;假如硬盤損壞,那么一切的數(shù)據(jù)都將丟掉。
分布式文件體系
上文中說了傳統(tǒng)文件存儲方法的一些缺點和壞處,這其實也是一切“單點“的壞處,無論是單點數(shù)據(jù)庫、或許單點緩存、又或許是單點網(wǎng)關、單點注冊中心,都在往分布式集群的方向開展。
總結(jié)一下,單點文件體系大致有這些缺點:
1. 磁盤容量存在瓶頸
2. IO速度存在瓶頸
3. 宕機、硬盤損壞數(shù)據(jù)丟掉的危險
那么關于文件體系,咱們怎么運用分布式的方法來處理上述的缺點呢?
-
處理磁盤容量瓶頸
上文中說到,單服務器文件體系存在磁盤容量瓶頸的原因是磁盤無法很便利的進行擴容,咱們一般需求從硬件的層面來考慮擴容硬盤,如:替換大容量硬盤。
這種方法顯然是不現(xiàn)實的,因為替換硬盤意味著咱們需求關服務器,出產(chǎn)環(huán)境服務器關停三十秒都是很嚴重的出產(chǎn)事故,所以咱們只能運用服務器橫向擴展的方法,假如不能替換硬盤,那么咱們就加服務器。
- 這樣咱們就能夠運用多臺服務器共同來構成咱們的文件體系了,每個文件服務器都是一個獨立的節(jié)點,來存儲不同的文件,依據(jù)特定的邏輯(這兒需求自己寫),來決議文件需求存儲到哪個文件服務器中。這樣即便服務器容量滿了,咱們也還能夠持續(xù)橫向擴展,理論上這樣咱們的文件體系是沒有容量上限的。
-
處理IO速度瓶頸
方才咱們處理了單點文件服務器容量瓶頸,可是假如某臺或許某幾臺服務器上的文件數(shù)量過多(查詢功率降低),或許有許多的用戶拜訪某一臺服務器,仍是會形成IO速度瓶頸。那么要怎么處理這個問題。
咱們能夠想一想相似的事例——MySQL數(shù)據(jù)庫。
眾所周知,MySQL的數(shù)據(jù)也是存在硬盤中的,而咱們在寫SQL句子的時分,為了保證查詢功率,一般會避免全表掃描,而是通過索引讓其找到咱們對應的那條數(shù)據(jù)。
所以咱們也能夠通過這種方法,避免全盤掃描或許大范圍掃描,而咱們都知道,操作體系關于文件是有一個天然的索引的,便是咱們的多級目錄。FastDFS也正是利用了這個來添加咱們文件IO的功率的,這個暫且不提,下文中會展示。
-
處理宕機、硬盤損壞數(shù)據(jù)丟掉的危險
能否處理這個問題才是分布式文件體系和單機文件體系最底子的區(qū)別,因為無論是單機磁盤容量瓶頸仍是IO速度瓶頸,咱們都能夠通過添加硬件裝備來處理,只不過不太便利且本錢太高罷了。而單機形式是絕對無法處理宕機形成的文件服務失效,或許硬盤損壞形成的數(shù)據(jù)丟掉的,因為數(shù)據(jù)只存在一份。
那么咱們思考一下分布式文件體系是怎么來處理這些問題的。
- 首要咱們需求處理宕機的問題,如上圖,咱們有多個文件服務器節(jié)點,可是假如咱們自己寫邏輯來決議某個文件應該存哪個服務器上,假定那個服務器此時宕機了,文件依舊是無法存入的,當然咱們能夠持續(xù)寫邏輯來決議假如宕機了之后應該怎么辦,可是FastDFS中現(xiàn)已替咱們實現(xiàn)了,Tracker節(jié)點能夠協(xié)助咱們挑選文件應該上傳到哪個服務器上,并且還能夠在某個節(jié)點宕機的時分挑選其從節(jié)點(備份節(jié)點)進行文件上傳,防止因為宕機形成的無法操作文件。
那么依據(jù)上面這幅圖,第二個問題也就很好理解了,假定某臺服務器硬盤損壞了,那么數(shù)據(jù)依舊會存在備份,即便備份服務器也損壞了,數(shù)據(jù)也只會丟掉一部分,而不會全部丟掉。
FastDFS
上面說了這么多的關于分布式文件體系能夠處理的一些實際問題,那么就直接切入今天的主題——FastDFS。
- 全體架構
FastDFS文件體系由兩大部分組成,客戶端和服務端。
客戶端一般指咱們寫的程序(當然FastDFS也供給了客戶端測試程序),例如咱們運用Java去銜接FastDFS、操作文件,那么咱們的Java程序便是一個客戶端,F(xiàn)astDFS供給專有API拜訪,目前供給了C、Java和PHP等編程言語的API,用來拜訪FastDFS文件體系。
服務端由兩個部分組成,分別是跟蹤器(Tracker)和存儲節(jié)點(Storage)。
跟蹤器(Tracker):主要做調(diào)度作業(yè),相似微服務注冊中心,在內(nèi)存中記載集群存儲節(jié)點的storage的狀況信息,是客戶端和服務端存儲節(jié)點storage的樞紐,因為相關信息全部在內(nèi)存中,每個Storage在發(fā)動后會銜接Tracker,奉告自己所屬的group等信息,并周期性發(fā)送心跳,TrackerServer的性能十分高,假定咱們有上百個Storage節(jié)點,咱們只需求3臺左右的Tracker就足夠了。
存儲節(jié)點(Storage)用于存儲文件,包含文件和文件屬性(metaData)都保存到服務器磁盤上,完結(jié)文件辦理的一切功用:文件存儲、文件同步和文件拜訪等。
Storage以group為組織單位,一個group內(nèi)能夠包含多臺Storage機器,數(shù)據(jù)互為備份,總存儲空間以group內(nèi)容量最小的storage為準(木桶),所以主張一個group內(nèi)的機器存儲空間巨細應該盡量相同,以免形成空間的糟蹋。Storage在榜首次發(fā)動時,會在每一個存儲目錄里創(chuàng)立二級目錄,合計256 * 256個目錄,咱們上傳的文件會以Hash的方法被路由到其間某個子目錄下。
- 作業(yè)流程
- 上傳
下載
- 客戶端發(fā)送下載懇求,Tracker依據(jù)文件信息,回來Storage地址和端口(客戶端也能夠通過自己存儲的文件方位直接拜訪Storage)。
- 客戶端拜訪Storage,Storage依據(jù)file_id(組名、虛擬磁盤、二級目錄、文件名)查找到文件,回來文件數(shù)據(jù)。
- 當客戶端建議上傳懇求時,會先拜訪Tracker,因為Storage定時向Tracker發(fā)送狀況信息,所以Tracker中存有一切Storage Group的信息。
- Tracker依據(jù)本地的Storage Group信息,為客戶端上傳的文件分配Storage Group,并回來給客戶端。
- 客戶端拿到Storage Group地址和端口后,上傳文件到指定的Storage Group中。
- Storage回來文件的途徑信息和文件名。
- Client將文件信息存儲到本地。
- 單機裝置
-
裝置前準備
-
裝置
裝置FastDFS需求兩個源碼包,分別是libfastcommon-1.0.43.tar.gz和fastdfs-6.06.tar.gz。
這兒附上作者的github地址:fastdfs,libfastcommon,咱們能夠到這兒下載對應的包。
下載完結(jié)后,將其上傳到咱們的linux服務器中
[root@localhost SoftwareInstallPackage]# ll 總用量 971800 -rw-r--r--. 1 root root 809328 9月 9 23:10 fastdfs-6.06.tar.gz -rw-r--r--. 1 root root 166526 9月 9 23:10 libfastcommon-1.0.43.tar.gz
-
分別運轉(zhuǎn)tar -zxvf fastdfs-6.06.tar.gz和tar -zxvf libfastcommon-1.0.43.tar.gz對其進行解壓,解壓后進入libfastcommon-1.0.43目錄中運轉(zhuǎn)sh make.sh,運轉(zhuǎn)完畢后運轉(zhuǎn)sh make.sh install,然后進入fastdfs-6.06目錄中執(zhí)行相同的操作,即可完結(jié)裝置。
裝置成功后進入/usr/bin目錄下,假如存在許多fdfs開頭的命令,則證明裝置成功。
[root@localhost bin]# ll|grep fdfs -rwxr-xr-x. 1 root root 362208 9月 9 23:17 fdfs_appender_test -rwxr-xr-x. 1 root root 361984 9月 9 23:17 fdfs_appender_test1 -rwxr-xr-x. 1 root root 348872 9月 9 23:17 fdfs_append_file -rwxr-xr-x. 1 root root 348480 9月 9 23:17 fdfs_crc32 -rwxr-xr-x. 1 root root 348904 9月 9 23:17 fdfs_delete_file -rwxr-xr-x. 1 root root 349640 9月 9 23:17 fdfs_download_file -rwxr-xr-x. 1 root root 349592 9月 9 23:17 fdfs_file_info -rwxr-xr-x. 1 root root 364912 9月 9 23:17 fdfs_monitor -rwxr-xr-x. 1 root root 349128 9月 9 23:17 fdfs_regenerate_filename -rwxr-xr-x. 1 root root 1280096 9月 9 23:17 fdfs_storaged -rwxr-xr-x. 1 root root 372080 9月 9 23:17 fdfs_test -rwxr-xr-x. 1 root root 367200 9月 9 23:17 fdfs_test1 -rwxr-xr-x. 1 root root 512312 9月 9 23:17 fdfs_trackerd -rwxr-xr-x. 1 root root 349832 9月 9 23:17 fdfs_upload_appender -rwxr-xr-x. 1 root root 350848 9月 9 23:17 fdfs_upload_file
- 而/etfc/fdfs目錄中寄存了一切的FastDFS的裝備文件:
然后進入/etc/fdfs,這兒寄存了一切fastDFS的裝備文件
[root@localhost fdfs]# ll 總用量 32 #客戶端銜接裝備 -rw-r--r--. 1 root root 1909 9月 9 23:17 client.conf.sample #存儲節(jié)點裝備 -rw-r--r--. 1 root root 10246 9月 9 23:17 storage.conf.sample -rw-r--r--. 1 root root 620 9月 9 23:17 storage_ids.conf.sample #追尋器裝備 -rw-r--r--. 1 root root 9138 9月 9 23:17 tracker.conf.sample
- 最后一步,咱們需求進入FastDFS裝置包解壓后的conf目錄下,找到http.conf和mime.types將其復制到/etc/fdfs目錄下。
[root@localhost conf]# pwd /WorkSpace/Software/fastdfs-6.06/conf [root@localhost conf]# cp http.conf /etc/fdfs/ [root@localhost conf]# cp mime.types /etc/fdfs/
- 這樣咱們就完結(jié)了FastDFS的裝置。
-
裝備文件詳解
裝置完結(jié)后需求先把裝備文件裝備好才能夠正常發(fā)動,這兒會貼上tracker.conf、storage.conf、client.conf的一切裝備項,就當作一個裝備模板吧,裝備的時分能夠直接copy。
首要是tracker.conf:
# 這個裝備文件是否 不收效(這兒筆者個人以為,改成是否收效會比較好),true代表不收效,false代表收效 disabled = false # 是否綁定ip,假如不填就代表一切的ip都供給服務,常用于服務器有多個ip但只期望一個ip供給服務 bind_addr = # Tracker的端口號 port = 22122 # 銜接超時的時刻 單位為s connect_timeout = 5 # Tracker的網(wǎng)絡超時,單位為秒。發(fā)送或接納數(shù)據(jù)時,假如在超時時刻后還不能發(fā)送或接納數(shù)據(jù),則本次網(wǎng)絡通信失利。 network_timeout = 60 # Tracker服務的數(shù)據(jù)寄存地址,這個目錄有必要是存在的 base_path = /home/yuqing/fastdfs # 體系供給的最大銜接數(shù) max_connections = 1024 # 接納線程數(shù) 主張為1 accept_threads = 1 # 作業(yè)線程數(shù) 引薦設置為CPU線程數(shù) work_threads = 4 # 最小網(wǎng)絡緩存 默許值為8KB min_buff_size = 8KB # 最大網(wǎng)絡緩存 默許值為128KB max_buff_size = 128KB # 上傳文件挑選group的方法 # 0:輪詢 # 1:指定一個group # 2:負載均衡,挑選一個最多閑暇空間的group來上傳文件 store_lookup = 2 # 當store_lookup設置為1時,有必要在這個參數(shù)中設置一個group用來上傳文件 # 當store_lookup設置不為1時,這個參數(shù)無效 store_group = group2 # 挑選group中的哪一個storage服務器用來上傳文件 # 0:輪詢 # 1:依照ip地址排序,ip最小的那個服務器用來上傳文件 # 2:依據(jù)優(yōu)先級進行排序,上傳優(yōu)先級在storage裝備文件中進行裝備,裝備項為upload_priority store_server = 0 # 挑選storage服務器中的哪一個目錄進行上傳,一個storage中能夠有多個寄存文件的base_path(能夠理解為磁盤分區(qū)) # 0:輪詢 # 2:負載均衡,挑選剩余空間最多的一個途徑來上傳文件 store_path = 0 # 挑選哪個storage服務器作為下載文件的服務器 # 0:輪詢 # 1:文件上傳到哪個storage服務器就去哪個storage服務器上下載 download_server = 0 # storage服務器上為其他應用保存的空間 # 能夠用絕對值或許百分比:10G或許1024M或許1024K或許XX.XX% # 假如同組中的服務器硬盤巨細相同 以最小的為準,到達最小的那個值,則無法再進行上傳 reserved_storage_space = 20% # 規(guī)范日志級別從小到大順次:debuglog_level = info # 操作體系運轉(zhuǎn)FastDFS的用戶組,不填默許便是發(fā)動FastDFS的用戶組 run_by_group= # 操作體系運轉(zhuǎn)FastDFS的用戶,不填默許便是發(fā)動FastDFS的用戶 run_by_user = # 能夠銜接到此Tracker Server的IP范圍 # 比如: # allow_hosts=10.0.1.[1-15,20] # allow_hosts=host[01-08,20-25].domain.com # allow_hosts=192.168.5.64/26 allow_hosts = * # 同步日志緩存到硬盤的時刻 # 默許十秒一次(Tracker的日志默許是先寫在內(nèi)存里的) sync_log_buff_interval = 10 # 查看storage服務器存活狀況的距離時刻 check_active_interval = 120 # 線程棧巨細 需求大于64KB # 默許值256KB # 線程棧越大 work_thread能發(fā)動的就越少 thread_stack_size = 256KB # 當storage server IP地址改動時,集群是否自動調(diào)整。注:只有在storage server進程重啟時才完結(jié)自動調(diào)整。 # 默以為true storage_ip_changed_auto_adjust = true # storage 同步文件最大延遲時刻 # 默以為一天 86400秒 # 注:本參數(shù)并不影響文件同步進程。本參數(shù)僅在下載文件時,判別文件是否現(xiàn)已被同步完結(jié)的一個閾值(經(jīng)驗值) storage_sync_file_max_delay = 86400 # 存儲服務器同步一個文件需求消耗的最大時刻,缺省為300s,即5分鐘。 # 注:本參數(shù)并不影響文件同步進程。本參數(shù)僅在下載文件時,作為判別當前文件是否被同步完結(jié)的一個閾值(經(jīng)驗值) storage_sync_file_max_time = 300 # 是否運用小文件兼并,默以為false # trunk_file能夠理解為一個容器,專門用來寄存小文件的 # 含有許多個slot(槽),每個槽寄存一個小文件 use_trunk_file = false # trunk file給小文件分配的最小字節(jié)數(shù)。比如文件只有16個字節(jié),體系也會分配slot_min_size個字節(jié)。 slot_min_size = 256 # 只有文件巨細<=這個參數(shù)值的文件,才會兼并存儲。假如一個文件的巨細大于這個參數(shù)值,將直接保存到一個文件中(即不選用兼并存儲方法)。 slot_max_size = 1MB # 兼并存儲的trunk file巨細,至少4MB,缺省值是64MB。不主張設置得過大。 trunk_alloc_alignment_size = 256 # 兼并后trunk file的接連可用空間(槽)是否兼并,默以為true(防止產(chǎn)生碎片) trunk_free_space_merge = true # 刪去沒有運用的trunk_files delete_unused_trunk_files = false # trunk file的最大巨細,有必要要大于4MB trunk_file_size = 64MB # 是否提早創(chuàng)立trunk file 默以為false trunk_create_file_advance = false # 創(chuàng)立trunk file的起始(榜首次)時刻點 默以為2:00 trunk_create_file_time_base = 02:00 # 創(chuàng)立trunk file的時刻距離 默以為1天 86400秒 trunk_create_file_interval = 86400 # 提早創(chuàng)立trunk_file時,需求到達的閑暇trunk巨細 trunk_create_file_space_threshold = 20G # trunk初始化時,是否查看可用空間是否被占用 trunk_init_check_occupying = false # 是否無條件從trunk binlog中加載trunk可用空間信息 # FastDFS缺省是從快照文件storage_trunk.dat中加載trunk可用空間, # 該文件的榜首行記載的是trunk binlog的offset,然后從binlog的offset開端加載 trunk_init_reload_from_binlog = false # 緊縮trunk binlog日志的最小時刻距離,0代表從不緊縮 trunk_compress_binlog_min_interval = 86400 # 緊縮trunk binlog日志的時刻距離 0代表從不緊縮 trunk_compress_binlog_interval = 86400 # 首次緊縮trunk binlog的時刻 trunk_compress_binlog_time_base = 03:00 # trunk binlog的最大備份 0代表無備份 trunk_binlog_max_backups = 7 # 是否運用storage_id作為區(qū)別storage的標識 use_storage_id = false # use_storage_id 設置為true,才需求設置本參數(shù) # 在文件中設置組名、server ID和對應的IP地址,拜見源碼目錄下的裝備示例:conf/storage_ids.conf storage_ids_filename = storage_ids.conf # 文件名中存儲服務器的id類型,值為: # ip:存儲服務器的ip地址 # id:存儲服務器的服務器id # 此參數(shù)僅在use_storage_id設置為true時有用 # 默許值為id id_type_in_filename = id # 是否運用符號鏈接的方法 # 假如設置為true 一個文件將占用兩個文件 符號鏈接指向原始文件 store_slave_file_use_link = false # 是否定時切割error.log true只支撐一天一次 rotate_error_log = false # error.log切割時刻 error_log_rotate_time = 00:00 # 是否緊縮舊error_log日志 compress_old_error_log = false # 緊縮幾天前的errorlog,默許7天前 compress_error_log_days_before = 7 # error log按巨細切割 # 設置為0表示不按文件巨細切割,否則當error log到達該巨細,就會切割到新文件中 rotate_error_log_size = 0 # 日志寄存時刻 # 0表示從不刪去舊日志 log_file_keep_days = 0 # 是否運用銜接池 use_connection_pool = true # 銜接池最大閑暇時刻 connection_pool_max_idle_time = 3600 # 本tracker服務器的默許HTTP端口 http.server_port = 8080 # 距離幾秒查看storage http服務器的存活 # <=0代表從不查看 http.check_alive_interval = 30 # 查看storage的存活狀況的類型 # tcp:銜接上就能夠,但不發(fā)送懇求也不獲取響應 # http storage有必要回來200 http.check_alive_type = tcp # 查看storage狀況的uri http.check_alive_uri = /status.html