用nginx區(qū)分文件大小做出不同響應(yīng)
昨晚和前21v的同事聊天,說到我離職后一些技術(shù)上的更新。其中有個給某大客戶(游戲下載類)的特殊需求設(shè)計,因為文件大小差距很大——估計是大版本和補丁的區(qū)別——又走的是同一個域名,而squid在響應(yīng)比較大的文件時,尤其是初次下載的時候,性能比較差,所以拆成兩組服務(wù)器,squid服務(wù)于較小的文件,通過pull方式從peer層獲取,nginx服務(wù)于較大的文件,通過push方式由peer層分發(fā)同步。外部發(fā)布域名一律解析到squid服務(wù)器組上,請求透傳到peer層的nginx,nginx分析這個url的content-length,如果大于閾值,則不返回文件,而是302到nginx服務(wù)器組的獨立域名下的相應(yīng)url去。
這里要注意的是,nginx的內(nèi)部變量里有一個$content-length,是不能用在這里的,官方wiki是這么解釋這個變量的:”This variable is equal to line Content-Length in the header of request”。可見,這個變量是請求頭的內(nèi)容,一般見于POST請求用來限定POST信息的長度;而不是我們需要的響應(yīng)頭的內(nèi)容。
老東家最后是修改了nginx的src完成的功能。不過我想,這里其實可以使用http_perl_module完成的。而且還可以擴(kuò)展302跳轉(zhuǎn)的功能,把獨立域名改成直接通過remote_addr定向到最近IP上。
因為手頭沒有服務(wù)器,以下內(nèi)容都是憑空想象,看官們注意…… 首先是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
大體應(yīng)該就是上面這樣。 之前還考慮過如果不是push方式,可以在perl里考慮使用LWP獲取header,不過仔細(xì)想想:第一,萬一源站開啟了chunked獲取不到content-length呢?第二,就算可以,如果一個文件是1個G,那再去下載這1個G的文件下來,這個perl進(jìn)程肯定掛了——官方wiki里可是連DNS解析時間都認(rèn)為太長……也就是說,這個設(shè)想不適合在peer層,而是在loadbalance的角色,通過lwp的header結(jié)果,小文件upstream到后端的squid,大文件location到另外的nginx。 另一個可改進(jìn)的地方,就是self->location前面,可以結(jié)合Net::IP::Match::Regexp模塊或者自己完成的類似功能,來針對self->remote_addr選擇最近的服務(wù)器組IP,最后返回location(“http://$ip$uri”)這樣。
本文僅代表作者觀點,版權(quán)歸原創(chuàng)者所有,如需轉(zhuǎn)載請在文中注明來源及作者名字。
免責(zé)聲明:本文系轉(zhuǎn)載編輯文章,僅作分享之用。如分享內(nèi)容、圖片侵犯到您的版權(quán)或非授權(quán)發(fā)布,請及時與我們聯(lián)系進(jìn)行審核處理或刪除,您可以發(fā)送材料至郵箱:service@tojoy.com






