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


導讀

  篇幅較長,干貨滿滿,需花費較長時間,轉載請注明出處!

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

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

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

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

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

技術文檔

鏈接: 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個狀態,如下

  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 ->在線,可以提供服務

文件上傳流程分析

流程說明

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。

同步規則總結如下

  1. 只在本組內的Storage Server之間進行同步
  2. 源頭數據才需要同步,備份數據不需要再次同步,否則就構成閉環了
  3. 上述第二條規則有個例外,就是新增一台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安裝

需求

  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日志

關閉防火牆!!!

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擴展模塊來訪問存儲文件呢?

  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文件(關鍵一步)

修改第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圖片)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM