nginx的性能很好,插件也多。当Nginx作为文件下载服务的反向代理,用户请求一个非常大的文件的时候,它会一直占满反向代理服务器与后端主机之间的带宽。因为nginx一次获取整个文件,缓冲获取到的文件,导致客户端不能马上读取到。带宽使用和iowait会很高。

当时经验不足,突然遇到这个问题,想到的第一个办法就是预分发:

在服务端用脚本监听源nginx的根目录;

一旦有文件变化就直接遍历边缘nginx,用wget下载此文件;

在边缘nginx配置nginx proxy_store或proxy_cache模块,这样文件就被缓存到边缘节点了,达到了预分发的效果。

  这个办法理论上是没有问题的,可实际上很难保证在文件预分发完成之前禁止回源。

而恰巧360的开源项目中的ngx_http_subrange_module模块解决了这个问题:

ngx_http_subrange_module就是为了解决这个问题,它能分割HTTP requests。将大数据量的HTTP请求切分为多个子请求,当下载一个1G的文件,subrange将从后端主机中下载文件块,比如先获取5M,然后再获取5M,直到客户端下载完整个文件。

http://www.oschina.net/p/ngx_http_subrange_module

下面是我原来方案使用的脚本:

#!/bin/sh

echo "$0 is running...."
#Configuration. According to the your case configuration to configure.
ADDRLIST=("http://172.30.25.246:8090" "http://192.168.15.159:7091" "http://192.168.15.159:7092" "http://172.30.25.246:8090");
INOTIFYDIR="/home/diskf";
LOGDIR=`pwd`;

#Default Configuration.Please don't change.
RUNDIR=`pwd`;
STARTTIME=0;
NOWTIME=`date +%s`;
FAILEDLIST=`./failedlist.txt`;

#Make sure only one predist.sh is running!
if [ -e pre.pid ]
then
echo "There is a pre.sh running!exit."
exit 0
fi
echo $$ > pre.pid;

#clean cachedir and mkdir tmp
rm -rf "${RUNDIR}/tmp/*";
mkdir -p ${RUNDIR}/tmp;

if [ -e pre.star ]
then
STARTTIME=`cat pre.star`
else
tmptime=`date +%s`;
${tmptime}=${$tmptime-432000};
echo "${tmp}"
fi
echo ${NOWTIME} > pre.star

function download()
{
for item in $@
do
name=`echo $item | cut -d '|' -f1`;
url=`echo $item | cut -d '|' -f2`;
if [ -z $url ];
then 
exit 1;
fi
touch $name;
wget "$url" -O "$STOREPATH$name" -a "$WGETLOGDIR"
echo "------Status:$?-----";
if [ $?!=0 ];
then
echo "Download $url failed!";
echo "$item" >> $FAILEDLIST; 
fi
echo $url;
done
}

function scandir() {
local cur_dir parent_dir workdir
workdir=$1
cd ${workdir}
if [ ${workdir} = "/" ]
then
cur_dir=""
else
cur_dir=`pwd`
fi

for dirlist in $(ls ${cur_dir})
do
if test -d ${dirlist};then
cd ${dirlist}
scandir ${cur_dir}/${dirlist}
cd ..
else
#echo ${cur_dir}/${dirlist}
a=`stat -c %Y ${cur_dir}/${dirlist}`;
abs_dir=${cur_dir}/${dirlist};
if [ $STARTTIME -lt $a ]
then
for tmpaddr in ${ADDRLIST[@]}
do
touch "${RUNDIR}/tmp/${dirlist}"; 
#wget -b "${tmpaddr}${abs_dir#$INOTIFYDIR}" -O "${RUNDIR}/tmp/${dirlist}" -a "${LOGDIR}/wgetinfo.log";
wget "${tmpaddr}${abs_dir#$INOTIFYDIR}" -O "${RUNDIR}/tmp/${dirlist}" -a "${LOGDIR}/wgetinfo.log";
if [ $?!=0 ];
then
echo "Download failed!";
echo "${tmpaddr}${abs_dir#$INOTIFYDIR}|${RUNDIR}/tmp/${dirlist}" >> $FAILEDLIST; 
fi
echo "wget status:$?; filename:${RUNDIR}/tmp/${dirlist}";
#rm -rf "${RUNDIR}/tmp/${dirlist}";
done
fi
fi
done
}

if test -d $INOTIFYDIR
then
#Download the files which dowload filed just now.
items=`cat $FAILEDLIST`;
echo "">"$FAILEDLIST";
download ${items};

#Scand dir a new loop.
scandir $INOTIFYDIR 
elif test -f $INOTIFYDIR 
then
echo "You set a file as INOTIFYDIR but not a directory,pleas reinput and try again"
exit 1
else
echo "The INOTIFYDIR isn't exist which you input,pls input a new one!!"
exit 1
fi
cd ${RUNDIR}
rm -f pre.pid
echo "$0 has been finished....."
View Code

END

posted on 2015-05-25 19:25  步孤天  阅读(1993)  评论(0编辑  收藏  举报