GitChat · 架構 | 如何從零開始搭建高性能直播平臺?

來自 GitChat 做者:七夜html

前言

如今直播已經成爲移動互聯網時代一個新的重要流量入口,從YY、鬥魚到花椒直播,直播已經成爲人們分享交流的新方式,應用場景衆多,主要分爲:linux

  • 金融類直播:金融直播可應用於實時解盤,在線專家講座,專家在線直播技術分析、指導投資者等使用場景。nginx

  • 大型賽事,演唱會類直播:可應用於大型演唱會,音樂會,遊戲,體育賽事等類直播場景。git

  • 互動類直播:娛樂類互動,如YY等。github

  • 會議類直播:大型會議直播。web

等4大類。在本文中,我將先從rtmp協議開始,一步步帶領你們搭建一個簡易高性能的直播平臺。正則表達式

RTMP協議詳解

RTMP協議Real Time Message Protocol(實時信息傳輸協議)的首字母縮寫,是由Adobe公司開發的一種用於解決多媒體數據傳輸流多路複用和分包的網絡協議。它工做在TCP協議之上,所以是一種提供可靠交付的協議,在傳輸時不會出現丟包狀況,從而保證了用戶體驗(QoE)。雖然TCP協議爲了提供可靠交付付出了一些額外的開銷作爲代價,佔用了一些帶寬和處理器資源,可是隨着網絡帶寬的提升和硬件的發展,這些開銷會顯得愈來愈微不足道。所以RTMP協議在爲了有很好的發展前景。瀏覽器

官方定義:tomcat

The Real-Time Messaging Protocol (RTMP) was designed for安全

high-performance transmission of audio, video, and data between Adobe

Flash Platform technologies, including Adobe Flash Player and Adobe

AIR. RTMP is now available as an open specification to create products

and technology that enable delivery of video, audio, and data in the

open AMF, SWF, FLV, and F4V formats compatible with Adobe Flash

Player.

協議分類

  • RTMP協議工做在TCP之上,是應用層協議, 默認的端口是1935。

  • RTMPE在RTMP的基礎上增長了加密功能。

  • RTMPT工做在HTTP之上,默認端口是80或443,可穿透防火牆。

  • RTMPS相似RTMPT,增長了TLS/SSL的安全功能。

  • RTMFP爲RTMP協議的UDP版本。

雖然協議變種有不少,但實際在咱們的直播應用中最多見的是原生的RTMP協議,所以本篇文章以該協議的1.0版本爲基礎,對其它演進協議感興趣的同窗能夠關注本文的後續知識。

交互流程

RTMP的交互流程能夠分爲握手過程、控制命令傳輸與數據傳輸。

enter image description here

  • 握手過程

RTMP 鏈接以握手開始,RTMP 握手由三個固定長度的塊組成。客戶端 (發起鏈接請求的終端) 和服務器端各自發送相同的三塊。便於演示,本文將從客戶端發送的這些塊指定爲 C0、C1 和 C2;將從服務器端發送的這些塊分別指定爲 S0、S1 和 S2。

RTMP握手以客戶端發送 C0 和 C1 塊開始,客戶端要等收到S1以後才能發送C2,客戶端要等收到S2以後才能發送其餘信息(控制信息和真實音視頻等數據),服務端要等到收到C0以後發送S1, 服務端必須等到收到C1以後才能發送S2, 服務端必須等到收到C2以後才能發送其餘信息(控制信息和真實音視頻等數據)。如下爲RTMP握手的時序圖介紹。

enter image description here

流程圖中所提到的各類狀態以下:

狀態 描述
未初始化 客戶端在C0中發送協議版本,如服務端支持,則回發送S0和S1,若是不能,則鏈接結束
版本發送 客戶端等待S1包,服務端等待C1包,當接收到想要的包,客戶端發送C2,服務端發送S2,此時階段變成了ACK的發送
ACK發送 客戶端和服務端分別等待S2和C2
握手完成 客戶端和服務交換消息

理論上來說只要知足以上條件,如何安排6個Message的順序都是能夠的。但在實際實現中爲了儘可能減小通訊的次數,客戶端發送C0+C1,服務端發送S0+S1+S2,再客戶端在發送C2結束握手。

enter image description here

  • 控制命令傳輸

握手結束之後,RTMP協議進入控制命令傳輸過程,客戶端經過發送connnect命令與服務器實現雙向鏈接。鏈接成功後,經過發送createStream命令創建網絡流。

  • 數據傳輸

網絡流創建成功後,推流(將直播內容推送至服務器的過程)過程會發送publish命令發佈音視頻內容,拉流(服務器已有直播內容,用指定地址進行拉取的過程)過程會發送play命令播放內容。

協議格式

URI格式

rtmpt://127.0.0.1/{app}/{stream_name}

  • {app}爲音頻/視頻和其餘內容定義的一個容器。

  • {stream_name}爲具體的一個流名稱。

消息(Message)格式

enter image description here

消息是RTMP協議中基本的數據單元,不能種類的消息包含有不能的消息類型(Message Type)。RTMP協議一共規範了十多種消息類型。其中類型爲8,9的消息分別用於傳輸音頻和視頻數據。消息頭包含如下信息:

  • Message Type: 消息類型,佔用1個字節。

  • Length: 有效負載的字節數,佔用3個字節。該字段是用大字節序表示的。

  • Timestamp: 時間戳,佔用4個字節,用大字節序表示。

  • Message Stream Id: 消息流ID,標識消息所使用的流,用大字節序表示。

消息塊格式

在網絡上傳輸數據時,消息須要被拆分紅較小的數據塊才適合在相應的網絡環境上傳輸。RTMP協議中規範了對消息拆分紅消息塊,每一個消息塊首部(ChunkHeader)有三部分組成:用於標識本塊的ChunkBasicHeader,用於標識本塊負載所屬消息的ChunkMessageHeader,以及當時間戳溢出時纔出現的ExtendedTimestamp。

消息分塊

RTMP傳輸媒體數據的過程當中,發送端首先把媒體數據封裝成消息,而後把消息分割成消息塊,最後將分割後的消息塊經過TCP協議發送出去。接收端在經過TCP協議收到數據後,首先把消息塊從新組合成消息,而後經過對消息進行解封裝處理就能夠恢復出媒體數據。

開源技術選型

目前直播服務器有開源和商業兩種版本,商業版本主要又FMS(Flash Media Server)與Wowza。本文章僅針對開源版本作介紹,相應的開源項目主要分爲Red5與 Nginx-Rtmp兩類:

Red5

簡介

GitHub:https://github.com/Red5/red5-... (1k+ stars)

enter image description here

Red5是一個採用Java開發開源的Flash流媒體服務器。它支持:把音頻(MP3)和視頻(FLV)轉換成播放流; 錄製客戶端播放流(只支持FLV);共享對象;現場直播流發佈;遠程調用。Red5使用RTMP, RTMPT, RTMPS, 和RTMPE做爲流媒體傳輸協議,在其自帶的一些示例中演示了在線錄製,flash流媒體播放,在線聊天,視頻會議等一些基本功能。

官方給出的主要特性:
Red5 is an Open Source Flash Server written in Java that supports:

  • Streaming Video (FLV, F4V, MP4, 3GP)

  • Streaming Audio (MP3, F4A, M4A, AAC)

  • Recording Client Streams (FLV and AVC+AAC in FLV container)

  • Shared Objects

  • Live Stream Publishing

  • Remoting

  • Protocols: RTMP, RTMPT, RTMPS, and RTMPE

Additional features supported via plugin:

  • WebSocket (ws and wss)

  • RTSP (From Axis-type cameras)

  • HLS

安裝與簡單應用實例(Mac下安裝)

前置條件(jdk已安裝)。

enter image description here

  • 建立安裝目錄:

mkdir -p /Users/ypzdw/gitchat/rtmp/red5

  • 設置主目錄環境變量:

export RED5_HOME=/Users/ypzdw/gitchat/rtmp/red5

  • 下載red5應用,並解壓到RED5_HOME:

https://github.com/Red5/red5-...

enter image description here

目錄簡介:因爲 Red5 是在 Tomcat 中運行的,所以 Red5 項目與普通 JAVAEE 項目結構相似

conf:red5配置目錄

lib:存放的是一些依賴jar包
weapps:用來存放應用程序,與tomcat下的webapps目錄做用相似。

  • 運行:

cd /Users/ypzdw/gitchat/rtmp/red5
./red5.sh &

  • 簡單實例

通過前面的介紹,這裏將用red5介紹一個簡單的實例。打開http://127.0.0.1:5080 出現red5 管理控制檯。

enter image description here

選擇"Publisher" demo,該項目提供了主播端與聽課端。

enter image description here

主播端:「1」中 Name表示流名,publish能夠發佈一個直播。

enter image description here

直播收聽端:「1」中Name爲收聽的流名;「2」中 Location爲直播端地址;「3」中Log能夠觀察到整個直播的交流日誌。

enter image description here

enter image description here

  • 中止應用:

cd /Users/ypzdw/gitchat/rtmp/red5

./red5-shutdown.sh

Nginx-Rtmp

Github:https://github.com/arut/nginx... (5k+ stars)

enter image description here

簡介

俄羅斯人民開發的一款NGINX的流媒體插件,除了直播發布音視頻流以外具有流媒體服務器的常見功能:

  • RTMP在線直播。

  • 基於HTTP的FLV/MP4 VOD點播。

  • HLS (HTTP Live Streaming) M3U8的支持。

  • 基於http的操做(發佈、播放、錄製)。

  • 能夠很好的協同現有的流媒體服務器以及播放器一塊兒工做。

  • 在線調用ffmpeg對流媒體進行轉碼。

  • H264/AAC音視頻編碼格式的支持。

  • linux/BSD/MAC系統的支持。

官方承諾的功能:

  • RTMP/HLS/MPEG-DASH live streaming

  • RTMP Video on demand FLV/MP4, playing from local filesystem or HTTP

  • Stream relay support for distributed streaming: push & pull models

  • Recording streams in multiple FLVs

  • H264/AAC support

  • Online transcoding with FFmpeg

  • HTTP callbacks (publish/play/record/update etc)

  • Running external programs on certain events (exec)

  • HTTP control module for recording audio/video and dropping clients

  • Advanced buffering techniques to keep memory allocations at a minimum level for faster streaming and low memory footprint

  • Proved to work with Wirecast, FMS, Wowza, JWPlayer, FlowPlayer, StrobeMediaPlayback, ffmpeg, avconv, rtmpdump, flvstreamer and many more

  • Statistics in XML/XSL in machine- & human- readable form

  • Linux/FreeBSD/MacOS/Windows

經常使用指令與語法

  • Core

rtmp

語法:rtmp { ... }

上下文:nginx根上下文
描述:保存全部 RTMP 配置的塊

server

語法:server { ... }

上下文:rtmp
描述:聲明一個 RTMP 實例。
rtmp {
server {
}
}

listen

語法:listen (addr[:port]|port|unix:path)

上下文:server
描述:給 NGINX 添加一個監聽端口以接收 RTMP 鏈接。
server {

listen 1935;

}

application

語法:application name { ... }
上下文:server

描述:建立一個 RTMP 應用,application 名不支撐正則表達式。
server {

listen 1935;
application myapp {
}

}

timeout

語法:timeout value
上下文:rtmp, server

描述:Socket 超時。這個值主要用於寫數據時。
timeout 60s;

ping

語法:ping value

上下文:rtmp, server
描述:RTMP ping 間隔。零值的話將 ping 關掉。RTMP ping 是一個用於檢查活動鏈接的協議功能。發送一個特殊的包到遠程鏈接,而後在 ping_timeout 指令指定的時間內期待一個回覆。若是在這個時間裏沒有收到 ping 回覆,鏈接斷開。ping 默認值爲一分鐘。ping_timeout 默認值爲 30 秒。
ping 3m;
ping_timeout 30s;

  • Access

allow

語法:allow [play|publish] address|subnet|all

上下文:rtmp, server, application
容許來自指定地址或者全部地址發佈/播放。allow 和 deny 指令的前後順序可選。
allow publish 127.0.0.1;
deny publish all;
allow play 192.168.0.0/24;
deny play all;

deny

語法:deny [play|publish] address|subnet|all

上下文:rtmp, server, application
描述:參考 allow 的描述。

  • Exec

exec_push

語法:exec_push command arg*

上下文:rtmp, server, application
描述:定義每一個流發佈時要執行的帶有參數的外部命令。發佈結束時進程終止。第一個參數是二進制可執行文件的完整路徑。執行外部命令時可使用參數替換:
$name - 流的名字。
$app - 應用名。
$addr - 客戶端地址。
$flashver - 客戶端 flash 版本。
$swfurl - 客戶端 swf url。
$tcurl - 客戶端 tc url。
$pageurl - 客戶端頁面 url。也能夠在 exec 指令中定義 Shell 格式的轉向符用於寫輸出和接收輸入。

exec_pull

與exec_push相似,主要工做在play端。

  • Live

live

語法:live on|off

上下文:rtmp, server, application
描述:切換直播模式,即一對多廣播。
live on;

meta

語法:meta on|off

上下文:rtmp, server, application
描述:切換髮送元數據到客戶端。默認爲 on。
meta off;

interleave

語法:interleave on|off

上下文:rtmp, server, application
描述:切換交叉模式。在這個模式下,音頻和視頻數據會在同一個 RTMP chunk 流中傳輸。默認爲 off。
interleave on;

wait_key

語法:wait_key on|off

上下文:rtmp, server, application
描述:使視頻流從一個關鍵幀開始。默認爲 off。
wait_key on;

wait_video

語法:wait_video on|off

上下文:rtmp, server, application
描述:在第一個視頻幀發送以前禁用音頻。默認爲 off。能夠和 wait_key 進行組合以使客戶端能夠收到具備全部其餘數據的視頻關鍵幀。然而這一般增長鏈接延遲。您能夠經過在編碼器中調整關鍵幀間隔來減小延遲。
wait_video on;

publish_notify

語法:publish_notify on|off

上下文:rtmp, server, application
描述:發送 NetStream.Publish.Start 和 NetStream.Publish.Stop 給用戶。默認爲 off。
publish_notify on;

drop_idle_publisher

語法:drop_idle_publisher timeout

上下文:rtmp, server, application
描述:終止指定時間內閒置(沒有音頻/視頻數據)的發佈鏈接。默認爲 off。注意這個僅僅對於發佈模式的鏈接起做用(發送 publish 命令以後)。
drop_idle_publisher 10s;

sync

語法:sync timeout

上下文:rtmp, server, application
描述:同步音頻和視頻流。若是用戶帶寬不足以接收發布率,服務器會丟棄一些幀。這將致使同步問題。當時間戳差超過 sync 指定的值,將會發送一個絕對幀來解決這個問題。默認爲 300 ms。
sync 10ms;

play_restart

語法:play_restart on|off

上下文:rtmp, server, application
描述:使 nginx-rtmp 可以在發佈啓動或中止時發送 NetStream.Play.Start 和 NetStream.Play.Stop 到每一個用戶。若是關閉的話,那麼每一個用戶就只能在回放的開始和結束時收到這些通知了。默認爲 on。
play_restart off;

  • Record

record

語法:record [off|all|audio|video|keyframes|manual]*

上下文:rtmp, server, application, recorder
描述:切換錄製模式。流能夠被記錄到 flv 文件。本指令指定應該被記錄的:
off - 什麼也不錄製
all - 音頻和視頻(全部)
audio - 音頻
video - 視頻
keyframes - 只錄制關鍵視頻幀
manual - 用不自動啓動錄製,使用控制接口來啓動/中止
在單個記錄指令中能夠有任何兼容的組合鍵。
record all;

record_path

語法:record_path path

上下文:rtmp, server, application, recorder
描述:指定錄製的 flv 文件存放目錄。
record_path /tmp/rec;

record_suffix

語法:record_suffix value

上下文:rtmp, server, application, recorder
描述:設置錄製文件後綴名。默認爲 '.flv'。
record_suffix _recorded.flv;
錄製後綴能夠匹配 strftime 格式。如下指令
record_suffix -%d-%b-%y-%T.flv
將會產生形如 mystream-24-Apr-13-18:23:38.flv 的文件。全部支持 strftime 格式的選項能夠在 strftime man page 裏進行查找

record_append

語法:record_append on|off

上下文:rtmp, server, application, recorder
描述:切換文件附加模式。當這一指令爲開啓是,錄製時將把新數據附加到老文件,若是老文件丟失的話將從新建立一個。文件中的老數據和新數據沒有時間差。默認爲 off。
record_append on;

  • Relay

pull

語法:pull url [key=value]*

上下文:application
描述:建立 pull 中繼。流將從遠程服務器上拉下來,成爲本地可用的。僅當至少有一個播放器正在播放本地流時發生。
Url 語法:[rtmp://]host:port]。若是 application 找不着那麼將會使用本地 application 名。若是找不着 playpath 那麼就是用當前流的名字。
支持如下參數:
app:明確 application 名。
name:捆綁到 relay 的本地流名字。若是爲空或者沒有定義,那麼將會使用 application 中的全部本地流。
tcUrl:若是爲空的話自動構建。
pageUrl:模擬頁面 url。
swfUrl:模擬 swf url。
flashVer:模擬 flash 版本,默認爲 'LNX.11,1,102,55'。
playPath:遠程播放地址。
live:切換直播特殊行爲,值:0,1。
start:開始時間。
stop:結束時間。
static:建立靜態 pull,這樣的 pull 在 nginx 啓動時建立。
若是某參數的值包含空格,那麼你應該在整個 key=value 對周圍使用引號,好比:'pageUrl=FAKE PAGE URL'。
pullrtmp://cdn2.example.com/another/a?b=1&c=d pageUrl=http://www.example.com/video.html swfUrl=http://www.example.com/player.swf live=1;

push

語法:push url [key=value]*

上下文:application
描述:push 的語法和 pull 同樣。不一樣於 pull 指令的是 push 推送發佈流到遠程服務器。

push_reconnect

語法:push_reconnect time

上下文:rtmp, server, application
描述:在斷開鏈接後,在 push 從新鏈接前等待的時間。默認爲 3 秒。
push_reconnect 1s;

session_relay

語法:session_relay on|off

上下文:rtmp, server, application
描述:切換會話 relay 模式。在這種模式下鏈接關閉時 relay 銷燬。當設置爲 off 時,流關閉,relay 銷燬,這樣子之後另外一個 relay 能夠被建立。默認爲 off。
session_relay on;

  • Notify

on_connect

語法:on_connect url

上下文:rtmp, server
描述:設置 HTTP 鏈接回調。當客戶分發鏈接命令一個鏈接命令時,一個 HTTP 請求異步發送,命令處理將被暫停,直到它返回結果代碼。當 HTTP 2XX 碼(成功狀態碼)返回時,RTMP 會話繼續。返回碼 3XX (重定向狀態碼)會使 RTMP 重定向到另外一個從 HTTP 返回頭裏獲取到的 application。不然(其餘狀態碼)鏈接丟棄。
注意這一指令在 application 域是不容許的,由於 application 在鏈接階段仍是未知的。
HTTP 請求接收到一些參數。在 application/x-www-form-urlencoded MIME 類型下使用 POST 方法。如下參數將被傳給調用者:
call=connect。
addr - 客戶端 IP 地址。
app - application 名。
flashVer - 客戶端 flash 版本。
swfUrl - 客戶端 swf url。
tcUrl - tcUrl。
pageUrl - 客戶端頁面 url。
除了上述參數之外,全部顯式傳遞給鏈接命令的參數也由回調發送。你應該將鏈接參數和 play/publish 參數區分開。播放器經常有獨特的方式設置鏈接字符串不一樣於 play/publish 流名字。

on_play

語法:on_play url

上下文:rtmp, server, application
描述:設置 HTTP 播放回調。每次一個客戶分發播放命令時,一個 HTTP 請求異步發送,命令處理會掛起 - 直到它返回結果碼。以後再解析 HTTP 結果碼。
HTTP 2XX 返回碼的話繼續 RTMP 會話。
HTTP 3XX 返回碼的話 重定向 RTMP 到另外一個流,這個流的名字在 HTTP 返回頭的 Location 獲取。
HTTP 請求接收到一些個參數。在 application/x-www-form-urlencoded MIME 類型下使用 POST 方法。如下參數會被傳送給調用者:
call=play。
addr - 客戶端 IP 地址。
app - application 名。
flashVer - 客戶端 flash 版本。
swfUrl - 客戶端 swf url。
tcUrl - tcUrl。
pageUrl - 客戶端頁面 url。
name - 流名。

on_publish

語法:on_publish url
上下文:rtmp, server, application

描述:同上面提到的 on_play 同樣,惟一的不一樣點在於這個指令在發佈命令設置回調。不一樣於遠程 pull,push 在這裏是能夠的。

on_done

語法:on_done url

上下文:rtmp, server, application
描述:設置播放/發佈禁止回調。上述全部適用於此。但這個回調並不檢查 HTTP 狀態碼。

on_play_done

語法:on_publish_done url

上下文:rtmp, server, application
描述:等同於 on_done 的表現,但只適用於播放結束事件。

on_publish_done

語法:on_publish_done url

上下文:rtmp, server, application
描述:等同於 on_done 的表現,但只適用於發佈結束事件。

on_record_done

語法:on_record_done url

上下文:rtmp, server, application, recorder
描述:設置 record_done 回調。除了普通 HTTP 回調參數它接受錄製文件路徑。
on_record_done http://example.com/recorded;

on_update

語法:on_update url

上下文:rtmp, server, application
描述:設置 update 回調。這個回調會在 notify_update_timeout 期間調用。若是一個請求返回結果不是 2XX,鏈接禁止。這能夠用來同步過時的會話。追加 time 參數即播放/發佈調用後的秒數會被髮送給處理程序。
on_update http://example.com/update;

notify_update_timeout

語法:notify_update_timeout timeout

上下文:rtmp, server, application
描述:在 on_update 回調之間的超時設置。默認爲 30 秒。
notify_update_timeout 10s;
on_update http://example.com/update;

notify_update_strict

語法:notify_update_strict on|off

上下文:rtmp, server, application
描述:切換 on_update 回調嚴格模式。默認爲 off。當設置爲 on 時,全部鏈接錯誤,超時以及 HTTP 解析錯誤和空返回會被視爲更新失敗並致使鏈接終止。當設置爲 off 時只有 HTTP 返回碼不一樣於 2XX 時致使失敗。
notify_update_strict on;
on_update http://example.com/update;

notify_relay_redirect

語法:notify_relay_redirect on|off

上下文:rtmp, server, application
描述:使本地流能夠重定向爲 on_play 和 on_publish 遠程重定向。新的流名字是 RTMP URL 用於遠程重定向。默認爲 off。
notify_relay_redirect on;

notify_method

語法:notify_method get|post

上下文:rtmp, server, application, recorder
描述:設置 HTTP 方法通知。默認是帶有 application/x-www-form-urlencoded 的 POST 內容類型。在一些狀況下 GET 更好,例如若是你打算在 nginx 的 http{} 部分處理調用。在這種狀況下你可使用 arg_* 變量去訪問參數。
notify_method get;
Statistics
statistics 模塊不一樣於本文列舉的其餘模塊,它是 NGINX HTTP 模塊。所以 statistics 指令應該位於 http{} 塊內部。

rtmp_stat

語法:rtmp_stat all

上下文:http, server, location
描述:爲當前 HTTP location 設置 RTMP statistics 處理程序。RTMP statistics 是一個靜態的 XML 文檔。可使用 rtmp_stat_stylesheet 指令在瀏覽器中做爲 XHTML 頁面查看這個文檔。

http {
server {
    location /stat {
        rtmp_stat all;
        rtmp_stat_stylesheet stat.xsl;
    }
    location /stat.xsl {
        root /path/to/stat/xsl/file;
    }
}

}

rtmp_stat_stylesheet

語法:rtmp_stat_stylesheet path
上下文:http, server, location

描述:添加 XML 樣式表引用到 statistics XML 使其能夠在瀏覽器中可視。

測試

我所在的公司的直播業務中,前期也是採用red5,可是隨着用戶數的不斷增加,red5徹底不能支撐整個業務。問題集中爆發在幾個方面:

  • 對於單主播,聽者超過400人時,CPU超過90%(主機爲4核,32G)。

  • 人數越多,音質,畫面卡頓不少,不穩定,用戶體驗不好。因而咱們決定對red5進行替換,對各類選型進行了調研,並在red5相同環境下作了測試,發現nginx-rtmp的性能很是突出,最終選用nginx-rtmp替換Red5,到目前爲止,已經無端障運行近一年。附nginx-rtmp測試數據:

Server CPU 內存 鏈接數 帶寬 延遲
nginx-rtmp 8.3% 13MB 500 100Mbps 0.8秒
nginx-rtmp 27.3% 19MB 1000 200Mbps 0.8秒
nginx-rtmp 50.2% 37MB 2500 500Mbps 0.8秒
nginx-rtmp 70.2% 61MB 4000 650Mbps 0.8秒

從測試結果能夠得知,nginx-rtmp模塊運行穩定,單CPU4000人時負載只有70%,已經接近網卡流量的極限,比Red5 在性能上高一個數量級。

快速實現一個直播平臺

實戰前準備

  • 硬件

阿里雲ECS: CPU:2核心,內存:8G,硬盤:40G

enter image description here

  • 操做系統

CentOS 7.2 x86_64 Linux

  • 配置服務器

超過1024的鏈接數測試須要打開linux的限制。且必須以root登陸和執行

設置鏈接數:ulimit -HSn 10240

查看鏈接數:

enter image description here

  • 域名

非必須,如沒有,能夠直接使用ip也能夠。可是正式環境中爲了減小收聽端對ip地址的依賴性,通常會使用域名而非ip地址來鏈接直播服務器。本文使用域名爲datahq.cn.

申請域名:國內能夠選擇萬網或新網;國外的name.com和godaddy.com口碑不錯。

域名備案:國外的服務器和網站在上線前都須要通過工信部備案和公安部備案;若是在阿里雲上購買ECS能夠直接使用其的免費備案服務。

創建直播子域名:

enter image description here

  • 客戶端

爲方便測試,本文使用Red5 做爲直播的客戶端

  • 直播端

目前最好用的直播端軟件是OBS(Open Broadcaster Software)。下載地址是:

https://obsproject.com/download

快速設置:

視頻的清晰度與碼率和品質有關,碼率大,品質高,那麼視頻的清晰度就高,同時,對帶寬的要求也越大。詳細的參數設定參考以下:

  • 在來源中新增「視頻捕捉設備」,並設置分辨率,您能夠從分辨率選擇最接近的一項。本例分辨率爲1280x720,以下圖所示

enter image description here

  • 經過「設置」->「視頻」中設置壓縮分辨率,您能夠從壓縮分辨率選擇與本身指望最接近的一項。本例指望分辨率爲960x540,以下圖所示

enter image description here

  • 直播推流設置,打開「設置」->"流",URL輸入推流地址的URL,流名稱輸入推流的名稱,以下圖所示

enter image description here

實戰

  • 架構方案

目前,咱們線上的直播架構爲:

enter image description here

  • 支撐線上峯值近10萬人,並沒有故障運行一年有餘。

  • 配置中心會按期刷新直播端與收聽端APP的路由信息。

  • 直播端APP推流到Master集羣。

  • 因爲nginx-rtmp自己不支持集羣,所以咱們在架構時沒有采用從Master集羣Forward推流到Slave集羣的方式,而是設計了當收聽端拉流到slave服務器集羣時,若是不存在該流,就會從Master集羣主動拉取流的架構,解決了直播集羣的大規模併發問題。

  • 該架構在大規模併發狀況下,比Master推流到Slave流的架構節省了很大的帶寬。

  • 除此以外咱們對nginx-rtmp進行了源代碼的修改,支撐了一些如合成,轉碼,高級錄製等功能。

本文爲了各位同窗可以更快的掌握如何搭建的過程,所以沒有采用以上的架構,相信經過下面的實踐,各位也可以搭建相應的架構。

enter image description here

架構圖中黃色標識了咱們要使用的直播server。

  • 編譯與部署

建立源碼存儲目錄:mkdir -p /root/rtmp/src

進入源碼目錄:

cd /root/rtmp/src

下載nginx源碼並解壓,注意nginx-rtmp對nginx版本的選擇限制較多,在選擇時爲了少踩不須要的坑,建議根據官方提示選擇對應的nginx 版本,如圖本文選擇nginx-1.11.5:

enter image description here

wget http://nginx.org/download/ngi...
tar -zxvf nginx-1.11.5.tar.gz

下載nginx-rtmp模塊源碼:

wget https://github.com/arut/nginx...
tar -zxvf v1.1.10.tar.gz

編譯nginx,若是須要調試消息則打開--with-debug:

./configure --add-module=/root/rtmp/src/nginx-rtmp-module-1.1.10 --with-debug

make
make install

enter image description here

默認編譯到路徑:

/usr/local/nginx

驗證編譯是否成功:

enter image description here

建立錄製文件存儲目錄:

mkdir -p /usr/local/nginx/files

rtmp 模塊配置(nginx.conf):

enter image description here

本文所採用的配置以下

user  root;//使用root用戶運行nginx
worker_processes  1;//指明瞭nginx要開啓的進程數,通常等於cpu的總核數,若是沒有出現io性能問題,最好不要修改

error_log  logs/error.log  debug;//錯誤日誌存放路徑;日誌級別爲debug,調試用。
events {
    worker_connections  1024;//每一個工做進程的最大鏈接數量;
}


http {
    include       mime.types;//設定mime類型,類型由mime.type文件定義
    default_type  application/octet-stream;
    client_max_body_size 3m;//設定經過nginx上傳文件的大小
    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;//指定 nginx 是否調用sendfile 函數(zero copy 方式)來輸出文件
    keepalive_timeout  65;//keepalive超時時間
    server {//配置虛擬機
        listen       8080;//監聽端口
        server_name  rtmp.datahq.cn 59.110.237.245;//名稱
    location /stat{//配置統計頁面路徑
            rtmp_stat all;
            rtmp_stat_stylesheet stat.xsl;
        }
    location /stat.xsl{//統計模板路徑
            root /usr/local/nginx/conf;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}
rtmp{
    server{
        listen 0.0.0.0:1935;//監聽端口
        ping 30s;//活動鏈接檢查週期
        application live{//應用名
        live on;//打開直播模式
        meta copy; //是否發送直播端元數據信息
        session_relay on;//打開會話轉發模式
        drop_idle_publisher 10s;//10s沒有推流,自動斷開直播端
        sync 10ms;//同步流時間閥值
        record_append on;//打開直播流錄製追加模式
        record_path /usr/local/nginx/files;//錄製文件地址
        record all;//打開錄製功能
        }
    }
}

拷貝統計模板到ngin配置目錄:

cp /root/rtmp/src/nginx-rtmp-module-1.1.10/stat.xsl /usr/local/nginx/conf/

啓動直播服務器:

cd /usr/local/nginx/sbin && ./nginx

打開統計頁面控制檯:

http://rtmp.datahq.cn:8080/stat

enter image description here

統計表各屬性說明爲:
clients:鏈接數
live streams:流名
codec:編碼
bits:分辨率
size:視頻畫面大小
fps:每秒傳輸幀數
freq:音頻率
chan:音頻聲道
State:流狀態
Time:流活動時間

其它4個爲輸入與輸出流的每秒傳輸速率。

  • 測試直播

打開OBS,推流至rtmp://rtmp.datahq.cn/live,流名爲demo

打開red5,從rtmp://rtmp.datahq.cn/live拉取直播流,流名爲demo

enter image description here
打開直播統計後臺:若是看到已經有一個推流,一個拉流,並有數據傳輸時,說明整個直播鏈路已經暢通。

enter image description here

查看直播錄製文件:

enter image description here

此時看下系統的負載:能夠發現CPU,內存的負載都很低,能夠忽略不計。

enter image description here

  • 上線

到本節爲止,一個簡單的直播平臺就搭建好了,接下來咱們要作的就是上線,由於沒有上線,一切都是零。下面是咱們在上線過程當中遇到的一些坑,供各位同窗參考:

  • 系統打開文件數默認過低,形成部分用戶鏈接不上。

  • 遇到活動高峯,網絡帶寬成爲瓶頸,形成收聽用戶卡頓不少。在生產環境中須要時刻關注是否升級帶寬。

  • 上線儘可能選擇在沒有直播的時候進行。

總結

今天給你們分享了直播平臺搭建的一些知識,涉及到了rtmp協議,直播選型的一些注意點,大規模直播架構,nginx-rtmp直播服務器實戰搭建等。若是各位有直播的須要,能夠順着本文的一些知識點進行實戰。

第一次寫Chat,不知道效果如何,若是你們有興趣,咱們在後續推出nginx模塊開發與nginx-rtmp的分享,感謝你們的參與。


實錄:《七月:從零搭建高性能直播平臺實戰解析》

圖片描述

相關文章
相關標籤/搜索