美文网首页
高性能分布式文件存储及文件下载解决方案-基于Nginx+Fast

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

作者: 李小磊_0867 | 来源:发表于2019-10-11 10:40 被阅读0次

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

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

  • 大量静态文件的存储以及访问,包括图片、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的断点续传功能。

相关文章

网友评论

      本文标题:高性能分布式文件存储及文件下载解决方案-基于Nginx+Fast

      本文链接:https://www.haomeiwen.com/subject/jtqtmctx.html