高性能分布式文件存储及文件下载解决方案-基于Nginx+FastDFS(二)

当前服务中有大量的文件,包括图书、短文等,同时也包括音频、视频、图片等资源。其存储及下载方案是需要仔细思考。一方面满足大量文件存储、后续扩容等基本需求;另一方面还要能够支持高性能下载,解放服务器压力;同时还要考虑文档地址的安全性,防盗链,以及检查用户的下载权限等。

本系统的设计主要为了解决以下几个问题:

  • 大量静态文件的存储以及访问,包括图片、pdf、epub、音频、视频甚至是网页文档或JS文件
  • 将文件的存储与业务数据分离以及与业务分离,只提供纯粹的存储和访问
  • 解决文件存储单点故障
  • 实现文件高性能读取,文档下载过程一方面支持实现鉴权,另一方面高下载性能且不影响业务服务

系统架构

架构图

系统整体架构参见上图,描述了本系统的所有部署模块、结构,以及对文档的下载过程做了详细描述。从架构图上看该方案主要分为以下几个模块:

  • 内容管理系统,主要针对业务实现的客户端上传或服务端上传服务
  • 文件映射服务(阅读资源服务),主要实现文档上传FastDFS后的存储位置记录(MySql),以及提供资源下载的处理接口(Handler),当下载是提供内部映射(FileMapping)机制,在本服务中实现鉴权处理,配合Nginx模块实现文件保护措施
  • FastDFS模块,提供资源高性能存储,解决单点存储问题
  • Nginx模块,提供文件分发功能,同时集成ngx-fastdfs模块,支持FastDFS文件Nginx访问机制,配合Nginx内部映射机制,实现文档保护措施。在该模中,利用Nginx的文件分发功能(sendfile),使得文件映射服务,只提供鉴权、文件映射,不再提供从FastDFS中下载文档到容器,读取文件到内存,并通过容器将内容写回给客户端,从而释放了内存、IO、并发等方面的资源,从而提高文档的高速访问,达到高性能读取的目的

逻辑处理流程


上图流程描述了文档存储的处理流程,对照系统架构中,主要操作为:文档映射服务、内容管理系统、FastDFS等三个模块。

  • 当用户将文档提交到内容管理系统中,该服务将接收到的文件直接提交到FastDFS模块中
  • 当文档存储成功后,FastDFS将返回文档存储信息
  • 内容管理系统接收到文档存储信息后,将该信息存储到文档映射服务中,并告知客户端上传结果

上述流程,就是一个普通的上传流程,唯一区别是增加了文档映射服务模块。在该模块中,主要存储了两种信息:

  1. 文件在FastDFS中的位置信息
  2. 用户访问该文件的URL,比如https://www.xx.com/storage/748/startjava.epub,该URL可以是生成的短Url(/storage/beNvds34sd) ;URL也可能是资源的标识b20190819001;总之通过该访问URL能够映射到FastDFS的位置信息

上述流程中,对于文件存储主要依赖于FastDFS,而对于上传的并发、内存等需求,未发生改变,可通过部署分节点提高上传性能。对于读多写少的系统而言(通常更多的大文件仍然是通过后台分步存储),高性能的读取对于性能的提高效果更为显著。

对于文件的读取,主要用到的模块为:

  • Nginx(文件分发)
  • 文件映射服务,主要是提供鉴权逻辑以及根据请求的URL映射到对应的文件位置,并提供Nginx内部映射头信息,进行服务器内部跳转;
  • FastDFS,提供文档读取


  • Nginx作为反向代理和负载均衡,接收用户访问文档请求,并将该请求转发到文档映射服务中
  • 文档映射服务根据请求Url,查询(缓存)该Url对应的文件位置
  • 查询到文件位置后,通过设置响应头X-Accel-Redirect,该头信息的值为文件的实际存储位置
  • 设置X-Accel-Redirect头信息后,服务将自动内部转发到Nginx上,Nginx读取设置的文件位置信息,并将该文件信息转发到ngx-fastdfs-module模块中
  • ngx-fastdfs-module模块读取文件数据,并将该数据返回给Nginx,从而实现Nginx分发文件,实现高性能下载文件的目的

以上步骤为下载文件的整体流程,为了实现鉴权、Nginx高性能分发文件,需要对Nginx进行下述配置:

  • Nginx开启sendfile功能
    在http模块中添加以下信息:
    sendfile on;
  • 通过nginx转发时自动添加X-Sendfile信息,该节点和sendfile节点同步开启和关闭
    在http模块中添加以下信息,参考上图:
    proxy_set_header X-Sendfile on;
    对于文件映射服务来说,可以通过读取该节点信息,以确定当前服务是否开启了Nginx文件分发功能,如果读取不到或该值不为on,则可以通过容器进行文件读取和下载(性能低)
  • 对于FastDFS的Nginx,需要开启internal属性,该属性开启后,则表明当前的代理反问,只能通过服务器内部转发,浏览器等客户端无法感知,且外部无法直接访问该代理URL,从而可以配合文件映射服务实现鉴权和限流的措施


  • Nginx的X-Accel-Redirect静态转发。对于Nginx将请求下载服务转发给文件映射服务后,文件映射服务查询到文件位置信息,通过在响应头中设置该信息,即X-Accel-Redirect=文件位置信息,该设置可以实现服务器内部转发,客户端无法感知,从而保护了真实的文件位置信息。虽然该方案效率会比302方案性能稍低,但可以实现鉴权及文件保护,因此在该方案中作为文件转发的处理方案
  • 文件映射服务与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; # 对转发请求,添加X-Sendfile节点信息
sendfile        on;  #开启nginx文件分发

location /M00 部分,为FastDFS的配置,其中添加了internal,保证该代理只能通过内部转发请求。root节点配置的是FastDFS的文件存储位置。

后一个包含/d/的节点配置,模拟了文件映射服务的配置。

文件映射处理逻辑

    @GetMapping("/t")
    public void download(HttpServletResponse response, @RequestHeader(value = "X-Sendfile", required = false) String useXSend) {
        if ("on".equalsIgnoreCase(useXSend)) {
            // nginx分发下载
            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分发下载的过程,对于容器下载,就是普通的读取文件,并写数据流到客户端。通过X-Sendfile控制是走容器下载,还是走Nginx下载。另外Nginx和容器都可以支持断点续传,后续会描述Nginx的断点续传功能。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容