Qiuliang's Site

做一个独立思考和具备创新能力的人,打造谦逊和强大的内心

文件存储系统映射模块原理解析

系统简介

近期我们开发了一套基于Fastdfs的分布式文件存储发布系统,用于解决如下几个问题:

  • 大量静态文件的存储和访问
  • 停用原有的FTP管理模式
  • 解决NAS存储单点的问题

在项目之初,为了实现满足这些需求的一套系统,查证了一些相关案例和开源组件,本着简单可依赖的原则,最后确定为采用Fastdfs作为存储平台,之所以是Fastdfs,也是觉得一是公司的某些业务线已经在使用,其可用性和稳定性已得到一定检验;二是Fastdfs作为国内的一款开源软件,资料较多且使用成本较低。

核心思路

因底层存储系统采用了开源实现,那么我们的核心就是做一个简单易用的文件管理端和发布站点,使用过Fastdfs的同学应该知道,通过其client api上传文件后,得到的是一个通过哈希散列计算后的文件名,无法使用原始文件名进行访问,如果是一般的文件存储(例如一些广告背景图等),可能问题也不大,但如果是发布一个促销专题页面,那么这个工作将变得极其困难,因为一个促销专题页,往往同时包含所依赖的样式文件、背景图片、脚本等,页面html中一般是依赖的相对路径,所以如果直接上传到Fastdfs则文件路径依赖的问题无法解决,或者说要很麻烦的方式解决。

因此,我们引入了映射模块,用来处理逻辑地址和物理地址的对应关系。在本文中也将主要针对映射模块做一个比较详细的介绍和分析。

主要具备如下功能和特点

该系统目前已经上线,主要具备如下功能和特点:

  • 基于目录层级的文件、权限管理方案
  • 文件发布支持多域名
  • 分布式系统保证高可用和稳定性,易于横向扩展
  • 映射模块基于Nginx内部原理实现
  • 支持文件版本管理,支持回滚操作

该系统包含三个模块:

  • 管理模块

      一套基于HTML的UI界面,可进行系统管理、文件管理等功能。
    
  • 映射模块

      负责解析用户请求,并利用Nginx内部特性来返回数据。
    
  • 存储模块

      完全基于Fastdfs实现,易于扩展,要求安装fastdfs-nginx-module。
    

映射模块介绍

映射模块就是一个部署于Tomcat之上的web站点,其职责就是接受前端Nginx转发过来的请求,把一个URL地址转换为fastdfs存储的物理地址,并返回给NginxNginx拿到物理地址后读取文件并返回给用户。

Nginx作为高性能的反向代理服务器,在本模块中起到的作用不仅仅是负载均衡,还利用到了Nginx的一个内部特性sendfile,利用该特性,Tomcat作为映射模块仅需要处理映射关系,而不用处理文件IO操作,而我们知道,应用程序服务器上的性能瓶颈往往是IO操作,通过部署这样的系统结构,得以提高系统的整体性能。

为什么需要加入映射模块

既然底层的存储是基于Fastdfs实现,那么利用fastdfs-nginx-module,完全可以通过文件的物理地址进行访问,只需要做一个GUI来进行文件的管理即可,这也是很多存储系统的实现方式。现加入映射模块,除了解决上文提到的发布促销页面的问题,其意义还在于:

  • 文件的URL地址由复杂变为简单可理解,易于阅读且对SEO友好。
  • 文件的组织方式变得有序、可管理。
  • 基于目录树的结构,易于权限的控制和管理。
  • 发布站点多域名支持、性能扩展更为容易。

映射模块工作流程

完整的映射模块包含如下几个部分:

  • Nginx(同时起到负载均衡和读取文件的作用)
  • Tomcat 站点(处理url和物理地址对应关系的程序逻辑)
  • MySQL(逻辑url和物理url mapping关系存储)

现以用户请求一个文件为例,来说明映射模块的工作流程。例如某用户访问地址: http://promotion.xxx.com/hotel/2014/1111.html

  1. Nginx作为负载均衡,接受用户请求,并将请求转发到某个Tomcat实例上。
  2. Tomcat 通过查询本地缓存,得到物理地址,并将物理地址写入Response Header中,其key为:X-Accel-Redirect
  3. Nginx获取到Response Header中包含X-Accel-Redirect,读取其中的value,并再次将请求分发到fastdfs-nginx-module上。
  4. fastdfs-nginx-module返回数据给Nginx,用户接收到文件流,整体流程结束。

流程图

部署说明和关键配置

要实现如上的系统结构,在系统部署和配置上需要满足如下的条件:

  • Nginx作为前端负载均衡
  • Tomcat(或其他任意后端Server)部署映射处理程序
  • Fastdfs Tracker和Storage服务器集群
  • Nginx转发规则需要配置两个,一是fastdfs group路径,二是除此之外的所有路径。

Nginx转发规则配置如下:

转发规则1

location /group1/ {
    expires      -1s;
    proxy_pass http://fastdfs.server;
    #break;
}

转发规则2

location / {
    expires      -1s;
    proxy_set_header Host $host;
    proxy_pass http://efcproxy.server;
    #break;
}

upstream配置

upstream efcproxy.server{
	server 127.0.0.1:8080; #映射处理程序服务器地址
}

upstream fastdfs.server{
	server 192.168.14.153:8080; #fastdfs storage地址
}

还是以上文中的请求示例:

路径/hotel/2014/1111.html会首先被规则2转发到映射处理程序,然后写入Response Header后,X-Accel-Redirect的value为:/group1/M00/AA/BB/asldkjfj89oip9.html,Nginx读取到该值,并由规则1继续完成处理。

X-Accel-Redirect是在Nginx内部处理,所以在用户端浏览器是看不到该header,不会暴露出文件的真实地址,浏览器也不会做302跳转,是在一次请求中完成。

总结

通过上述系统实现,映射模块具备如下的特点:

  • 结构简单、轻量级
  • 拥有基本上接近于静态文件服务器的性能
  • Tomcat无IO压力
  • 易于部署和扩展

文件存储系统整体结构图

最后附上本系统的整体结构图,方便做更全面的了解。

整体结构图

参考