高性能分布式文件存儲及文件下載解決方案-基于Nginx+FastDFS(二)

當前服務中有大量的文件,包括圖書、短文等,同時也包括音頻、視頻、圖片等資源。其存儲及下載方案是需要仔細思考。一方面滿足大量文件存儲、后續(xù)擴容等基本需求;另一方面還要能夠支持高性能下載,解放服務器壓力;同時還要考慮文檔地址的安全性,防盜鏈,以及檢查用戶的下載權限等。

本系統(tǒng)的設計主要為了解決以下幾個問題:

  • 大量靜態(tài)文件的存儲以及訪問,包括圖片、pdf、epub、音頻、視頻甚至是網(wǎng)頁文檔或JS文件
  • 將文件的存儲與業(yè)務數(shù)據(jù)分離以及與業(yè)務分離,只提供純粹的存儲和訪問
  • 解決文件存儲單點故障
  • 實現(xiàn)文件高性能讀取,文檔下載過程一方面支持實現(xiàn)鑒權,另一方面高下載性能且不影響業(yè)務服務

系統(tǒng)架構

架構圖

系統(tǒng)整體架構參見上圖,描述了本系統(tǒng)的所有部署模塊、結構,以及對文檔的下載過程做了詳細描述。從架構圖上看該方案主要分為以下幾個模塊:

  • 內容管理系統(tǒng),主要針對業(yè)務實現(xiàn)的客戶端上傳或服務端上傳服務
  • 文件映射服務(閱讀資源服務),主要實現(xiàn)文檔上傳FastDFS后的存儲位置記錄(MySql),以及提供資源下載的處理接口(Handler),當下載是提供內部映射(FileMapping)機制,在本服務中實現(xiàn)鑒權處理,配合Nginx模塊實現(xiàn)文件保護措施
  • FastDFS模塊,提供資源高性能存儲,解決單點存儲問題
  • Nginx模塊,提供文件分發(fā)功能,同時集成ngx-fastdfs模塊,支持FastDFS文件Nginx訪問機制,配合Nginx內部映射機制,實現(xiàn)文檔保護措施。在該模中,利用Nginx的文件分發(fā)功能(sendfile),使得文件映射服務,只提供鑒權、文件映射,不再提供從FastDFS中下載文檔到容器,讀取文件到內存,并通過容器將內容寫回給客戶端,從而釋放了內存、IO、并發(fā)等方面的資源,從而提高文檔的高速訪問,達到高性能讀取的目的

邏輯處理流程


上圖流程描述了文檔存儲的處理流程,對照系統(tǒng)架構中,主要操作為:文檔映射服務、內容管理系統(tǒng)、FastDFS等三個模塊。

  • 當用戶將文檔提交到內容管理系統(tǒng)中,該服務將接收到的文件直接提交到FastDFS模塊中
  • 當文檔存儲成功后,F(xiàn)astDFS將返回文檔存儲信息
  • 內容管理系統(tǒng)接收到文檔存儲信息后,將該信息存儲到文檔映射服務中,并告知客戶端上傳結果

上述流程,就是一個普通的上傳流程,唯一區(qū)別是增加了文檔映射服務模塊。在該模塊中,主要存儲了兩種信息:

  1. 文件在FastDFS中的位置信息
  2. 用戶訪問該文件的URL,比如https://www.xx.com/storage/748/startjava.epub,該URL可以是生成的短Url(/storage/beNvds34sd) ;URL也可能是資源的標識b20190819001;總之通過該訪問URL能夠映射到FastDFS的位置信息

上述流程中,對于文件存儲主要依賴于FastDFS,而對于上傳的并發(fā)、內存等需求,未發(fā)生改變,可通過部署分節(jié)點提高上傳性能。對于讀多寫少的系統(tǒng)而言(通常更多的大文件仍然是通過后臺分步存儲),高性能的讀取對于性能的提高效果更為顯著。

對于文件的讀取,主要用到的模塊為:

  • Nginx(文件分發(fā))
  • 文件映射服務,主要是提供鑒權邏輯以及根據(jù)請求的URL映射到對應的文件位置,并提供Nginx內部映射頭信息,進行服務器內部跳轉;
  • FastDFS,提供文檔讀取


  • Nginx作為反向代理和負載均衡,接收用戶訪問文檔請求,并將該請求轉發(fā)到文檔映射服務中
  • 文檔映射服務根據(jù)請求Url,查詢(緩存)該Url對應的文件位置
  • 查詢到文件位置后,通過設置響應頭X-Accel-Redirect,該頭信息的值為文件的實際存儲位置
  • 設置X-Accel-Redirect頭信息后,服務將自動內部轉發(fā)到Nginx上,Nginx讀取設置的文件位置信息,并將該文件信息轉發(fā)到ngx-fastdfs-module模塊中
  • ngx-fastdfs-module模塊讀取文件數(shù)據(jù),并將該數(shù)據(jù)返回給Nginx,從而實現(xiàn)Nginx分發(fā)文件,實現(xiàn)高性能下載文件的目的

以上步驟為下載文件的整體流程,為了實現(xiàn)鑒權、Nginx高性能分發(fā)文件,需要對Nginx進行下述配置:

  • Nginx開啟sendfile功能
    在http模塊中添加以下信息:
    sendfile on;
  • 通過nginx轉發(fā)時自動添加X-Sendfile信息,該節(jié)點和sendfile節(jié)點同步開啟和關閉
    在http模塊中添加以下信息,參考上圖:
    proxy_set_header X-Sendfile on;
    對于文件映射服務來說,可以通過讀取該節(jié)點信息,以確定當前服務是否開啟了Nginx文件分發(fā)功能,如果讀取不到或該值不為on,則可以通過容器進行文件讀取和下載(性能低)
  • 對于FastDFS的Nginx,需要開啟internal屬性,該屬性開啟后,則表明當前的代理反問,只能通過服務器內部轉發(fā),瀏覽器等客戶端無法感知,且外部無法直接訪問該代理URL,從而可以配合文件映射服務實現(xiàn)鑒權和限流的措施


  • Nginx的X-Accel-Redirect靜態(tài)轉發(fā)。對于Nginx將請求下載服務轉發(fā)給文件映射服務后,文件映射服務查詢到文件位置信息,通過在響應頭中設置該信息,即X-Accel-Redirect=文件位置信息,該設置可以實現(xiàn)服務器內部轉發(fā),客戶端無法感知,從而保護了真實的文件位置信息。雖然該方案效率會比302方案性能稍低,但可以實現(xiàn)鑒權及文件保護,因此在該方案中作為文件轉發(fā)的處理方案
  • 文件映射服務與ngx-fastdfs-module共存于一個Nginx服務

具體部署方案

Nginx配置

http {
    include       mime.types;
    default_type  application/octet-stream;
    proxy_set_header      Host $host:$server_port;
    # 遠程IP
    proxy_set_header      X-Real-IP $remote_addr;
    proxy_set_header      X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header      X-Forwarded-Proto  $scheme;
    
    proxy_set_header      X-Sendfile on;
    sendfile        on;
    
    server {
        listen       9001;
        server_name  localhost;
        location /M00 {
           internal;
           root /home/storage/fdfs/data/;
           ngx_fastdfs_module;
        }
        
        location / {
           root html;
           if ($request_uri ~ (.*)/d/) {
                rewrite ^.*/d/(.*) /$1 break;
                proxy_pass  http://http_t;
          }
        }
    }
}

以上配置為基礎配置。部分說明:

proxy_set_header      X-Sendfile on; # 對轉發(fā)請求,添加X-Sendfile節(jié)點信息
sendfile        on;  #開啟nginx文件分發(fā)

location /M00 部分,為FastDFS的配置,其中添加了internal,保證該代理只能通過內部轉發(fā)請求。root節(jié)點配置的是FastDFS的文件存儲位置。

后一個包含/d/的節(jié)點配置,模擬了文件映射服務的配置。

文件映射處理邏輯

    @GetMapping("/t")
    public void download(HttpServletResponse response, @RequestHeader(value = "X-Sendfile", required = false) String useXSend) {
        if ("on".equalsIgnoreCase(useXSend)) {
            // nginx分發(fā)下載
            response.setHeader("Content-Disposition", "attachment;filename=test.epub");
            response.setHeader("X-Accel-Redirect", "/M00/00/00/wKhxkF1wLL6AGsQVABFbpT1QNps669.epub");
            response.setHeader("X-Accel-Buffering", "yes");
        } else {
            // 容器下載
        }
    }

上述示例程序中,只描述了Nginx分發(fā)下載的過程,對于容器下載,就是普通的讀取文件,并寫數(shù)據(jù)流到客戶端。通過X-Sendfile控制是走容器下載,還是走Nginx下載。另外Nginx和容器都可以支持斷點續(xù)傳,后續(xù)會描述Nginx的斷點續(xù)傳功能。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
禁止轉載,如需轉載請通過簡信或評論聯(lián)系作者。

相關閱讀更多精彩內容

友情鏈接更多精彩內容