nginx-fastdfs-mod,fastcgi,文件上传和下载原理
推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习
fastcgi
cgi
什么是cgi?
通用网关接口(Common Gateway Interface、CGI)描述了客户端和服务器程序之间传输数据的一种标准,可以让一个客户端,从网页浏览器向执行在网络服务器上的程序请求数据。
cgi处理流程
-
web服务器收到客户端(浏览器)的请求Http Request,启动CGI程序,并通过环境变量、标准输入传递数据;对于每个http request,都要fork出来一个cgi程序进行处理,这是cgi性能低的主要原因;
-
cgi进程启动解析器、加载配置(如业务相关配置)、连接其他服务器(如数据库服务器)、逻辑处理等;
-
cgi进程将处理结果通过标准输出、标准错误,传递给web服务器;
-
web服务器收到cgi返回的结果,构建http response返回给客户端,并kill掉cgi进程;
环境变量
对于GET请求,将数据打包放置在环境变量
QUERY_STRING中,CGI从环境变量中获取数据;常用的环境变量包括QUERY_STRING、CONTENT_LENGTH等。
环境变量 | 含义 |
---|---|
QUERY_STRING | 传递给CGI程序的请求参数,也就是用"?"隔开,添加在URL后面的字串 |
CONTENT_LENGTH | 由标准输入传递给CGI程序的数据长度,以bytes或字元数来计算 |
… |
标准输入/输出
环境变量的大小是有一定的限制的,不适合传输大量数据;因此后来又发展出另外一种方法:POST,利用了io重定向的方法,让cgi程序可以通过stdin和stdout跟web服务器通信。
当我们指定用这种方法传递请求的数据时,web服务器收到数据后会先放在一块输入缓冲区中,并且将数据的大小记录在CONTENT_LENGTH这个环境变量,然后调用CGI程序并将CGI程序的stdin指向这块缓冲区,于是我们就可以很顺利的通过stdin和环境变量CONTENT_LENGTH得到所有的信息,再没有信息大小的限制了。
fastcgi
什么是fastcgi?
fastcgi(Fast Common Gateway Interface),是对cgi的改进;cgi程序是每次请求都要fork一个进程,而fastcgi是一个常驻的进程;fastcgi效率比cgi提高5倍以上。
nginx支持fastcgi,nginx对应的fastcgi的module为:
ngx_http_fastcgi_module, 它允许将请求传递给fastcgi服务器。
fastcgi处理流程
fastdfs-nginx扩展模块
参考架构
说明: 在每一台storage服务器主机上部署Nginx及FastDFS扩展模块,由Nginx模块对storage存储的文件提供http下载服务, 仅当当前storage节点找不到文件时会向源storage主机发起redirect或proxy动作。
文件下载过程
fastdfs-nginx-mod只提供下载功能:
收到下载请求后,先在本地的storage检测文件是否存在,如果有直接发给客户端;
如果本地没有,则可以通过proxy和redirect两种方式处理,这两种模式可以配置:
proxy模式,自己去其他storage读取数据,然后转发给客户端;
redirect模式,回复客户端哪个storage上有该文件,客户端自己再去下载。
文件上传类型分析
秒传
客户端发送文件前,先发送文件md5值;服务器查找文件md5值是否已经存在,即文件是否已经存在,存在则可以进行秒传;md5可以存入mysql,也可以存入redis,查询更快。
分片上传
分片上传,就是前端将所要上传的文件,按照一定的大小,将整个文件分隔成多个数据块(我们称之为Part)来进行分别上传,上传完之后再由服务端对所有上传的文件进行汇总整合成原始的文件。
分片上传的场景:
- 大文件上传;
- 网络环境不好,存在需要重传风险的场景。
大文件上传
大文件上传一般采用分片上传的方式,这样可以提高文件上传的速度,前端拿到文件流后进行分片,然后与后端进行通讯传输,一般还会结合断点继传,这时后端一般提供三个接口:
-
第一个接口获取已经上传的分片信息
-
第二个接口将前端分片文件进行传输
-
第三个接口是将所有分片上传完成后告诉后端进行文件合并
断点续传
断点续传也是基于分片上传的,如果上传的过程中碰到网络故障,恢复后可以从已经上传完成的部分开始上传,没有必要从头开始上传。
断点续传,客户端发起续传前需要到服务器查询目前已经上传的片情况;一般会将分片存储为临时文件;分片上传情况可以存入redis,这样查询比较快,否则需要遍历文件目录,比较慢;收到最后一个分片后进行合并。
多线程下载
对于单个连接限速的场景,可以使用多线程下载
- 先获取文件大小;
- 根据线程数量划分每个线程要下载的文件长度,确定好range;
- 写入文件;写入同一文件的不同位置,需要加互斥锁;也可以使用临时文件,全部下载完成后,在进行merge。