1 Nginx简介
Nginx(engine x)是一个高性能的HTTP服务器,也是一款轻量级的Web服务器,反向代理服务器及电子邮件IMAP/POP3/SMTP代理服务器。Nginx是由伊戈尔·赛索耶夫为站点Rambler.ru开发的。第一个公开版本发布于2004年10月4日。其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、示列配置文件和低系统资源的消耗而闻名。其特点是占用内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服务器中表现比较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
2 Nginx的特点
2.1 动静分离
Nginx是一种轻量级,高性能,多进程的Web服务器,非常适合作为静态资源服务器使用,而动态的访问操作可以是用稳定的Apache,Tomcat及IIS等来实现。这里就以Nginx作为代理服务器的同时,也使用其作为静态资源服务器。
静态资源服务器通过绝对路径去访问,放在nginx服务器当中。
动态资源通过url拼接字符串的方式去访问例如tomcat服务器
2.2 均衡负载
2.2.1 Nginx的upstream目前支持以下几种方式的分配
1).轮询(默认)
每个请求按实际顺序逐一分配到不同的后端服务器,如果后端服务器dump掉,能自动剔除。
2) weight(权重)
为后台服务器指定轮询几率,weight和访问量成正比,让性能高的服务器承担更多的访问量。
3).ip_hash
每个请求按访问ip的hash结构分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
4).fair(第三方)
按后端服务器的响应时间来分配请求,响应时间快短的优先分配。
5).url_hash(第三方)
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。
2.2.2 Session问题
当我们确定一系列负载的服务器后,如果你先访问到A服务器,下一次请求突然转到B服务器。这时候与A服务器建立的Session,传到B服务器肯定是无法响应的。下面我们来看一下解决方案:
1).Session或凭据缓存到独立的服务器上
将seesion保存到独立的服务器,缓存效率会比较高,但如果同时访问的服务器过多的话,可能导致session服务器无法负荷而宕机。
2).Session或凭据保存数据库中
保存到数据中,除了要控制Session的有效期,同时也加重了数据库的负担,所以最终转变为SQL Server负载均衡,涉及读,写,过期同步,处理起来会很复杂。
3).nginx ip_hash保持同一IP的请求都是指定到固定的一台服务器
通过nginx ip_hash负载保持对同一服务器的会话,这种方式最方便,最轻量。
2.2.3 文件的上传下载
如果实现了均衡负载,除了Session问题,我们还会碰到文件的上传下载问题。文件不可能上传不同的服务器上,这样会导致下载不到对应文件的问题。下面来看一下解决方案:
1).独立文件服务器
2).文件压缩数据库
两种方案都是常用的,我们来说一下文件压缩数据库,以前的方式都是将文件二进制压缩至关系型数据库,而现在NOSQL的流行,加上MongoDB处理文件又比较方便,所以文件压库又多了一种选择。毕竟文件服务器的效率和管理以及安全都不及数据库。
2.3 反向代理
反向代理(Reverse Proxy)方式是指以代理服务器来接受Internet上的连接请求,然后将请求转发给内部网络上的服务器;并将从服务器上得到的结果返回给Internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。
反向代理服务器:
通常的代理服务器,只用于代理内部网络对Internet的连接请求,客户机必须指定代理服务器,并将本来要直接发送到Web服务器上的http请求发送到代理服务器中。当一个代理服务器能够代理外部网络上的主机,访问内部网络时,这种代理服务的方式称为反向代理服务器。
2.4 单点故障
某台节点服务器挂了,但是Nginx仍然会可能选中这个出故障的机器,然后就一直连接着是因为超时时间很长,具体多长不清楚,所以为了避免一直连接着,我们需要设置超时时间。
用Keepalived搭建双Nginx server集群,防止单点故障
2.5.优化
2.5.1 高层的配置(nginx.conf)
worker_processes auto;
worker_rlimit_nofile 100000;
worker_cpu_affinity 0001 0010 0100 1000 0001 0010 0100 1000;
worker_processes:
定义了nginx对外提供web服务时的worker进程数。最优值取决于许多因素,包括(但不限于)CPU核的数量、存储数据的硬盘数量及负载模式。不能确定的时候,将其设置为可用的CPU内核数将是一个好的开始(设置为“auto”将尝试自动检测它)。
worker_rlimit_nofile:
更改worker进程的最大打开文件数限制。如果没设置的话,这个值为操作系统的限制。设置后你的操作系统和Nginx可以处理比“ulimit -a”更多的文件,所以把这个值设高,这样nginx就不会有“too many open files”问题了。
worker_cpu_affinity:
CPU亲和力配置,让不同的进程绑定不同的CPU,可以减少由于线程切换时CPU切换带来的缓存拷贝导致降低效率。
2.5.2 Events模块
events模块中包含Nginx中所有处理连接的设置。
events {
worker_connections 2048;
multi_accept on;
use epoll;
}
worker_connections:
设置可由一个worker进程同时打开的最大连接数。如果设置了上面提到的worker_rlimit_nofile,我们可以将这个值设得很高。但是不能超过系统的可用socket连接数限制(~ 64K)。
multi_accept:
告诉nginx收到一个新连接通知后接受尽可能多的连接。
use 设置用于复用客户端线程的轮询方法。如果你使用Linux 2.6+,你应该使用epoll。如果你使用FreeBSD,你应该使用kqueue。
(值得注意的是如果你不知道Nginx该使用哪种轮询方法的话,它会选择一个最适合你操作系统的)
2.5.3 HTTP 模块
HTTP模块控制着Nginx http处理的所有核心特性。
http {
server_tokens off;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
...
}
server_tokens:
并不会让nginx执行的速度更快,但它可以关闭在错误页面中的nginx版本数字,这样对于安全性是有好处的。
sendfile:
可以让sendfile()发挥作用。sendfile()可以在磁盘和TCP socket之间互相拷贝数据(或任意两个文件描述符)。Pre-sendfile是传送数据之前在用户空间申请数据缓冲区。
之后用read()将数据从文件拷贝到这个缓冲区,write()将缓冲区数据写入网络。sendfile()是立即将数据从磁盘读到OS缓存。
因为这种拷贝是在内核完成的,sendfile()要比组合read()和write()以及打开关闭丢弃缓冲更加有效(更多有关于sendfile)。
tcp_nopush:
告诉nginx在一个数据包里发送所有头文件,而不一个接一个的发送。
tcp_nodelay:
告诉nginx不要缓存数据,而是一段一段的发送--当需要及时发送数据时,就应该给应用设置这个属性,这样发送一小块数据信息时就不能立即得到返回值。
access_log off;
error_log /var/log/nginx/error.log crit;
access_log:
设置nginx是否将存储访问日志。关闭这个选项可以让读取磁盘IO操作更快(aka,YOLO)
error_log:
告诉nginx只能记录严重的错误:
3 Nginx编译
nginx依赖于pcre, openssl, zlib, nginx-rtmp-module。故在编译nginx之前必须下载先编译这些库。
pcre是一个Perl库,包括perl兼容的正则表达式库。
zlib提供数据压缩用的函式库。
nginx-rtmp-module是nginx的rtmp流媒体服务拓展库,实现了rtmp,hls,dash的流媒体服务功能。下面是本人编写的nginx一键下载编译脚本,运行该脚步即可下载编译nginx:
#!/bin/bash
#indicate that this script execute by /bin/bash
# 本脚本用于自动下载nginx已经依赖库pcre, openssl, zlib, nginx-rtmp-module,并编译安装,安装时需要输入管理员账号权限
#zipexts=(".tar.gz" ".tar.bz2" ".tar.Z" ".tgz" ".tar" ".gz" ".bz2" ".Z" ".rar" ".zip")
#zipexts=(".tar.gz" ".tar.bz2" ".tar.Z" ".tgz" ".tar" ".gz" ".bz2" ".Z" ".rar" ".zip")
# 由于shell脚本的函数不能返回字符串,故设置全局变量以便记录dezip产生的返回值以及下downloazanddezip函数下载解压后的文件夹名称
extname=""
outputname=""
# 解压压缩包,并返回解压后的文件夹或文件名称
# param1:压缩包名称,必填项
# param2:解压到指定文件夹,可为空
# 返回值:无, 注,shell返回值只能为整形,不能为字符串
dezip(){
outputname=$2
extname=""
exename="tar"
unzipflag=""
echo "param1:"$1
# 检测压缩包类型,并使用对应的解压方式
if expr match $1 ".*.tar.gz" != 0; then
extname=".tar.gz"
exename="tar"
unzipflag="-zxvf"
#echo $extname
elif expr match $1 ".*.tar.bz2" != 0; then
extname=".tar.bz2"
exename="tar"
unzipflag="-xjf"
#echo $extname
elif expr match $1 ".*.tar" != 0; then
extname=".tar"
exename="tar"
unzipflag="-xvf"
elif expr match $1 ".*.tgz" != 0; then
extname=".tgz"
exename="tar"
unzipflag="-xvf"
elif expr match $1 ".*.gz" != 0; then
extname=".gz"
exename="gzip" # 或gunzip
unzipflag="-d"
elif expr match $1 ".*.bz2" != 0; then
extname=".bz2"
exename="bzip2" # 或bunzip2
unzipflag="-d"
elif expr match $1 ".*.tar.Z" != 0; then
extname=".tar.Z"
exename="tar"
unzipflag="-xZf"
elif expr match $1 "*.Z" != 0; then
extname=".Z"
exename="uncompress"
unzipflag=""
elif expr match $1 ".*.rar" != 0; then
extname=".rar"
exename="unrar"
unzipflag="e"
elif expr match $1 ".*.zip" != 0; then
extname=".zip"
exename="unzip"
unzipflag="-o"
fi
if [ ! -d $outputname ]; then
outputname=${1%$extname}
echo "outputname" $outputname
fi
#if [ ! -d $outputname ]; then
#mkdir $outputname
#echo $outputname
#fi
echo "$exename $unzipflag $1"
# 解压文件
$exename $unzipflag $1
#return $extname
}
# 下载压缩包并解压
# param1:url
# param2:zip
# return: dezip filename
downloazanddezip()
{
if [ -d $1 ]; then
echo "Invalid url, please input url while you run downloazanddezip"
fi
downloadurl=$1
# 截取?前面的字符串
downloadurl=${downloadurl%\?*}
echo $downloadurl
# 截取最后一个/后面的字符串,即压缩包名称
zipname=${downloadurl##*/}
echo $zipname
if [ ! -f $zipname ]; then
curl -o $zipname $1
echo 'curl -o $zipname $1'
fi
echo "dezip:"$zipname
dezip $zipname
#extname=$?
echo $extname'=dezip' $zipname
if expr match $zipname $extname == 0; then
zipname=${zipname%$extname}
echo "zipname:"$zipname
fi
outputname=$zipname
}
# 下载nginx源码,如果链接有误,直接替换链接即可
curdir=$PWD
downloazanddezip http://117.128.6.28/cache/nginx.org/download/nginx-1.14.2.tar.gz?ich_args2=468-23103716018527_5b6f2632bf91b3cdae35405cfb43338b_10001002_9c89612cdfcbf8d59538518939a83798_ff478ef610d500dd7f20fe13dd251d7b
# 记录nginx库源码文件夹目录名称
nginxname=$outputname
cd $outputname
if [ ! -d "./thirdpart/" ];then
mkdir thirdpart
fi
cd ./thirdpart
# 下载pcre库
downloazanddezip https://ftp.pcre.org/pub/pcre/pcre-8.42.zip
# 记录pcre库源码文件夹目录名称
pcrename=$outputname
# 下载openssl
downloazanddezip https://www.openssl.org/source/openssl-1.0.2q.tar.gz
# 记录openssl库源码文件夹目录名称
opensslname=$outputname
# 下载zlib库
downloazanddezip http://117.128.6.17/cache/www.zlib.net/zlib-1.2.11.tar.gz?ich_args2=531-22232503018317_67f53fed3443a8995b0d31f74b74bce1_10001002_9c89612cdfc7f8d09639518939a83798_9b3b5eb8fa2f98e0b42e37f3838be97f
# 记录zlib库源码文件夹目录名称
zlibname=$outputname
# 从github下载nginx-rtmp-module源码
if [ ! -d "./nginx-rtmp-module/" ];then
git clone https://github.com/arut/nginx-rtmp-module.git
fi
cd ../
make clean
./configure --prefix=$curdir/$nginxname/build --with-openssl=$curdir/$nginxname/thirdpart/$opensslname --with-pcre=$curdir/$nginxname/thirdpart/$pcrename --with-zlib=$curdir/$nginxname/thirdpart/$zlibname --add-module=$curdir/$nginxname/thirdpart/nginx-rtmp-module --with-http_ssl_module
make
make install
4 配置点播服务
4.1 修改nginx.conf
打开build目录下conf文件夹下的nginx.conf文件:
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
# add stat page
location /stat {
rtmp_stat all;
rtmp_stat_stylesheet stat.xsl;
}
location /stat.xsl {
root $nginxpath/thirdpart/nginx-rtmp-module;
}
# add stat page end
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# 支持flv、mp4文件点播
location ~* \.flv$ {#flv 支持
root $flvpath;#flv点播文件目录
}
location ~* \.mp4$ {#MP4 支持
root $mp4path;#mp4点播文件目录
}
}
4.2 测试点播服务
运行nginx:
$sudo ./nginx -c $buildpath/conf/nginx.conf
然后打开浏览器访问:
http://127.0.0.1/test.mp4
如果能够正常播放,说明点播服务配置成功。
5 配置直播服务
5.1 修改nginx.conf配置:
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
location /stat {
rtmp_stat all;
rtmp_stat_stylesheet stat.xsl;
}
location /stat.xsl {
root $nginxpath/third/nginx-rtmp-module;
}
location / {
root html;
index index.html index.htm;
}
location /live { #这里也是需要添加的字段。
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
alias /opt/video/hls;
expires -1;
add_header Cache-Control no-cache;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# 支持flv、mp4文件点播
location ~* \.flv$ {#flv 支持
root $flvpath;#flv点播文件目录
}
location ~* \.mp4$ {#MP4 支持
root $mp4path;#mp4点播文件目录
}
}
}
# 增加rtmp服务
rtmp {
server {
listen 1935;
chunk_size 4096;
# rtmp点播
application vod {
play $rtmpvodpath;#rtmp点播文件存放路径
}
# rtmp直播
application live {
live on;
hls on; #这个参数把直播服务器改造成实时回放服务器。
wait_key on; #对视频切片进行保护,这样就不会产生马赛克了。
hls_path $hls_save_path; #切片视频文件存放位置。
hls_fragment 10s; #每个视频切片的时长。
hls_playlist_length 60s; #总共可以回看的事件,这里设置的是1分钟。
hls_continuous on; #连续模式。
hls_cleanup on; #对多余的切片进行删除。
hls_nested on; #嵌套模式。
}
}
}
5.2 测试rtmp直播服务
安装ffmpeg,并使用ffmpeg进行rtmp推流
$ sudo apt-get install ffmpeg
$ ffmpeg -re -I $mp4path/test.mp4 -vcodec libx264 -acodec aac -strict -2 -f flv rtmp://localhost:1935/live
$ ffplay -I rtmp://localhost:1935/live
若能正常播放rtmp流,则rtmp直播服务发布成功。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。