nginx中区分文件大小并作出不同响应的实现方法分享

发布时间:2020-11-26编辑:脚本学堂
本文介绍下,在nginx中,区分文件大小,并由此作出不同的服务器响应的方法。有需要的朋友,可以作个参考。

有个给某大客户(游戏下载类)的特殊需求设计,因为文件大小差距很大——估计是大版本和补丁的区别——又走的是同一个域名,而squid在响应比较大的文件时,尤其是初次下载
时,性能比较差,所以拆成两组服务器,squid服务于较小的文件,通过pull方式从peer层获取,nginx服务于较大的文件,通过push方式由peer层分发同步。外部发布域名一
律解析到squid服务器组上,请求透传到peer层的nginx,nginx分析这个url的content-length,如果大于阈值,则不返回文件,而是302到nginx服务器组的独立域名下的相应
url去。

注意:
nginx的内部变量里有一个$content-length,是不能用在这里的,官方wiki是这么解释这个变量的:”This variable is equal to line Content-Length in the
header of request”。
可见,这个变量是请求头的内容,一般见于POST请求用来限定POST信息的长度;而不是我们需要的响应头的内容。

最后是修改了nginx的src完成的功能。

其实可以使用http_perl_module完成的。而且还可以扩展302跳转的功能,把独立域名改成直接通过remote_addr定向到最近IP上。

以下内容仅限测试与学习使用。

首先,在nginx.conf中配置:
 

复制代码 代码示例:
http {
    perl_modules perl;
    perl_require SizeDiff.pm;
    server {
       listen       80;
       server_name  dl.gamedomain.com;
       location / {
          perl SizeDiff::handler;
       }
    }
}

然后,在perl/SizeDiff.pm文件中,如下:
 

复制代码 代码示例:
package SizeDiff;
use Nginx::Simple;
sub main {
    my $self = shift;
    my $webroot = '/www/dl.gamedomain.com/'
    return HTTP_NOT_ALLOWED unless $self->uri =~ m!^(/.+/)[^/]+$!;
    my $file = $webroot . $1 . $self->filename;
    my @filestat = stat($file) or return HTTP_NOT_FOUND;
    my $filesize = $filestat[7];
    if ( $filesize < 8 * 1024 * 1024 ) {
        return OK;
    } else {
        $self->location('http://bigfile.cdndomain.com'.$self->uri);
    }
};
1

基本就是这样子,之前还考虑过如果不是push方式,可以在perl里考虑使用LWP获取header,不过仔细想想:
第一,万一源站开启了chunked获取不到content-length呢?
第二,就算可以,如果一个文件是1个G,那再去下载这1个G的文件下来,这个perl进程肯定挂了——官方wiki里可是连DNS解析时间都认为太长……也就是说,这个设想不适合在
peer层,而是在loadbalance的角色,通过lwp的header结果,小文件upstream到后端的squid,大文件location到另外的nginx。

另一个可改进之处,就是self->location前面,可以结合Net::IP::Match::Regexp模块或者自己完成的类似功能,来针对self->remote_addr选择最近的服务器组IP,最后返回
location(“http://$ip$uri”)。

闲来神笔,仅作参考,呵呵。
不妨作为研究nginx与squid的文档吧,脚本学堂,祝大家学习进步。