• 开源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配置文件中进行修改返回的地址。

  • 相关阅读:
    HDU 4665 Unshuffle DFS找一个可行解
    Servlet生命周期引起的问题
    获取真实Ip地址
    java中return与finally的执行顺序
    理解正则表达式
    抽象类与接口
    java 4种方式读取配置文件 + 修改配置文件
    Java基础语法
    接口多继承
    Java类成员(成员变量和方法)的覆盖与隐藏归纳
  • 原文地址:https://www.cnblogs.com/vovlie/p/2917935.html
Copyright © 2020-2023  润新知