ubuntu下Nginx詳解及點播直播服務器搭建

1 Nginx簡介

  Nginx(engine x)是一個高性能的HTTP服務器,也是一款輕量級的Web服務器,反向代理服務器及電子郵件IMAP/POP3/SMTP代理服務器。Nginx是由伊戈爾·賽索耶夫爲站點Rambler.ru開發的。第一個公開版本發佈於2004年10月4日。其將源代碼以類BSD許可證的形式發佈,因它的穩定性、豐富的功能集、示列配置文件和低系統資源的消耗而聞名。其特色是佔用內存少,併發能力強,事實上nginx的併發能力確實在同類型的網頁服務器中表現比較好,中國大陸使用nginx網站用戶有:百度、京東、新浪、網易、騰訊、淘寶等。html

2 Nginx的特色

2.1 動靜分離

  Nginx是一種輕量級,高性能,多進程的Web服務器,很是適合做爲靜態資源服務器使用,而動態的訪問操做能夠是用穩定的Apache,Tomcat及IIS等來實現。這裏就以Nginx做爲代理服務器的同時,也使用其做爲靜態資源服務器。
靜態資源服務器經過絕對路徑去訪問,放在nginx服務器當中。
動態資源經過url拼接字符串的方式去訪問例如tomcat服務器node

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定向到同一個後端服務器,後端服務器爲緩存時比較有效。nginx

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負載保持對同一服務器的會話,這種方式最方便,最輕量。git

2.2.3 文件的上傳下載

  若是實現了均衡負載,除了Session問題,咱們還會碰到文件的上傳下載問題。文件不可能上傳不一樣的服務器上,這樣會致使下載不到對應文件的問題。下面來看一下解決方案:
  1).獨立文件服務器
  2).文件壓縮數據庫
  兩種方案都是經常使用的,咱們來講一下文件壓縮數據庫,之前的方式都是將文件二進制壓縮相當系型數據庫,而如今NOSQL的流行,加上MongoDB處理文件又比較方便,因此文件壓庫又多了一種選擇。畢竟文件服務器的效率和管理以及安全都不及數據庫。github

2.3 反向代理

  反向代理(Reverse Proxy)方式是指以代理服務器來接受Internet上的鏈接請求,而後將請求轉發給內部網絡上的服務器;並將從服務器上獲得的結果返回給Internet上請求鏈接的客戶端,此時代理服務器對外就表現爲一個服務器。
  反向代理服務器:
  一般的代理服務器,只用於代理內部網絡對Internet的鏈接請求,客戶機必須指定代理服務器,並將原本要直接發送到Web服務器上的http請求發送到代理服務器中。當一個代理服務器可以代理外部網絡上的主機,訪問內部網絡時,這種代理服務的方式稱爲反向代理服務器。web

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」將嘗試自動檢測它)。shell

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直播服務發佈成功。

相關文章
相關標籤/搜索