從入門到精通(分佈式文件系統架構)-FastDFS,FastDFS-Nginx整合,合併存儲,存儲縮略圖,圖片壓縮,Java客戶端

導讀

  篇幅較長,乾貨滿滿,需花費較長時間,轉載請註明出處!html

互聯網環境中的文件如何存儲?

  1. 不能存本地應用服務器
  2. NFS(採用mount掛載)
  3. HDFS(適合大文件)
  4. FastDFS(強力推薦👍)
  5. 雲存儲(有免費和收費的,不推薦,使用前能夠看該公司實力怎麼樣,別文件都存上去了,過2年公司破產了,損失慘重呀,嗚嗚嗚~~~)

互聯網環境中的文件如何進行HTTP訪問?

Web服務器:Nginx(本案例使用Nginx,還不會用Nginx的小夥伴,請看我另外一篇博客:點我直達)、Apache等等。java

FastDFS介紹

FastDFS是什麼?

  1. FastDFS是一個C編寫的開源的高性能分佈式文件系統(Distributed File System,簡稱DFS)
  2. 它由淘寶開發平臺部資深架構師餘慶開發,論壇:http://bbs.chinaunix.net/forum-240-1.html
  3. 它對文件進行管理,功能包括:文件存儲、文件同步、文件訪問(文件上傳、文件下載)等,解決了大容量存儲和負載均衡的問題
  4. 特別適合以文件爲載體的在線服務,如相冊網站、視頻網站、電商等等。特別適合以中小文件(建議範圍:4KB<file_size<500mb)爲載體的在線服務
  5. FastDFS爲互聯網量身定製,充分考慮了冗餘備份、負載均衡、線性擴容等機制,並注重高可用、高性能等指標,使用FastDFS很容易搭建一套高性能的文件服務器集羣提供文件上傳、下載等服務
  6. github:https://github.com/happyfish100/fastdfs

技術文檔node

連接: https://pan.baidu.com/s/1BpPwJBg2mR8CvqOiKj2rDQ  密碼: ocj5

流程圖

  實際比這複雜的多linux

FastDFS架構原理分析(重點)

架構分析

  FastDFS系統有三個角色:跟蹤服務器(Tracker Server)、存儲服務器(Storage Server)和客戶端(Client)。nginx

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:客戶端

  • 上傳下載數據的服務器,也就是咱們本身的項目所部署在的服務器

存儲策略

  爲了支持大容量,存儲節點(服務器)採用分卷(或分組)的組織方式。存儲系統由一個或多個卷組成,卷與卷之間的文件是相互獨立的,全部卷的文件容量累加就是整個存儲系統中的文件容量。一個卷能夠由一臺或多臺存儲服務器組成,一個卷下的存儲服務器中的文件都是相同的卷中的多臺存儲服務器起到了冗餘備份和負載均衡的做用。c++

  在卷中增長服務器時,同步已有的文件由系統自動完成,同步完成後,系統自動將新增服務器切換到線上提供服務。當存儲空間不足或即將耗盡時,能夠動態加載卷,只須要增長一臺或多臺服務器,並將它們配置爲一個新的卷,這樣就擴大了存儲系統的容量。git

Storage狀態收集

  Storage Server會經過配置鏈接集羣中全部的Tracker Server,定時向他們報告本身的狀態,包括磁盤剩餘空間、文件上傳下載次數等統計信息github

Storage Server有7個狀態,以下正則表達式

  1. FDFS_STORAGE_STATUS_INIT ->初始化,還沒有獲得同步已有數據的源服務器
  2. FDFS_STORAGE_STATUS_WAIT_SYNC ->等待同步,已獲得同步已有數據的源服務器
  3. FDFS_STORAGE_STATUS_SYNCING ->同步中
  4. FDFS_STORAGE_STATUS_DELETED ->已刪除,該服務器從本組中摘除
  5. FDFS_STORAGE_STATUS_OFFLINE ->離線
  6. FDFS_STORAGE_STATUS_ONLINE ->在線,尚不能提供服務
  7. FDFS_STORAGE_STATUS_ACTIVE ->在線,能夠提供服務

文件上傳流程分析

流程說明

一、Tracker Server收集Storage Server的狀態信息算法

  1.一、Storage Server定時向已知的tracker server(能夠是多個)發送磁盤剩餘空間、文件同步狀態、文件上傳下載次數等統計信息

  1.二、Storage Server會鏈接整個集羣中全部的Tracker Server,向它們報告本身的狀態

二、選擇Tracker server

  2.一、當集羣中不止一個Tracker Server時,因爲Tracker之間是徹底對等的關係,客戶端在upload文件時能夠任意選擇一個Tracker 

三、選擇存儲的group

  當Tracker接收到upload file的請求時,會爲該文件分配一個可存儲該文件的group,支持以下規則

    3.一、Round robin,全部的group間輪詢(默認)

    3.二、Specified group,指定某一個肯定的group

    3.三、Load balance,剩餘存儲空間多的,group優先

四、選擇Storage Server

  當選定group後,Tracker會在group內選擇一個Storage Server給客戶端,支持以下選擇Storage的規則

  4.一、Round robin,在group內的全部Storage間輪詢(默認)

  4.二、First server ordered by ip,按ip排序

  4.三、First server ordered by priority,按優先級排序(優先級在Storage上配置)

五、選擇Storage path

  當分配好Storage server後,客戶端將向Storage發送寫文件請求,Storage將會爲文件分配一個數據存儲目錄,支持以下規則(在Storage配置文件中能夠經過store_path*參數來設置,該參數能夠設置多個,經過*來區別)

  5.一、Round robin,多個存儲目錄間輪詢

  5.二、剩餘存儲空間最多的優先

六、生成fileid

  選定存儲目錄以後,Storage會爲文件生一個fileid,由源Storage server ip、文件建立時間、文件大小、文件crc32和一個隨機數拼接而成,而後將這個二進制串進行base64編碼,轉換爲可打印的字符串。

七、選擇兩級目錄

  當選定存儲目錄以後,Storage會爲文件分配一個fileid,每一個存儲目錄下有兩級256*256的子目錄,Storage會按文件fileid進行兩次hash,路由到其中一個子目錄,而後將文件以fileid爲文件名存儲到該子目錄下。

八、生成文件名

  當文件存儲到某個子目錄後,既認爲該文件存儲成功,接下來會爲該文件生成一個文件名,文件名由group、存儲目錄、兩級子目錄、fileid、文件後綴名(由客戶端指定,主要用於區分文件類型)拼接而成。

文件同步分析

  寫文件時,客戶端將文件寫至group內一個Storage Server既認爲寫文件成功,Storage Server寫完文件後,會由後臺線程將文件同步至group內其餘的Storage Server。

同步規則總結以下

  1. 只在本組內的Storage Server之間進行同步
  2. 源頭數據才須要同步,備份數據不須要再次同步,不然就構成閉環了
  3. 上述第二條規則有個例外,就是新增一臺Storage Server時,由已有的一臺Storage Server將已有的全部數據(包括源頭數據和備份數據)同步給該新增服務器

  每一個Storage寫文件後,同時會寫一份binlog,binlog裏不包含文件數據,只包含文件名等元信息,這份binlog用於後臺同步,Storage會記錄向group內其餘Storage同步的進度,以便重啓後能接上次的進度繼續同步;進度以時間戳的方式進行記錄,因此最好能保證集羣內全部Server的時鐘保持同步。

文件下載流程分析

  客戶端upload file成功後,會拿到一個Storage生成的文件名,接下來客戶端根據這個文件名便可訪問到該文件。

流程說明

一、Tracker Server收集Storage Server的狀態信息

  1.一、Storage Server定時向已知的Tracker Server(能夠是多個)發送磁盤剩餘空間、文件同步狀態、文件上傳下載次數等統計信息。

  1.二、Storage Server會鏈接整個集羣中全部的Tracker Server,向他們報告本身的狀態。

二、選擇Tracker Server

  2.一、跟upload file同樣,在download file時客戶端能夠選擇任意Tracker Server 

三、選擇可用的Storage Server

   3.一、client發送download請求給某個Tracker,必須帶上文件名信息,Tracker從文件名中解析出文件的group、路徑信息、文件大小、建立時間、源Storage Server ip等信息,而後爲該請求選擇一個Storage用來服務讀請求。

  3.二、因爲group內的文件同步是在後臺異步進行的,因此有可能出如今讀的時候,文件尚未同步到某些Storage Server上,爲了儘可能避免訪問到這樣的Storage,Tracker按照以下規則選擇group內可讀的Storage

    3.2.一、該文件上傳到的源頭Storage - 源頭Storage只要存活着,確定包含這個文件,源頭的地址被編碼在文件名中。

    3.2.二、文件建立時間戳 == Storage被同步到時間戳 且(當前時間 - 文件建立時間戳) > 文件同步最大時間 - 文件建立後,認爲通過最大同步時間後,確定已經同步到其餘Storage了。

    3.2.三、文件建立時間戳 < Storage被同步到的時間戳。 - 同步時間戳以前的文件肯定已經同步

    3.2.四、(當前時間 - 文件建立時間戳) > 同步延遲閾值。 通過同步延遲閾值時間,認爲文件確定已經同步了

FastDFS安裝

需求

  1. Tracker Server:
  2. 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日誌

關閉防火牆!!!

一、關閉命令: service iptables stop
二、永久關閉防火牆:chkconfig iptables off
三、兩個命令同時運行內,運行完成容後查看防火牆關閉狀態
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,圖文並茂、負載均衡、動靜分離、虛擬主機 附案例源碼

下載文件

點我直達 

補充

上傳文件能夠用:
一、yum install -y lrzsz

二、rz

安裝依賴庫

一、yum install -y gcc-c++ gcc   (C語言依賴庫,若安裝過,可不安裝)

pcre-devel:pcre,Perl Compatible Regular Expressions,Perl腳本語言兼容正則表達式,爲Nginx提供正則表達式庫。
openssl-devel:爲Nginx提供SSL(安全套接字層)密碼庫,包含主要的密碼算法,經常使用的密鑰和證書封裝管理功能及SSL協議,並提供豐富的應用程序供測試或其餘目的使用。
二、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擴展模塊來訪問存儲文件呢?

  1. 若是進行文件合併,那麼不使用FastDFS的Nginx擴展模塊,是沒法訪問到具體的文件的,由於文件合併以後,多個小文件都是存儲在一個trunk文件中的,在存儲目錄下,是看不到具體的小文件的。
  2. 若是文件未同步成功,那麼不適用FastDFS的Nginx擴展模塊,是沒法正常訪問到指定的文件的,而使用了FastDFS的Nginx擴展模塊以後,若是要訪問的文件未同步成功,那麼會解析出來該文件的源存儲服務器ip,而後將訪問請求重定向或者代理到源存儲服務器中進行訪問。

下載文件

注:FastDFS的Nginx擴展模塊須要安裝到每一個Storage Server中

github:https://github.com/happyfish100/fastdfs-nginx-module/releases/tag/V1.22

解壓縮

修改config文件(關鍵一步)

修改第六、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)+從文件擴展名

流程說明

  一、先上傳主文件(既:源文件,獲得主文件FID)

  二、而後上傳從文件(既:縮略圖),指定主文件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圖片)

相關文章
相關標籤/搜索