導讀
篇幅較長,干貨滿滿,需花費較長時間,轉載請注明出處!
互聯網環境中的文件如何存儲?
- 不能存本地應用服務器
- NFS(采用mount掛載)
- HDFS(適合大文件)
- FastDFS(強力推薦👍)
- 雲存儲(有免費和收費的,不推薦,使用前可以看該公司實力怎么樣,別文件都存上去了,過2年公司破產了,損失慘重呀,嗚嗚嗚~~~)
互聯網環境中的文件如何進行HTTP訪問?
Web服務器:Nginx(本案例使用Nginx,還不會用Nginx的小伙伴,請看我另一篇博客:點我直達)、Apache等等。
FastDFS介紹
FastDFS是什么?
- FastDFS是一個C編寫的開源的高性能分布式文件系統(Distributed File System,簡稱DFS)
- 它由淘寶開發平台部資深架構師余慶開發,論壇:http://bbs.chinaunix.net/forum-240-1.html
- 它對文件進行管理,功能包括:文件存儲、文件同步、文件訪問(文件上傳、文件下載)等,解決了大容量存儲和負載均衡的問題
- 特別適合以文件為載體的在線服務,如相冊網站、視頻網站、電商等等。特別適合以中小文件(建議范圍:4KB<file_size<500mb)為載體的在線服務
- FastDFS為互聯網量身定制,充分考慮了冗余備份、負載均衡、線性擴容等機制,並注重高可用、高性能等指標,使用FastDFS很容易搭建一套高性能的文件服務器集群提供文件上傳、下載等服務
- github:https://github.com/happyfish100/fastdfs
技術文檔
鏈接: https://pan.baidu.com/s/1BpPwJBg2mR8CvqOiKj2rDQ 密碼: ocj5
流程圖
實際比這復雜的多

FastDFS架構原理分析(重點)
架構分析
FastDFS系統有三個角色:跟蹤服務器(Tracker Server)、存儲服務器(Storage Server)和客戶端(Client)。
Tracker Server:跟蹤服務器
- 主要做調度工作,並對Storage Server起到負載均衡的作用
- 負責管理所有的Storage Server和group,每個storage在啟動后連接Tracker,告知自己所屬group等信息,並保存周期性心跳。
- Tracker Server可以有多台,Tracker Server之間是相互平等關系同時提供服務,Tracker Server不存在單點故障。客戶端請求Tracker Server采用輪詢方式,如果請求的Tracker無法提供服務則換另一個Tracker。
Storage Server:存儲服務器
- 主要提供容量和備份服務
- 以group為單位,不同group之間互相獨立,每個group內可以有多台storage server,數據互為備份。
- 采用分組存儲方式的好處是靈活,可控性強,比如上傳文件時,可以由客戶端直接指定上傳到的組也可以由Tracker進行調度選擇。
- 一個分組的存儲服務器的訪問壓力較大時,可以在該組增加存儲服務器來擴充服務能力(縱向擴容)。當系統容量不足時,可以增加組來擴充存儲容量(橫向擴容)。
Client:客戶端
- 上傳下載數據的服務器,也就是我們自己的項目所部署在的服務器

存儲策略
為了支持大容量,存儲節點(服務器)采用分卷(或分組)的組織方式。存儲系統由一個或多個卷組成,卷與卷之間的文件是相互獨立的,所有卷的文件容量累加就是整個存儲系統中的文件容量。一個卷可以由一台或多台存儲服務器組成,一個卷下的存儲服務器中的文件都是相同的,卷中的多台存儲服務器起到了冗余備份和負載均衡的作用。
在卷中增加服務器時,同步已有的文件由系統自動完成,同步完成后,系統自動將新增服務器切換到線上提供服務。當存儲空間不足或即將耗盡時,可以動態加載卷,只需要增加一台或多台服務器,並將它們配置為一個新的卷,這樣就擴大了存儲系統的容量。
Storage狀態收集
Storage Server會通過配置連接集群中所有的Tracker Server,定時向他們報告自己的狀態,包括磁盤剩余空間、文件上傳下載次數等統計信息。
Storage Server有7個狀態,如下
- FDFS_STORAGE_STATUS_INIT ->初始化,尚未得到同步已有數據的源服務器
- FDFS_STORAGE_STATUS_WAIT_SYNC ->等待同步,已得到同步已有數據的源服務器
- FDFS_STORAGE_STATUS_SYNCING ->同步中
- FDFS_STORAGE_STATUS_DELETED ->已刪除,該服務器從本組中摘除
- FDFS_STORAGE_STATUS_OFFLINE ->離線
- FDFS_STORAGE_STATUS_ONLINE ->在線,尚不能提供服務
- FDFS_STORAGE_STATUS_ACTIVE ->在線,可以提供服務
文件上傳流程分析

流程說明
1、Tracker Server收集Storage Server的狀態信息
1.1、Storage Server定時向已知的tracker server(可以是多個)發送磁盤剩余空間、文件同步狀態、文件上傳下載次數等統計信息
1.2、Storage Server會連接整個集群中所有的Tracker Server,向它們報告自己的狀態
2、選擇Tracker server
2.1、當集群中不止一個Tracker Server時,由於Tracker之間是完全對等的關系,客戶端在upload文件時可以任意選擇一個Tracker
3、選擇存儲的group
當Tracker接收到upload file的請求時,會為該文件分配一個可存儲該文件的group,支持如下規則
3.1、Round robin,所有的group間輪詢(默認)
3.2、Specified group,指定某一個確定的group
3.3、Load balance,剩余存儲空間多的,group優先
4、選擇Storage Server
當選定group后,Tracker會在group內選擇一個Storage Server給客戶端,支持如下選擇Storage的規則
4.1、Round robin,在group內的所有Storage間輪詢(默認)
4.2、First server ordered by ip,按ip排序
4.3、First server ordered by priority,按優先級排序(優先級在Storage上配置)
5、選擇Storage path
當分配好Storage server后,客戶端將向Storage發送寫文件請求,Storage將會為文件分配一個數據存儲目錄,支持如下規則(在Storage配置文件中可以通過store_path*參數來設置,該參數可以設置多個,通過*來區別)
5.1、Round robin,多個存儲目錄間輪詢
5.2、剩余存儲空間最多的優先
6、生成fileid
選定存儲目錄之后,Storage會為文件生一個fileid,由源Storage server ip、文件創建時間、文件大小、文件crc32和一個隨機數拼接而成,然后將這個二進制串進行base64編碼,轉換為可打印的字符串。
7、選擇兩級目錄
當選定存儲目錄之后,Storage會為文件分配一個fileid,每個存儲目錄下有兩級256*256的子目錄,Storage會按文件fileid進行兩次hash,路由到其中一個子目錄,然后將文件以fileid為文件名存儲到該子目錄下。
8、生成文件名
當文件存儲到某個子目錄后,既認為該文件存儲成功,接下來會為該文件生成一個文件名,文件名由group、存儲目錄、兩級子目錄、fileid、文件后綴名(由客戶端指定,主要用於區分文件類型)拼接而成。
文件同步分析
寫文件時,客戶端將文件寫至group內一個Storage Server既認為寫文件成功,Storage Server寫完文件后,會由后台線程將文件同步至group內其他的Storage Server。
同步規則總結如下
- 只在本組內的Storage Server之間進行同步
- 源頭數據才需要同步,備份數據不需要再次同步,否則就構成閉環了
- 上述第二條規則有個例外,就是新增一台Storage Server時,由已有的一台Storage Server將已有的所有數據(包括源頭數據和備份數據)同步給該新增服務器

每個Storage寫文件后,同時會寫一份binlog,binlog里不包含文件數據,只包含文件名等元信息,這份binlog用於后台同步,Storage會記錄向group內其他Storage同步的進度,以便重啟后能接上次的進度繼續同步;進度以時間戳的方式進行記錄,所以最好能保證集群內所有Server的時鍾保持同步。
文件下載流程分析

客戶端upload file成功后,會拿到一個Storage生成的文件名,接下來客戶端根據這個文件名即可訪問到該文件。
流程說明
1、Tracker Server收集Storage Server的狀態信息
1.1、Storage Server定時向已知的Tracker Server(可以是多個)發送磁盤剩余空間、文件同步狀態、文件上傳下載次數等統計信息。
1.2、Storage Server會連接整個集群中所有的Tracker Server,向他們報告自己的狀態。
2、選擇Tracker Server
2.1、跟upload file一樣,在download file時客戶端可以選擇任意Tracker Server
3、選擇可用的Storage Server
3.1、client發送download請求給某個Tracker,必須帶上文件名信息,Tracker從文件名中解析出文件的group、路徑信息、文件大小、創建時間、源Storage Server ip等信息,然后為該請求選擇一個Storage用來服務讀請求。
3.2、由於group內的文件同步是在后台異步進行的,所以有可能出現在讀的時候,文件還沒有同步到某些Storage Server上,為了盡量避免訪問到這樣的Storage,Tracker按照如下規則選擇group內可讀的Storage
3.2.1、該文件上傳到的源頭Storage - 源頭Storage只要存活着,肯定包含這個文件,源頭的地址被編碼在文件名中。
3.2.2、文件創建時間戳 == Storage被同步到時間戳 且(當前時間 - 文件創建時間戳) > 文件同步最大時間 - 文件創建后,認為經過最大同步時間后,肯定已經同步到其他Storage了。
3.2.3、文件創建時間戳 < Storage被同步到的時間戳。 - 同步時間戳之前的文件確定已經同步
3.2.4、(當前時間 - 文件創建時間戳) > 同步延遲閾值。 經過同步延遲閾值時間,認為文件肯定已經同步了
FastDFS安裝
需求
- Tracker Server:
- Storage Server:
注:Tracker和Storage安裝,安裝過程都一樣,配置文件有差異
安裝gcc環境

yum install -y gcc-c++ gcc
安裝libevent(高版本可忽略,保險起見安裝)
FastDFS依賴libevent庫

yum install -y libevent
安裝libfastcommon
下載地址:
https://github.com/happyfish100/libfastcommon/releases

補充
也可以用wget方式聯網下載,這里我是提前下載到本地客戶端,將包拖進linux中
若wget命令不能使用,請執行:yum install -y wget
wget方式:
wget https://github.com/happyfish100/libfastcommon/archive/V1.0.43.tar.gz

創建文件夾,用於存放安裝包

將下載后的包放到該目錄下
解壓縮

編譯並安裝

拷貝libfastcommon.so文件至/usr/lib目錄(高版本可忽略此步)
cp /usr/lib64/libfastcommon.so /usr/lib/
安裝FastDFS
下載地址
https://github.com/happyfish100/fastdfs/releases

解壓縮

編譯與安裝

拷貝FastDFS目錄下的文件到/etc/fdfs目錄下

cp /cyb/soft/fastdfs-6.06/conf/* /etc/fdfs
=========================分割線======================================================
-----------------Tracker和Storage共同安裝步驟結束!!!----------------------------
------------------Tracker和Storage只是配置不同!!!!-----------------------------
=========================分割線======================================================
Tracker Server 配置(虛擬機名:CentOS 6-FastDFS-01)
修改/etc/fdfs/tracker.conf
vim /etc/fdfs/tracker.conf
修改內容

創建目錄(若目錄已存在,可忽略)
mkdir /cyb/server/fastdfs/tracker -p
Storage Server配置(虛擬機名:CentOS 6-FastDFS-02)
修改/etc/fdfs/storage.conf
vim /etc/fdfs/storage.conf
修改內容模板
# 指定storage的組名
group_name=group1
base_path=/cyb/server/fastdfs/storage
# 如果有多個掛載磁盤則定義多個store_path
store_path0=/cyb/server/fastdfs/storage
# store_path1=.......
# store_path2=.......
# store_path3=.......
# 配置tracker服務器ip和端口
tracker_server=192.168.1.1:22122
# 若果有多個則配置多個tracker
# tracker_server=xxx.xxx.xxx.xxx:xxxx
# tracker_server=xxx.xxx.xxx.xxx:xxxx
# tracker_server=xxx.xxx.xxx.xxx:xxxx
修改:group_name

修改:base_path

修改:store_path*

補充:為什么要設置多個store_path*呢?linux如果磁盤不夠用的話,用戶可以加硬盤,然后設置多個store_path*
修改:tracker_server

創建目錄(若目錄已存在,可忽略)
mkdir /cyb/server/fastdfs/storage -p
重復Storage Server配置步驟(虛擬機名:CentOS 6-FastDFS-03)
用途
該步驟用於演示負載均衡,冗余備份
啟動
Tracker啟動命令
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf

Storage啟動命令
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf

Tracker開啟自啟動
編輯文件:
vim /etc/rc.d/rc.local
將以下內容添加到該文件中:
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf

Storage開啟自啟動
編輯文件:
vim /etc/rc.d/rc.local
將以下內容添加到該文件中:
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf

重啟
sudo /usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart
sudo /usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart
補充(重要)
查看Storage日志

關閉防火牆!!!
1、關閉命令: service iptables stop
2、永久關閉防火牆:chkconfig iptables off
3、兩個命令同時運行內,運行完成容后查看防火牆關閉狀態
service iptables status

上傳圖片測試
FastDFS安裝成功后可通過【fdfs_test】命令測試上傳、下載等操作(三台中的任意一台測試即可)
修改client.conf
vim /etc/fdfs/client.conf
修改內容如下

創建目錄
mkdir /cyb/server/fastdfs/client -p
上傳到FastDFS中
格式:
/usr/bin/fdfs_test /etc/fdfs/client.conf upload 文件路徑
/usr/bin/fdfs_test /etc/fdfs/client.conf upload /home/1.txt
上傳成功

此時這個地址是訪問不到的,需要與Nginx整合使用,方可訪問該文件!
驗證兩台機器都上傳成功

Tracker.conf配置文件
配置參數說明
#此配置文件是否已禁用 #false為啟用 #為殘疾人士適用 禁用=假 #綁定該主機的地址 #空用於綁定此主機的所有地址 bind_addr = #跟蹤器服務器端口 端口= 22122 #連接超時(以秒為單位) #默認值為30秒 connect_timeout = 10 #網絡超時(以秒為單位) #默認值為30秒 network_timeout = 60 #存儲數據和日志文件的基本路徑 base_path = / home / yuqing / fastdfs #此服務器支持的最大並發連接數 #您應該將此參數設置得更大一些,例如。102400 max_connections = 1024 #接受線程數 #默認值為1 #自V4.07起 accept_threads = 1 #工作線程數,應<= max_connections #默認值為4 自V2.00起 work_threads = 4 #最小拋光量 #默認值8KB min_buff_size = 8KB #最大增益 #默認值128KB max_buff_size = 128KB #選擇上傳文件組的方法 #0:循環賽 #1:指定組 #2:負載均衡,選擇最大可用空間組來上傳文件 store_lookup = 2 #上傳文件的組 #當store_lookup設置為1時,必須將store_group設置為組名 store_group = group2 #要上傳文件的存儲服務器 #0:循環(默認) #1:第一個服務器按IP地址排序 #2:按優先級排列的第一個服務器順序(最小) #注意:如果use_trunk_file設置為true,則必須將store_server設置為1或2 store_server = 0 #存儲服務器上載文件的路徑(表示磁盤或掛載點) #0:循環賽 #2:負載均衡,選擇最大可用空間路徑上傳文件 store_path = 0 #要下載文件的存儲服務器 #0:循環(默認) #1:當前文件上傳到的源存儲服務器 download_server = 0 #為系統或其他應用程序保留的存儲空間。 #如果以下任何存儲服務器的可用(可用)空間 #一個組<= reserved_storage_space, #沒有文件可以上傳到該組。 #字節單位可以是以下之一: ### G或g表示千兆字節(GB) ### M或m表示兆字節(MB) ### K或k表示千字節(KB) ###無字節單位(B) ### XX.XX%作為比例,例如reserved_storage_space = 10% reserved_storage_space = 20% #standard日志級別為syslog,不區分大小寫,值列表: ###緊急應急 ###警報 ###暴擊 ###錯誤 ###警告警告 ### 注意 ###信息 ###調試 log_level =信息 #unix組名以運行此程序, #未設置(空)表示由當前用戶組運行 run_by_group = #unix用戶名以運行此程序, #未設置(空)表示由當前用戶運行 run_by_user = #allow_hosts可以多次出現,host可以是主機名或IP地址, #“ *”(僅一個星號)表示匹配所有IP地址 #我們可以使用像192.168.5.64/26這樣的CIDR IP #並使用以下范圍:10.0.1。[0-254]和主機[01-08,20-25] .domain.com # 例如: #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 = * #每隔幾秒將日志buff同步到磁盤 #默認值為10秒 sync_log_buff_interval = 10 #檢查存儲服務器的活動間隔秒數 check_active_interval = 120 #線程堆棧大小,應> = 64KB #默認值為256KB thread_stack_size = 256KB #自動調整存儲服務器的IP地址 #默認值為true storage_ip_changed_auto_adjust = true #存儲同步文件的最大延遲秒數 #默認值為86400秒(一天) 自V2.00起 storage_sync_file_max_delay = 86400 #存儲文件同步的最長時間 #默認值為300秒 自V2.00起 storage_sync_file_max_time = 300 #如果使用中繼文件存儲幾個小文件 #默認值為false #自V3.00起 use_trunk_file =否 #最小插槽大小,應<= 4KB #默認值為256字節 #自V3.00起 slot_min_size = 256 #最大插槽大小,應> slot_min_size #當上傳文件的大小小於等於此值時,將其存儲到中繼文件 #默認值為16MB #自V3.00起 slot_max_size = 16MB #中繼文件大小,應> = 4MB #默認值為64MB #自V3.00起 trunk_file_size = 64MB #如果預先創建中繼文件 #默認值為false #從V3.06開始 trunk_create_file_advance =否 #創建中繼文件的時基 #時間格式:HH:MM #默認值為02:00 #從V3.06開始 trunk_create_file_time_base = 02:00 #創建Trunk文件的時間間隔,單位:秒 #默認值為38400(一天) #從V3.06開始 trunk_create_file_interval = 86400 #創建中繼文件的閾值 #當空閑中繼文件大小小於閾值時,將創建 #中繼文件 #默認值為0 #從V3.06開始 trunk_create_file_space_threshold = 20G #加載行李箱空閑空間時是否檢查行李箱空間占用 #占用的空間將被忽略 #默認值為false #自V3.09起 #注意:將此參數設置為true會減慢行李箱空間的加載 #啟動時。您應在必要時將此參數設置為true。 trunk_init_check_occupying =否 #如果忽略storage_trunk.dat,則從中繼binlog重新加載 #默認值為false #自V3.10起 #如果版本低於V3.10,則一次設置為true進行版本升級 trunk_init_reload_from_binlog =否 #壓縮中繼binlog文件的最小間隔 #單位:秒 #默認值為0,0表示永不壓縮 #在主干初始化和主干銷毀時,FastDFS壓縮主干binlog #重新命令將此參數設置為86400(一天) #自V5.01起 trunk_compress_binlog_min_interval = 0 #如果使用存儲ID代替IP地址 #默認值為false #自V4.00起 use_storage_id =假 #指定存儲ID的文件名,可以使用相對或絕對路徑 #自V4.00起 storage_ids_filename = storage_ids.conf #文件名中存儲服務器的id類型,值是: ## ip:存儲服務器的IP地址 ## id:存儲服務器的服務器ID #僅當use_storage_id設置為true時,此參數才有效 #默認值為ip 從V4.03開始 id_type_in_filename = id #如果存儲從屬文件使用符號鏈接 #默認值為false #自V4.01起 store_slave_file_use_link = false #如果每天旋轉錯誤日志 #默認值為false 從V4.02開始 rotation_error_log =否 #旋轉錯誤日志的時基,時間格式:小時:分鍾 #小時從0到23,分鍾從0到59 #默認值為00:00 從V4.02開始 error_log_rotate_time = 00:00 #當日志文件超過此大小時旋轉錯誤日志 #0表示永不按日志文件大小旋轉日志文件 #默認值為0 從V4.02開始 rotation_error_log_size = 0 #保留日志文件的天數 #0表示不刪除舊的日志文件 #默認值為0 log_file_keep_days = 0 #如果使用連接池 #默認值為false #自V4.05起 use_connection_pool =否 #空閑時間超過此時間的連接將被關閉 #單位:秒 #默認值為3600 #自V4.05起 connection_pool_max_idle_time = 3600 #該跟蹤器服務器上的HTTP端口 http.server_port = 8080 #檢查存儲HTTP服務器的活動間隔秒數 #<= 0表示永不檢查 #默認值為30 http.check_alive_interval = 30 #檢查存儲HTTP服務器的活動類型,值是: #tcp:僅使用HTTP端口連接到storge服務器, #不要求獲得回應 #http:存儲檢查有效網址必須返回http狀態200 #默認值為tcp http.check_alive_type = tcp #檢查存儲HTTP服務器是否存在uri / url #注意:存儲嵌入HTTP服務器支持uri:/status.html http.check_alive_uri = / status.html
安裝Nginx(Apache)
安裝事項
Nginx需要安裝在每一台Storage服務器上,Tracker服務器上不需要安裝!!!!Nginx不明白的童鞋,可以看我另一篇博客:從入門到精通-Nginx,圖文並茂、負載均衡、動靜分離、虛擬主機 附案例源碼
下載文件
補充
上傳文件可以用:
1、yum install -y lrzsz
2、rz
安裝依賴庫
1、yum install -y gcc-c++ gcc (C語言依賴庫,若安裝過,可不安裝)
pcre-devel:pcre,Perl Compatible Regular Expressions,Perl腳本語言兼容正則表達式,為Nginx提供正則表達式庫。
openssl-devel:為Nginx提供SSL(安全套接字層)密碼庫,包含主要的密碼算法,常用的密鑰和證書封裝管理功能及SSL協議,並提供豐富的應用程序供測試或其他目的使用。
2、yum -y install pcre-devel openssl-devel
解壓縮

執行configure配置

編譯與安裝

修改nginx.conf
vim /cyb/server/nginx/conf/nginx.conf

注:我的nginx.conf里面內容比較少,是因為我把沒用到的東西刪掉了!~
建立軟鏈接
ln -n /cyb/server/nginx/sbin/nginx /usr/local/sbin
注:建立完軟鏈接之后,就可以在任意位置執行
啟動nginx
注:啟動前,可以先執行下:nginx -tq,看會不會報錯,沒報錯,說明nginx.conf配置文件,配置的參數是正確的
nginx
測試

到目前為止,nginx已經可以正常訪問FastDFS上傳的文件內容了。
FastDFS-Nginx配置擴展模塊(重要)
采坑之路
nginx如果在原來的基礎模塊上,追加新模塊,重新編譯,原先的不會覆蓋,我不知道是版本的原因還是怎么回事,我的解決方案就是把原先的nginx,先刪掉,在重新一次性編譯與安裝。
rm -rf /etc/nginx/ --nginx的安裝目錄
rm -rf /usr/sbin/nginx
如果建立軟連接的話,別忘記一塊刪了哦
rm -rf /usr/local/sbin/nginx

背景
上面示例,FastDFS上傳的文件,已經可以通過nginx正常訪問了,為什么還要使用Nginx擴展模塊來訪問存儲文件呢?
- 如果進行文件合並,那么不使用FastDFS的Nginx擴展模塊,是無法訪問到具體的文件的,因為文件合並之后,多個小文件都是存儲在一個trunk文件中的,在存儲目錄下,是看不到具體的小文件的。
- 如果文件未同步成功,那么不適用FastDFS的Nginx擴展模塊,是無法正常訪問到指定的文件的,而使用了FastDFS的Nginx擴展模塊之后,如果要訪問的文件未同步成功,那么會解析出來該文件的源存儲服務器ip,然后將訪問請求重定向或者代理到源存儲服務器中進行訪問。
下載文件
注:FastDFS的Nginx擴展模塊需要安裝到每個Storage Server中
github:https://github.com/happyfish100/fastdfs-nginx-module/releases/tag/V1.22

解壓縮

修改config文件(關鍵一步)

修改第6、15行的內容

第6行: ngx_module_incs="/usr/include/fastdfs /usr/include/fastcommon/" 第15行: CORE_INCS="$CORE_INCS /usr/include/fastdfs /usr/include/fastcommon/"
拷貝mod_fastdfs.conf
將/cyb/soft/fastdfs-nginx-module-1.22/src/mod_fastdfs.conf拷貝至/etc/fdfs/下
cp /cyb/soft/fastdfs-nginx-module-1.22/src/mod_fastdfs.conf /etc/fdfs/
修改mod_fastdfs.conf
vim /etc/fdfs/mod_fastdfs.conf
base_path=/cyb/server/fastdfs/storage # 基礎路徑,存儲日志文件
tracker_server=192.168.31.220:22122 # tracker服務器的ip
url_have_group_name=true # url中是否包含group名稱
store_path0=/cyb/server/fastdfs/storage # 指定文件存儲路徑,訪問時使用該路徑
拷貝libfdfsclient.so(高版本可忽略)
cp /usr/lib64/libfdfsclient.so /usr/lib/
注:若/usr/lib/下已存在libfdfsclient.so,則此步驟可忽略!!!
執行configure配置

重新編譯與安裝

重啟並查看擴展包
nginx -V --->V是大寫的
顯示--add-module,才代表安裝模塊成功,沒成功的,請看我采坑之路介紹

修改nginx.conf配置

搞定
一樣可以正常訪問

Java客戶端
github下載
https://github.com/happyfish100/fastdfs-client-java/releases/tag/V1.26
如何打包,請看:https://www.cnblogs.com/chenyanbin/p/12831553.html
注意修改pom.xml中的<jdk.version>版本
Maven依賴
<!--fastdfs依賴--> <dependency> <groupId>org.csource</groupId> <artifactId>fastdfs-client-java</artifactId> <version>1.27-SNAPSHOT</version> </dependency>
java項目結構
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.cyb</groupId> <artifactId>fastdfs-demo</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!--fastdfs依賴--> <dependency> <groupId>org.csource</groupId> <artifactId>fastdfs-client-java</artifactId> <version>1.27-SNAPSHOT</version> </dependency> </dependencies> </project>
fdfs_client.conf
tracker_server=192.168.31.220:22122
FastDFSClient.java
package com.cyb.fdfs.client; import org.csource.common.NameValuePair; import org.csource.fastdfs.*; import java.net.URLDecoder; public class FastDFSClient { private static TrackerClient trackerClient = null; private static TrackerServer trackerServer = null; private static StorageServer storageServer = null; private static StorageClient1 client = null; // fdfsClient的配置文件路徑 private static String CONF_NAME="/fdfs/fdfs_client.conf"; static { try{ //配置恩建必須制定全路徑 String confName=FastDFSClient.class.getResource(CONF_NAME).getPath(); //配置文件全路徑如果有中文,需要進行utf8轉碼 confName= URLDecoder.decode(confName,"utf8"); ClientGlobal.init(confName); trackerClient=new TrackerClient(); trackerServer=trackerClient.getConnection(); storageServer=null; client=new StorageClient1(trackerServer,storageServer); } catch (Exception e){ e.printStackTrace(); } } /** * 上傳文件方法 * @param fileName 文件全路徑 * @param extName 文件擴展名,不包含(.) * @param metas 文件擴展信息 * @return * @throws Exception */ public static String uploadFile(String fileName, String extName, NameValuePair[] metas) throws Exception{ String result = client.upload_file1(fileName, extName, metas); System.out.println(result); return result; } public static void main(String[] args) { try { uploadFile("/Users/chenyanbin/Desktop/1.jpg","jpg",null); } catch (Exception e){ e.printStackTrace(); } } }
注:這次我只寫了一個上傳的,他會返回一直String字符串,也就是文件存儲的位置,前面在追加ip,拼成url,直接可以訪問,這里的client還有其他API,自行查閱,client.API
測試
上傳本地的1.jpg,然后通過ip+返回字符串,拼成url訪問

項目與maven依賴源碼下載
鏈接: https://pan.baidu.com/s/11kZfO_MRvwErnseWSVgSog 密碼: d0pp
maven源碼包,需要重新編譯
合並存儲(重要)
簡介
在處理海量小文件問題上,文件系統處理性能會受到顯著的影響,在讀此書(IOPS)與吞吐量(Throughput)這兩個指標上會有不少的下降。主要需要面對如下幾個問題
- 元數據管理低效,磁盤文件系統中,目錄項(dentry)、索引節點(inode)和數據(data)保存在介質的不同位置上。因此,訪問一個文件需要經歷至少3次獨立的訪問。這樣,並發小文件訪問就轉變成了大量的隨機訪問,而這種訪問廣泛使用的磁盤來說是非常低效的
- 數據布局低效
- IO訪問流程復雜,因此一種解決途徑就是將小文件合並存儲成大文件,使用seek來定位到大文件的指定位置來訪問該小文件。
注:
FastDFS提供的合並存儲功能,默認創建的大文件為64MB,然后在該大文件中存儲很多小文件。大文件中容納一個小文件的空間稱為一個Slot,規定Slot最小值為256字節,最大為16MB,也就是小於256字節的文件也需要占用256字節,超過16MB的文件不會合並存儲而是創建獨立的文件。
合並存儲配置
FastDFS提供了合並存儲功能,所有的配置在tracker.conf文件之中,開啟合並存儲只需要設置比:use_trunk_file=true 和store_server=1
修改tracker.conf(修改的tracker服務器)
vim /etc/fdfs/tracker.conf
store_server改為1

use_trunk_file改true

重啟tracker
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart
存儲縮略圖
FastDFS主從文件
應用背景
使用FastDFS存儲一個圖片的多個分辨率的備份時,希望只記錄源圖的fileid,並能將其分辨率的圖片與源圖關聯。可以使用從文件方法
解決辦法
名詞注解:主從文件是指文件ID有關聯的文件,一個主文件可以對應多個從文件。
- 主文件ID=主文件名+主文件擴展名
- 從文件ID=主文件名+從文件后綴名(如:200*200)+從文件擴展名
流程說明
1、先上傳主文件(既:源文件,得到主文件FID)
2、然后上傳從文件(既:縮略圖),指定主文件FID和從文件后綴名,上傳后得到從文件FID
java客戶端方式(不推薦)
package com.cyb.fdfs.client;
import com.sun.tools.corba.se.idl.StringGen;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
import java.net.URLDecoder;
public class FastDFSClient2 {
private static TrackerClient trackerClient = null;
private static TrackerServer trackerServer = null;
private static StorageServer storageServer = null;
private static StorageClient1 client = null;
// fdfsClient的配置文件路徑
private static String CONF_NAME = "/fdfs/fdfs_client.conf";
static {
try {
//配置恩建必須制定全路徑
String confName = FastDFSClient2.class.getResource(CONF_NAME).getPath();
//配置文件全路徑如果有中文,需要進行utf8轉碼
confName = URLDecoder.decode(confName, "utf8");
ClientGlobal.init(confName);
trackerClient = new TrackerClient();
trackerServer = trackerClient.getConnection();
storageServer = null;
client = new StorageClient1(trackerServer, storageServer);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 上傳主文件
*
* @param filePath
* @return 主文件ID
* @throws Exception
*/
public static String uploadFile(String filePath) throws Exception {
String fileId = "";
String fileExtName = "";
if (filePath.contains(".")) {
fileExtName = filePath.substring(filePath.lastIndexOf(".")+1);
} else {
return fileId;
}
try {
fileId = client.upload_file1(filePath, fileExtName, null);
} catch (Exception e) {
e.printStackTrace();
} finally {
trackerServer.close();
}
return fileId;
}
/**
* 上傳從文件
*
* @param masterFileId FastDFS服務器返回的主文件的fileid
* @param prefixName 從文件后綴名(如:_200*200)
* @param slaveFilePath 從文件所在路徑(主從文件在本地都需要有對應的文件)
* @return
* @throws Exception
*/
public static String uploadSlaveFile(String masterFileId, String prefixName, String slaveFilePath) throws Exception {
String slaveFileId = "";
String slaveFileExtName = "";
if (slaveFilePath.contains(".")) {
slaveFileExtName = slaveFilePath.substring(slaveFilePath.lastIndexOf(".") + 1);
} else {
return slaveFileId;
}
try {
slaveFileId = client.upload_file1(masterFileId, prefixName, slaveFilePath, slaveFileExtName, null);
} catch (Exception e) {
e.printStackTrace();
} finally {
trackerServer.close();
}
return slaveFileId;
}
public static int download(String fileId, String localFile) throws Exception {
int result = 0;
//建立連接
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
StorageClient1 client = new StorageClient1(trackerServer, storageServer);
//上傳文件
try {
result = client.download_file1(fileId, localFile);
} catch (Exception e) {
e.printStackTrace();
} finally {
trackerServer.close();
}
return result;
}
public static void main(String[] args) {
try {
//上傳主文件
String masterFileId=uploadFile("/Users/chenyanbin/Desktop/1.jpg");
System.out.println("主文件:"+masterFileId);
//下載上傳成功的主文件
download(masterFileId,"/Users/chenyanbin/Desktop/11.jpg");
//第三個參數:待上傳的從文件(由此可知道,還需要把之前的下載,在本地生成后,在上傳)
String slaveFileId=uploadSlaveFile(masterFileId,"_120x120","/Users/chenyanbin/Desktop/2.jpg");
System.out.println("從文件:"+slaveFileId);
//下載上傳成功的縮略圖
download(slaveFileId,"/Users/chenyanbin/Desktop/22.jpg");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Nginx生成縮略圖(推薦👍)
image_filter模塊
nginx_http_image_filter_module在nginx 0.7.54以后才出現的,用於對jpeg、gif和png圖片進行轉換處理(壓縮、裁剪、旋轉)。這個模塊默認不被編譯,所以要在編譯nginx源碼的時候,加入相關配置信息
檢測nginx模塊安裝情況

安裝步驟
安裝gd,HttpImageFilterModule模塊需要依賴gd-devel的支持
yum -y install gd-devel
在原來模塊基礎上追加
--with-http_image_filter_module

訪問普通圖片
需求,假設我們圖片的真實路徑是在本地/cyb/data/img/1.jpg,下面有狠毒ojpg格式的圖片,我們希望通過訪問/img/1_100x100.jpg這樣的請求路徑可以生成寬為100,高也為100的小圖,並且請求的寬和高是可變的,那么這時候需要在nginx模塊中攔截請求並返回轉換后的小圖,在對應server{}段中進行配置。
nginx.conf配置如下
location ~* /img/(.*)_(\d+)x(\d+)\.(jpg|gif|png)$ {
root /;
set $s $1;
set $w $2;
set $h $3;
set $t $4;
image_filter resize $w $h;
image_filter_buffer 10M;
rewrite ^/img/(.*)$ /cyb/data/img/$s.$t break;
}
旋轉:image_filter_rotate 度數;
image_filter rotate 90; --旋轉90度
image_filter rotate 180; --旋轉180度
裁剪:image_filter crop width height;
image_filter crop 120 60; --裁剪成寬120,高60

然后在/cyb/data/img/下存放一張圖片

注意:該圖片一定要有讀取權限,要不然nginx是讀取不到的!!!

關閉nginx,並重啟(平滑重啟沒用)
nginx -s stop
nginx
測試(普通圖片)

訪問FastDFS圖片
location ~ group1/M00/(.+)_(\d+)x(\d+)\.(jpg|gif|png){
# 設備別名(類似於root的用法)
alias /cyb/server/fastdfs/storage/data/;
# fastdfs中的ngx_fastdfs_module模塊
ngx_fastdfs_module;
set $w $2;
set $h $3;
if ($w != "0"){
rewrite group1/M00(.+)_(\d+)x(\d+)\.(jpg|gif|png)$ group1/M00$1.$4 break;
}
if ($h != "0"){
rewrite group1/M00(.+)_(\d+)x(\d+)\.(jpg|gif|png)$ group1/M00$1.$4 break;
}
# 根據給定長寬生成縮略圖
image_filter resize $w $h;
# 原圖最大2M,要裁剪的圖片超過2M返回415錯誤,需要調節參數image_filter_buffer
image_filter_buffer 2M;
}

測試(FastDFS圖片)

Nginx Image縮略圖 模塊
- 該模塊主要功能是對請求的圖片進行縮略/水印處理,支持文字水印和圖片水印
- 支持自定義字體,文字大小,水印透明度,水印位置
- 支持jpeg/png/gif(Gif生成后變成靜態圖片)
安裝nginx image模塊
編譯nginx前,請確認是否安裝過libcurl-dev libgd2-dev libpcre-dev依賴庫
yum install -y dg-devel pcre-devel libcurl-devel
下載nginx image模塊
https://github.com/oupula/ngx_image_thumb/archive/master.zip
解壓
tar -zxvf ngx_image_thumb-master.zip
執行configure

編譯與安裝
make && make install
修改nginx.conf配置
location /img/ {
root /cyb/data/;
# 開啟壓縮功能
image on;
# 是否不生成圖片而直接處理后輸出
image_output on;
image_water on;
# 水印類型:0為圖片水印,1為文字水印
image_water_type 0;
#水印出現位置
image_water_pos 9;
# 水印透明度
image_water_transparent 80;
# 水印文件
image_water_file "/cyb/data/logo.png";
}
關閉並重啟nginx
nginx -s stop
nginx
訪問普通圖片
- 源圖片:192.168.1.109/img/cyb.jpg
- 壓縮圖片:192.168.1.109/img/cyb.jpg!c300x200.jpg
其中c是生成圖片縮略圖的參數,300是生成的縮略圖的寬,200是高
參數說明:
一共可以生成四種不同類型的縮略圖
C:參數按照請求寬高比例從圖片高度 10% 處開始截取圖片,然后縮放/放大指定尺寸(圖片縮略圖大小等於請求的寬高)
m:參數按請求寬高比例居中截取圖片,然后縮放/放大到指定尺寸(圖片縮略圖大小等於請求的寬高)
t:參數按請求寬高比例按比例縮放/放大到指定尺寸(圖片縮略圖大小可能小於請求的寬高)
w:參數按請求寬高比例縮放/放大到指定尺寸,空白處填充白色背景色(圖片縮略圖大小等於請求的寬高)
測試(普通圖片)

細心的小伙伴發現,水印沒有出現,術印出沒出來有個閾值:600x600(版本不同,閾值可能不同)

訪問FastDFS圖片
location /group1/M00/ {
alias /cyb/server/fastdfs/storage/data/;
image on;
image_output on;
image_jpeg_quality 75;
image_water on;
image_water_type 0;
image_water_pos 9;
image_water_transparent 80;
image_water_file "/cyb/data/logo.png";
# 配置一個不存在的圖片地址,防止查看縮略圖時照片不存在,服務器響應慢
# image_backend_server http://www.baidu.com/img/baidu_jpglogo3.gif
}
測試(FastDFS圖片)

