开源Nginx 文件上传服务器。ngx_upload_module+web.py+gevent+varnish前端缓存

最近参与公司一项目,当中需使用图片与音频的存储方案,经过多方面考虑,采用了Nginx的ngx_upload_module作为上传前端,python web.py+gevent作为后端文件处理及生成缩略图方式,配合使用Varnish作为http缓存。整体架构与性能上应该比较理想。

前期由于考虑了分布式存储,大量地实验与尝试了fastDFS,感觉的确是小文件存储方案里面比较优秀的,但是由于对fastDFS的不熟悉与稳定性的考虑,暂时放下。

实现时,参考了大量py-graphic-0.1.1的思路,感谢作者。

https://code.google.com/p/py-graphic/

 

1、实现原理

     由Nginx+nginx_upload_module实现接收http Post请求,并将用户文件保存到nginx.conf指定的位置,这些文件信息从原始请求体中分离并根据nginx.conf中的配置重新组装好上传参数,交由upload_pass指定的段处理,从而允许处理任意上传文件。每个上传文件中的file字段值被一系列的upload_set_form_field指令值替换。每个上传文件的内容可以从$upload_tmp_path变量读取,或者可以将文件转移到目的目录下。上传的文件移除可以通过upload_cleanup指令控制。如果请求的方法不是POST,模块将返回405错误(405 Not Allowed),该错误提示可以通过error_page指令处理。

     upload_pass指定为proxy_pass地址,将上传结果转由gevent+web.py进行处理。通过web.input()获取所有参数,包括文件实际路径与大小,Md5等字段。如果是图片格式,则通过pgmagick组件对图片进能剪栽切割生成缩略图。然后将原图与缩略图保存到web目录下,最后对客户端返回JSON格式的Varnish缓存地址。

 

2、所需用到的依赖项

    以CentOS 最小化安装为例。

yum -y install gcc gcc-c++ autoconf make python python-devel libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel libxml2 libxml2-devel zlib zlib-devel glibc glibc-devel glib2 glib2-devel bzip2 bzip2-devel ncurses ncurses-devel curl curl-devel e2fsprogs e2fsprogs-devel krb5 krb5-devel libidn libidn-devel openssl openssl-devel openldap openldap-devel nss_ldap openldap-clients openldap-servers

 

 单独编译安装:      

boost_1_50_0
setuptools-0.6c11-py2.6.egg
gevent-1.0rc2
GraphicsMagick-1.3.16
pcre-8.10
pgmagick-0.5.4

  安装Nginx + ngx_upload_module 2.2。

      安装过程可以参考http://blog.s135.com/nginx_php_v6/

3、配置nginx.conf

    具体ngx_upload_module配置参数,请参考官网。

user www www;

worker_processes  4;

error_log /*自定义路径*/nginx_error.log crit;

pid        /usr/local/nginx/nginx.pid;

worker_rlimit_nofile 65535;

events {
    use epoll;
    worker_connections  65535;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    server_names_hash_bucket_size 128;
    client_header_buffer_size 32k;
    large_client_header_buffers 4 32k;
    client_max_body_size 20m;
      
    sendfile on;
    tcp_nopush     on;
    keepalive_timeout 60;
    tcp_nodelay on;

    gzip on;
    gzip_min_length  1k;
    gzip_buffers     4 16k;
    gzip_http_version 1.0;
    gzip_comp_level 2;
    gzip_types       text/plain application/x-javascript text/css application/xml;
    gzip_vary on;

    server {
        listen      9000;
        server_name  localhost;

        location / {
            index  index.html index.htm;
            root /自定义路径;
        }


        location /PicUpload {
                upload_pass /PicProccess;
                upload_store /*自定义路径*/ 1;
                upload_store_access user:r;

                upload_set_form_field $upload_field_name.name "$upload_file_name";
                upload_set_form_field $upload_field_name.content_type "$upload_content_type";
                upload_set_form_field $upload_field_name.path "$upload_tmp_path";

                upload_aggregate_form_field "$upload_field_name.md5" "$upload_file_md5";
                upload_aggregate_form_field "$upload_field_name.size" "$upload_file_size";

                upload_pass_form_field "^uid$|^thumb$";  #指定用户ID与缩略图尺寸,例如100x100

                upload_cleanup 400 404 499 500-505;  #遇到这些码,就清除上传内容。
        }

        location /VoiceUpload {
                upload_pass /VoiceProccess;
                upload_store /*自定义路径*/ 1;
                upload_store_access user:r;

                upload_set_form_field $upload_field_name.name "$upload_file_name";
                upload_set_form_field $upload_field_name.content_type "$upload_content_type";
                upload_set_form_field $upload_field_name.path "$upload_tmp_path";

                upload_aggregate_form_field "$upload_field_name.md5" "$upload_file_md5";
                upload_aggregate_form_field "$upload_field_name.size" "$upload_file_size";

                upload_pass_form_field "^uid$";  #post带uid域

                upload_cleanup 400 404 499 500-505;
        }

        location /PicProccess {
                proxy_pass http://127.0.0.1:9020/PicUpload;
        }
        location /VoiceProccess {
                proxy_pass http://127.0.0.1:9020/VoiceUpload;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /自定义路径;
        }

        log_format access '$remote_addr - $remote_user[$time_local] "$request"'
               '$status $body_bytes_sent "$http_referer"'
               '$http_user_agent" $http_x_forwarded_for';
        access_log /日志路径/nginx_access.log access;
     }

}

  4、 创建upload_store 存储位置。

     由于ngx_upload_module是散列存储,所以子目录需要包含 0 1 2 3 4 5 6 7 8 9 十个目录。

     具体可参考http://www.grid.net.ru/nginx/upload.en.html

   5、开源Github地址

  https://github.com/vovolie/nginx_upload

     十分简单的代码,可随意修改。

      目录结构

  bin : 包括Daemon守护进程,wsgiServer.py主程序。

  conf:日志配置与程序配置文件。

      log:日志存放位置。

      test:post测试的小程序。

    6、安装varnish,如果是同一台服务器,需指定不同的端口,在conf配置文件中进行修改返回的地址。

posted on 2013-02-20 00:12  Vovolie  阅读(5405)  评论(0编辑  收藏  举报

导航