如何從零開始搭建高性能直播平臺(tái)

前言

現(xiàn)在直播已經(jīng)成為移動(dòng)互聯(lián)網(wǎng)時(shí)代一個(gè)新的重要流量入口,從YY、斗魚到花椒直播,直播已經(jīng)成為人們分享交流的新方式,應(yīng)用場(chǎng)景眾多,主要分為:

  • 金融類直播:金融直播可應(yīng)用于實(shí)時(shí)解盤,在線專家講座,專家在線直播技術(shù)分析、指導(dǎo)投資者等使用場(chǎng)景。

  • 大型賽事,演唱會(huì)類直播:可應(yīng)用于大型演唱會(huì),音樂(lè)會(huì),游戲,體育賽事等類直播場(chǎng)景。

  • 互動(dòng)類直播:娛樂(lè)類互動(dòng),如YY等。

  • 會(huì)議類直播:大型會(huì)議直播。

等4大類。在本文中,我將先從rtmp協(xié)議開始,一步步帶領(lǐng)大家搭建一個(gè)簡(jiǎn)易高性能的直播平臺(tái)。

RTMP協(xié)議詳解

RTMP協(xié)議Real Time Message Protocol(實(shí)時(shí)信息傳輸協(xié)議)的首字母縮寫,是由Adobe公司開發(fā)的一種用于解決多媒體數(shù)據(jù)傳輸流多路復(fù)用和分包的網(wǎng)絡(luò)協(xié)議。它工作在TCP協(xié)議之上,因此是一種提供可靠交付的協(xié)議,在傳輸時(shí)不會(huì)出現(xiàn)丟包情況,從而保證了用戶體驗(yàn)(QoE)。雖然TCP協(xié)議為了提供可靠交付付出了一些額外的開銷做為代價(jià),占用了一些帶寬和處理器資源,但是隨著網(wǎng)絡(luò)帶寬的提高和硬件的發(fā)展,這些開銷會(huì)顯得越來(lái)越微不足道。因此RTMP協(xié)議在為了有很好的發(fā)展前景。

官方定義:

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.

協(xié)議分類

  • RTMP協(xié)議工作在TCP之上,是應(yīng)用層協(xié)議, 默認(rèn)的端口是1935。

  • RTMPE在RTMP的基礎(chǔ)上增加了加密功能。

  • RTMPT工作在HTTP之上,默認(rèn)端口是80或443,可穿透防火墻。

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

  • RTMFP為RTMP協(xié)議的UDP版本。

雖然協(xié)議變種有很多,但實(shí)際在我們的直播應(yīng)用中最常見的是原生的RTMP協(xié)議,因此本篇文章以該協(xié)議的1.0版本為基礎(chǔ),對(duì)其它演進(jìn)協(xié)議感興趣的同學(xué)可以關(guān)注本文的后續(xù)知識(shí)。

交互流程

RTMP的交互流程可以分為握手過(guò)程、控制命令傳輸與數(shù)據(jù)傳輸。

enter image description here
  • 握手過(guò)程

RTMP 連接以握手開始,RTMP 握手由三個(gè)固定長(zhǎng)度的塊組成??蛻舳?(發(fā)起連接請(qǐng)求的終端) 和服務(wù)器端各自發(fā)送相同的三塊。便于演示,本文將從客戶端發(fā)送的這些塊指定為 C0、C1 和 C2;將從服務(wù)器端發(fā)送的這些塊分別指定為 S0、S1 和 S2。

RTMP握手以客戶端發(fā)送 C0 和 C1 塊開始,客戶端要等收到S1之后才能發(fā)送C2,客戶端要等收到S2之后才能發(fā)送其他信息(控制信息和真實(shí)音視頻等數(shù)據(jù)),服務(wù)端要等到收到C0之后發(fā)送S1, 服務(wù)端必須等到收到C1之后才能發(fā)送S2, 服務(wù)端必須等到收到C2之后才能發(fā)送其他信息(控制信息和真實(shí)音視頻等數(shù)據(jù))。以下為RTMP握手的時(shí)序圖介紹。

enter image description here

流程圖中所提到的各種狀態(tài)如下:

狀態(tài) 描述
未初始化 客戶端在C0中發(fā)送協(xié)議版本,如服務(wù)端支持,則回發(fā)送S0和S1,如果不能,則連接結(jié)束
版本發(fā)送 客戶端等待S1包,服務(wù)端等待C1包,當(dāng)接收到想要的包,客戶端發(fā)送C2,服務(wù)端發(fā)送S2,此時(shí)階段變成了ACK的發(fā)送
ACK發(fā)送 客戶端和服務(wù)端分別等待S2和C2
握手完成 客戶端和服務(wù)交換消息

理論上來(lái)講只要滿足以上條件,如何安排6個(gè)Message的順序都是可以的。但在實(shí)際實(shí)現(xiàn)中為了盡量減少通信的次數(shù),客戶端發(fā)送C0+C1,服務(wù)端發(fā)送S0+S1+S2,再客戶端在發(fā)送C2結(jié)束握手。

enter image description here
  • 控制命令傳輸

    握手結(jié)束以后,RTMP協(xié)議進(jìn)入控制命令傳輸過(guò)程,客戶端通過(guò)發(fā)送connnect命令與服務(wù)器實(shí)現(xiàn)雙向連接。連接成功后,通過(guò)發(fā)送createStream命令建立網(wǎng)絡(luò)流。

  • 數(shù)據(jù)傳輸

網(wǎng)絡(luò)流建立成功后,推流(將直播內(nèi)容推送至服務(wù)器的過(guò)程)過(guò)程會(huì)發(fā)送publish命令發(fā)布音視頻內(nèi)容,拉流(服務(wù)器已有直播內(nèi)容,用指定地址進(jìn)行拉取的過(guò)程)過(guò)程會(huì)發(fā)送play命令播放內(nèi)容。

協(xié)議格式

URI格式

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

  • {app}為音頻/視頻和其他內(nèi)容定義的一個(gè)容器。
  • {stream_name}為具體的一個(gè)流名稱。

消息(Message)格式

enter image description here

消息是RTMP協(xié)議中基本的數(shù)據(jù)單元,不能種類的消息包含有不能的消息類型(Message Type)。RTMP協(xié)議一共規(guī)范了十多種消息類型。其中類型為8,9的消息分別用于傳輸音頻和視頻數(shù)據(jù)。消息頭包含以下信息:

  • Message Type: 消息類型,占用1個(gè)字節(jié)。

  • Length: 有效負(fù)載的字節(jié)數(shù),占用3個(gè)字節(jié)。該字段是用大字節(jié)序表示的。

  • Timestamp: 時(shí)間戳,占用4個(gè)字節(jié),用大字節(jié)序表示。

  • Message Stream Id: 消息流ID,標(biāo)識(shí)消息所使用的流,用大字節(jié)序表示。

消息塊格式

在網(wǎng)絡(luò)上傳輸數(shù)據(jù)時(shí),消息需要被拆分成較小的數(shù)據(jù)塊才適合在相應(yīng)的網(wǎng)絡(luò)環(huán)境上傳輸。RTMP協(xié)議中規(guī)范了對(duì)消息拆分成消息塊,每個(gè)消息塊首部(ChunkHeader)有三部分組成:用于標(biāo)識(shí)本塊的ChunkBasicHeader,用于標(biāo)識(shí)本塊負(fù)載所屬消息的ChunkMessageHeader,以及當(dāng)時(shí)間戳溢出時(shí)才出現(xiàn)的ExtendedTimestamp。

消息分塊

RTMP傳輸媒體數(shù)據(jù)的過(guò)程中,發(fā)送端首先把媒體數(shù)據(jù)封裝成消息,然后把消息分割成消息塊,最后將分割后的消息塊通過(guò)TCP協(xié)議發(fā)送出去。接收端在通過(guò)TCP協(xié)議收到數(shù)據(jù)后,首先把消息塊重新組合成消息,然后通過(guò)對(duì)消息進(jìn)行解封裝處理就可以恢復(fù)出媒體數(shù)據(jù)。

開源技術(shù)選型

目前直播服務(wù)器有開源和商業(yè)兩種版本,商業(yè)版本主要又FMS(Flash Media Server)與Wowza。本文章僅針對(duì)開源版本做介紹,相應(yīng)的開源項(xiàng)目主要分為Red5與 Nginx-Rtmp兩類:

Red5

簡(jiǎn)介

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

enter image description here

Red5是一個(gè)采用Java開發(fā)開源的Flash流媒體服務(wù)器。它支持:把音頻(MP3)和視頻(FLV)轉(zhuǎn)換成播放流; 錄制客戶端播放流(只支持FLV);共享對(duì)象;現(xiàn)場(chǎng)直播流發(fā)布;遠(yuǎn)程調(diào)用。Red5使用RTMP, RTMPT, RTMPS, 和RTMPE作為流媒體傳輸協(xié)議,在其自帶的一些示例中演示了在線錄制,flash流媒體播放,在線聊天,視頻會(huì)議等一些基本功能。

官方給出的主要特性:
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

安裝與簡(jiǎn)單應(yīng)用實(shí)例(Mac下安裝)

前置條件(jdk已安裝)。

enter image description here
  • 創(chuàng)建安裝目錄:

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

  • 設(shè)置主目錄環(huán)境變量:

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

  • 下載red5應(yīng)用,并解壓到RED5_HOME:

https://github.com/Red5/red5-server/releases/download/v1.0.7-RELEASE/red5-server-1.0.7-RELEASE.tar.gz

enter image description here

目錄簡(jiǎn)介:由于 Red5 是在 Tomcat 中運(yùn)行的,因此 Red5 項(xiàng)目與普通 JAVAEE 項(xiàng)目結(jié)構(gòu)類似
conf:red5配置目錄
lib:存放的是一些依賴jar包
weapps:用來(lái)存放應(yīng)用程序,與tomcat下的webapps目錄作用類似。

  • 運(yùn)行:

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

  • 簡(jiǎn)單實(shí)例

經(jīng)過(guò)前面的介紹,這里將用red5介紹一個(gè)簡(jiǎn)單的實(shí)例。打開http://127.0.0.1:5080 出現(xiàn)red5 管理控制臺(tái)。

enter image description here

選擇"Publisher" demo,該項(xiàng)目提供了主播端與聽課端。

enter image description here

主播端:“1”中 Name表示流名,publish可以發(fā)布一個(gè)直播。

enter image description here

直播收聽端:“1”中Name為收聽的流名;“2”中 Location為直播端地址;“3”中Log可以觀察到整個(gè)直播的交流日志。

enter image description here
enter image description here
  • 停止應(yīng)用:

cd /Users/ypzdw/gitchat/rtmp/red5
./red5-shutdown.sh

Nginx-Rtmp

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

enter image description here

簡(jiǎn)介

俄羅斯人民開發(fā)的一款NGINX的流媒體插件,除了直播發(fā)布音視頻流之外具備流媒體服務(wù)器的常見功能:

  • RTMP在線直播。

  • 基于HTTP的FLV/MP4 VOD點(diǎn)播。

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

  • 基于http的操作(發(fā)布、播放、錄制)。

  • 可以很好的協(xié)同現(xiàn)有的流媒體服務(wù)器以及播放器一起工作。

  • 在線調(diào)用ffmpeg對(duì)流媒體進(jìn)行轉(zhuǎn)碼。

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

  • linux/BSD/MAC系統(tǒng)的支持。

官方承諾的功能:

  • 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

常用指令與語(yǔ)法

  • Core

rtmp

語(yǔ)法:rtmp { ... }
上下文:nginx根上下文
描述:保存所有 RTMP 配置的塊

server

語(yǔ)法:server { ... }
上下文:rtmp
描述:聲明一個(gè) RTMP 實(shí)例。
rtmp {
server {
}
}

listen

語(yǔ)法:listen (addr[:port]|port|unix:path)
上下文:server
描述:給 NGINX 添加一個(gè)監(jiān)聽端口以接收 RTMP 連接。
server {
listen 1935;
}

application

語(yǔ)法:application name { ... }

上下文:server
描述:創(chuàng)建一個(gè) RTMP 應(yīng)用,application 名不支撐正則表達(dá)式。
server {
listen 1935;
application myapp {
}
}

timeout

語(yǔ)法:timeout value
上下文:rtmp, server
描述:Socket 超時(shí)。這個(gè)值主要用于寫數(shù)據(jù)時(shí)。
timeout 60s;

ping

語(yǔ)法:ping value
上下文:rtmp, server
描述:RTMP ping 間隔。零值的話將 ping 關(guān)掉。RTMP ping 是一個(gè)用于檢查活動(dòng)連接的協(xié)議功能。發(fā)送一個(gè)特殊的包到遠(yuǎn)程連接,然后在 ping_timeout 指令指定的時(shí)間內(nèi)期待一個(gè)回復(fù)。如果在這個(gè)時(shí)間里沒(méi)有收到 ping 回復(fù),連接斷開。ping 默認(rèn)值為一分鐘。ping_timeout 默認(rèn)值為 30 秒。
ping 3m;
ping_timeout 30s;

  • Access

allow

語(yǔ)法:allow [play|publish] address|subnet|all
上下文:rtmp, server, application
允許來(lái)自指定地址或者所有地址發(fā)布/播放。allow 和 deny 指令的先后順序可選。
allow publish 127.0.0.1;
deny publish all;
allow play 192.168.0.0/24;
deny play all;

deny

語(yǔ)法:deny [play|publish] address|subnet|all
上下文:rtmp, server, application
描述:參考 allow 的描述。

  • Exec

exec_push

語(yǔ)法:exec_push command arg*
上下文:rtmp, server, application
描述:定義每個(gè)流發(fā)布時(shí)要執(zhí)行的帶有參數(shù)的外部命令。發(fā)布結(jié)束時(shí)進(jìn)程終止。第一個(gè)參數(shù)是二進(jìn)制可執(zhí)行文件的完整路徑。執(zhí)行外部命令時(shí)可以使用參數(shù)替換:
$name - 流的名字。
$app - 應(yīng)用名。
$addr - 客戶端地址。
$flashver - 客戶端 flash 版本。
$swfurl - 客戶端 swf url。
$tcurl - 客戶端 tc url。
$pageurl - 客戶端頁(yè)面 url。也可以在 exec 指令中定義 Shell 格式的轉(zhuǎn)向符用于寫輸出和接收輸入。

exec_pull

與exec_push類似,主要工作在play端。

  • Live

live

語(yǔ)法:live on|off
上下文:rtmp, server, application
描述:切換直播模式,即一對(duì)多廣播。
live on;

meta

語(yǔ)法:meta on|off
上下文:rtmp, server, application
描述:切換發(fā)送元數(shù)據(jù)到客戶端。默認(rèn)為 on。
meta off;

interleave

語(yǔ)法:interleave on|off
上下文:rtmp, server, application
描述:切換交叉模式。在這個(gè)模式下,音頻和視頻數(shù)據(jù)會(huì)在同一個(gè) RTMP chunk 流中傳輸。默認(rèn)為 off。
interleave on;

wait_key

語(yǔ)法:wait_key on|off
上下文:rtmp, server, application
描述:使視頻流從一個(gè)關(guān)鍵幀開始。默認(rèn)為 off。
wait_key on;

wait_video

語(yǔ)法:wait_video on|off
上下文:rtmp, server, application
描述:在第一個(gè)視頻幀發(fā)送之前禁用音頻。默認(rèn)為 off??梢院?wait_key 進(jìn)行組合以使客戶端可以收到具有所有其他數(shù)據(jù)的視頻關(guān)鍵幀。然而這通常增加連接延遲。您可以通過(guò)在編碼器中調(diào)整關(guān)鍵幀間隔來(lái)減少延遲。
wait_video on;

publish_notify

語(yǔ)法:publish_notify on|off
上下文:rtmp, server, application
描述:發(fā)送 NetStream.Publish.Start 和 NetStream.Publish.Stop 給用戶。默認(rèn)為 off。
publish_notify on;

drop_idle_publisher

語(yǔ)法:drop_idle_publisher timeout
上下文:rtmp, server, application
描述:終止指定時(shí)間內(nèi)閑置(沒(méi)有音頻/視頻數(shù)據(jù))的發(fā)布連接。默認(rèn)為 off。注意這個(gè)僅僅對(duì)于發(fā)布模式的連接起作用(發(fā)送 publish 命令之后)。
drop_idle_publisher 10s;

sync

語(yǔ)法:sync timeout
上下文:rtmp, server, application
描述:同步音頻和視頻流。如果用戶帶寬不足以接收發(fā)布率,服務(wù)器會(huì)丟棄一些幀。這將導(dǎo)致同步問(wèn)題。當(dāng)時(shí)間戳差超過(guò) sync 指定的值,將會(huì)發(fā)送一個(gè)絕對(duì)幀來(lái)解決這個(gè)問(wèn)題。默認(rèn)為 300 ms。
sync 10ms;

play_restart

語(yǔ)法:play_restart on|off
上下文:rtmp, server, application
描述:使 nginx-rtmp 能夠在發(fā)布啟動(dòng)或停止時(shí)發(fā)送 NetStream.Play.Start 和 NetStream.Play.Stop 到每個(gè)用戶。如果關(guān)閉的話,那么每個(gè)用戶就只能在回放的開始和結(jié)束時(shí)收到這些通知了。默認(rèn)為 on。
play_restart off;

  • Record

record

語(yǔ)法:record [off|all|audio|video|keyframes|manual]*
上下文:rtmp, server, application, recorder
描述:切換錄制模式。流可以被記錄到 flv 文件。本指令指定應(yīng)該被記錄的:
off - 什么也不錄制
all - 音頻和視頻(所有)
audio - 音頻
video - 視頻
keyframes - 只錄制關(guān)鍵視頻幀
manual - 用不自動(dòng)啟動(dòng)錄制,使用控制接口來(lái)啟動(dòng)/停止
在單個(gè)記錄指令中可以有任何兼容的組合鍵。
record all;

record_path

語(yǔ)法:record_path path
上下文:rtmp, server, application, recorder
描述:指定錄制的 flv 文件存放目錄。
record_path /tmp/rec;

record_suffix

語(yǔ)法:record_suffix value
上下文:rtmp, server, application, recorder
描述:設(shè)置錄制文件后綴名。默認(rèn)為 '.flv'。
record_suffix _recorded.flv;
錄制后綴可以匹配 strftime 格式。以下指令
record_suffix -%d-%b-%y-%T.flv
將會(huì)產(chǎn)生形如 mystream-24-Apr-13-18:23:38.flv 的文件。所有支持 strftime 格式的選項(xiàng)可以在 strftime man page 里進(jìn)行查找

record_append

語(yǔ)法:record_append on|off
上下文:rtmp, server, application, recorder
描述:切換文件附加模式。當(dāng)這一指令為開啟是,錄制時(shí)將把新數(shù)據(jù)附加到老文件,如果老文件丟失的話將重新創(chuàng)建一個(gè)。文件中的老數(shù)據(jù)和新數(shù)據(jù)沒(méi)有時(shí)間差。默認(rèn)為 off。
record_append on;

  • Relay

pull

語(yǔ)法:pull url [key=value]*
上下文:application
描述:創(chuàng)建 pull 中繼。流將從遠(yuǎn)程服務(wù)器上拉下來(lái),成為本地可用的。僅當(dāng)至少有一個(gè)播放器正在播放本地流時(shí)發(fā)生。
Url 語(yǔ)法:[rtmp://]host[:port][/app[/playpath]]。如果 application 找不著那么將會(huì)使用本地 application 名。如果找不著 playpath 那么就是用當(dāng)前流的名字。
支持以下參數(shù):
app:明確 application 名。
name:捆綁到 relay 的本地流名字。如果為空或者沒(méi)有定義,那么將會(huì)使用 application 中的所有本地流。
tcUrl:如果為空的話自動(dòng)構(gòu)建。
pageUrl:模擬頁(yè)面 url。
swfUrl:模擬 swf url。
flashVer:模擬 flash 版本,默認(rèn)為 'LNX.11,1,102,55'。
playPath:遠(yuǎn)程播放地址。
live:切換直播特殊行為,值:0,1。
start:開始時(shí)間。
stop:結(jié)束時(shí)間。

static:創(chuàng)建靜態(tài) pull,這樣的 pull 在 nginx 啟動(dòng)時(shí)創(chuàng)建。
如果某參數(shù)的值包含空格,那么你應(yīng)該在整個(gè) key=value 對(duì)周圍使用引號(hào),比如:'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

語(yǔ)法:push url [key=value]*
上下文:application
描述:push 的語(yǔ)法和 pull 一樣。不同于 pull 指令的是 push 推送發(fā)布流到遠(yuǎn)程服務(wù)器。

push_reconnect

語(yǔ)法:push_reconnect time
上下文:rtmp, server, application
描述:在斷開連接后,在 push 重新連接前等待的時(shí)間。默認(rèn)為 3 秒。
push_reconnect 1s;

session_relay

語(yǔ)法:session_relay on|off
上下文:rtmp, server, application
描述:切換會(huì)話 relay 模式。在這種模式下連接關(guān)閉時(shí) relay 銷毀。當(dāng)設(shè)置為 off 時(shí),流關(guān)閉,relay 銷毀,這樣子以后另一個(gè) relay 可以被創(chuàng)建。默認(rèn)為 off。
session_relay on;

  • Notify

on_connect

語(yǔ)法:on_connect url
上下文:rtmp, server
描述:設(shè)置 HTTP 連接回調(diào)。當(dāng)客戶分發(fā)連接命令一個(gè)連接命令時(shí),一個(gè) HTTP 請(qǐng)求異步發(fā)送,命令處理將被暫停,直到它返回結(jié)果代碼。當(dāng) HTTP 2XX 碼(成功狀態(tài)碼)返回時(shí),RTMP 會(huì)話繼續(xù)。返回碼 3XX (重定向狀態(tài)碼)會(huì)使 RTMP 重定向到另一個(gè)從 HTTP 返回頭里獲取到的 application。否則(其他狀態(tài)碼)連接丟棄。
注意這一指令在 application 域是不允許的,因?yàn)?application 在連接階段還是未知的。
HTTP 請(qǐng)求接收到一些參數(shù)。在 application/x-www-form-urlencoded MIME 類型下使用 POST 方法。以下參數(shù)將被傳給調(diào)用者:
call=connect。
addr - 客戶端 IP 地址。
app - application 名。
flashVer - 客戶端 flash 版本。
swfUrl - 客戶端 swf url。
tcUrl - tcUrl。
pageUrl - 客戶端頁(yè)面 url。
除了上述參數(shù)以外,所有顯式傳遞給連接命令的參數(shù)也由回調(diào)發(fā)送。你應(yīng)該將連接參數(shù)和 play/publish 參數(shù)區(qū)分開。播放器常常有獨(dú)特的方式設(shè)置連接字符串不同于 play/publish 流名字。

on_play

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

on_publish

語(yǔ)法:on_publish url
上下文:rtmp, server, application
描述:同上面提到的 on_play 一樣,唯一的不同點(diǎn)在于這個(gè)指令在發(fā)布命令設(shè)置回調(diào)。不同于遠(yuǎn)程 pull,push 在這里是可以的。

on_done

語(yǔ)法:on_done url
上下文:rtmp, server, application
描述:設(shè)置播放/發(fā)布禁止回調(diào)。上述所有適用于此。但這個(gè)回調(diào)并不檢查 HTTP 狀態(tài)碼。

on_play_done

語(yǔ)法:on_publish_done url
上下文:rtmp, server, application
描述:等同于 on_done 的表現(xiàn),但只適用于播放結(jié)束事件。

on_publish_done

語(yǔ)法:on_publish_done url
上下文:rtmp, server, application
描述:等同于 on_done 的表現(xiàn),但只適用于發(fā)布結(jié)束事件。

on_record_done

語(yǔ)法:on_record_done url
上下文:rtmp, server, application, recorder
描述:設(shè)置 record_done 回調(diào)。除了普通 HTTP 回調(diào)參數(shù)它接受錄制文件路徑。
on_record_done http://example.com/recorded;

on_update

語(yǔ)法:on_update url
上下文:rtmp, server, application
描述:設(shè)置 update 回調(diào)。這個(gè)回調(diào)會(huì)在 notify_update_timeout 期間調(diào)用。如果一個(gè)請(qǐng)求返回結(jié)果不是 2XX,連接禁止。這可以用來(lái)同步過(guò)期的會(huì)話。追加 time 參數(shù)即播放/發(fā)布調(diào)用后的秒數(shù)會(huì)被發(fā)送給處理程序。
on_update http://example.com/update;

notify_update_timeout

語(yǔ)法:notify_update_timeout timeout
上下文:rtmp, server, application
描述:在 on_update 回調(diào)之間的超時(shí)設(shè)置。默認(rèn)為 30 秒。
notify_update_timeout 10s;

on_update http://example.com/update;

notify_update_strict

語(yǔ)法:notify_update_strict on|off
上下文:rtmp, server, application
描述:切換 on_update 回調(diào)嚴(yán)格模式。默認(rèn)為 off。當(dāng)設(shè)置為 on 時(shí),所有連接錯(cuò)誤,超時(shí)以及 HTTP 解析錯(cuò)誤和空返回會(huì)被視為更新失敗并導(dǎo)致連接終止。當(dāng)設(shè)置為 off 時(shí)只有 HTTP 返回碼不同于 2XX 時(shí)導(dǎo)致失敗。
notify_update_strict on;
on_update http://example.com/update;

notify_relay_redirect

語(yǔ)法:notify_relay_redirect on|off
上下文:rtmp, server, application
描述:使本地流可以重定向?yàn)?on_play 和 on_publish 遠(yuǎn)程重定向。新的流名字是 RTMP URL 用于遠(yuǎn)程重定向。默認(rèn)為 off。
notify_relay_redirect on;

notify_method

語(yǔ)法:notify_method get|post
上下文:rtmp, server, application, recorder
描述:設(shè)置 HTTP 方法通知。默認(rèn)是帶有 application/x-www-form-urlencoded 的 POST 內(nèi)容類型。在一些情況下 GET 更好,例如如果你打算在 nginx 的 http{} 部分處理調(diào)用。在這種情況下你可以使用 arg_* 變量去訪問(wèn)參數(shù)。
notify_method get;
Statistics
statistics 模塊不同于本文列舉的其他模塊,它是 NGINX HTTP 模塊。因此 statistics 指令應(yīng)該位于 http{} 塊內(nèi)部。

rtmp_stat

語(yǔ)法:rtmp_stat all
上下文:http, server, location
描述:為當(dāng)前 HTTP location 設(shè)置 RTMP statistics 處理程序。RTMP statistics 是一個(gè)靜態(tài)的 XML 文檔??梢允褂?rtmp_stat_stylesheet 指令在瀏覽器中作為 XHTML 頁(yè)面查看這個(gè)文檔。
http {
server {
location /stat {
rtmp_stat all;
rtmp_stat_stylesheet stat.xsl;
}
location /stat.xsl {
root /path/to/stat/xsl/file;
}
}
}

rtmp_stat_stylesheet

語(yǔ)法:rtmp_stat_stylesheet path
上下文:http, server, location
描述:添加 XML 樣式表引用到 statistics XML 使其可以在瀏覽器中可視。

測(cè)試

我所在的公司的直播業(yè)務(wù)中,前期也是采用red5,但是隨著用戶數(shù)的不斷增長(zhǎng),red5完全不能支撐整個(gè)業(yè)務(wù)。問(wèn)題集中爆發(fā)在幾個(gè)方面:

  • 對(duì)于單主播,聽者超過(guò)400人時(shí),CPU超過(guò)90%(主機(jī)為4核,32G)。

  • 人數(shù)越多,音質(zhì),畫面卡頓很多,不穩(wěn)定,用戶體驗(yàn)很差。于是我們決定對(duì)red5進(jìn)行替換,對(duì)各種選型進(jìn)行了調(diào)研,并在red5相同環(huán)境下做了測(cè)試,發(fā)現(xiàn)nginx-rtmp的性能非常突出,最終選用nginx-rtmp替換Red5,到目前為止,已經(jīng)無(wú)故障運(yùn)行近一年。附nginx-rtmp測(cè)試數(shù)據(jù):

Server |CPU|內(nèi)存|連接數(shù)|帶寬|延遲
---|---
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秒

從測(cè)試結(jié)果可以得知,nginx-rtmp模塊運(yùn)行穩(wěn)定,單CPU4000人時(shí)負(fù)載只有70%,已經(jīng)接近網(wǎng)卡流量的極限,比Red5 在性能上高一個(gè)數(shù)量級(jí)。

快速實(shí)現(xiàn)一個(gè)直播平臺(tái)

實(shí)戰(zhàn)前準(zhǔn)備

  • 硬件

阿里云ECS: CPU:2核心,內(nèi)存:8G,硬盤:40G

enter image description here
  • 操作系統(tǒng)

CentOS 7.2 x86_64 Linux

  • 配置服務(wù)器

超過(guò)1024的連接數(shù)測(cè)試需要打開linux的限制。且必須以root登錄和執(zhí)行

設(shè)置連接數(shù):ulimit -HSn 10240

查看連接數(shù):

enter image description here
  • 域名

非必須,如沒(méi)有,可以直接使用ip也可以。但是正式環(huán)境中為了減少收聽端對(duì)ip地址的依賴性,一般會(huì)使用域名而非ip地址來(lái)連接直播服務(wù)器。本文使用域名為datahq.cn.

申請(qǐng)域名:國(guó)內(nèi)可以選擇萬(wàn)網(wǎng)或新網(wǎng);國(guó)外的name.com和godaddy.com口碑不錯(cuò)。

域名備案:國(guó)外的服務(wù)器和網(wǎng)站在上線前都需要經(jīng)過(guò)工信部備案和公安部備案;如果在阿里云上購(gòu)買ECS可以直接使用其的免費(fèi)備案服務(wù)。

建立直播子域名:

enter image description here
  • 客戶端

為方便測(cè)試,本文使用Red5 作為直播的客戶端

  • 直播端

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

https://obsproject.com/download

快速設(shè)置:

視頻的清晰度與碼率和品質(zhì)有關(guān),碼率大,品質(zhì)高,那么視頻的清晰度就高,同時(shí),對(duì)帶寬的要求也越大。詳細(xì)的參數(shù)設(shè)定參考如下:

  • 在來(lái)源中新增“視頻捕捉設(shè)備”,并設(shè)置分辨率,您可以從分辨率選擇最接近的一項(xiàng)。本例分辨率為1280x720,如下圖所示
enter image description here
  • 通過(guò)“設(shè)置”->“視頻”中設(shè)置壓縮分辨率,您可以從壓縮分辨率選擇與自己期望最接近的一項(xiàng)。本例期望分辨率為960x540,如下圖所示
enter image description here
  • 直播推流設(shè)置,打開“設(shè)置”->"流",URL輸入推流地址的URL,流名稱輸入推流的名稱,如下圖所示
enter image description here

實(shí)戰(zhàn)

  • 架構(gòu)方案

目前,我們線上的直播架構(gòu)為:

enter image description here
  • 支撐線上峰值近10萬(wàn)人,并無(wú)故障運(yùn)行一年有余。

  • 配置中心會(huì)定期刷新直播端與收聽端APP的路由信息。

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

  • 由于nginx-rtmp本身不支持集群,因此我們?cè)诩軜?gòu)時(shí)沒(méi)有采用從Master集群Forward推流到Slave集群的方式,而是設(shè)計(jì)了當(dāng)收聽端拉流到slave服務(wù)器集群時(shí),如果不存在該流,就會(huì)從Master集群主動(dòng)拉取流的架構(gòu),解決了直播集群的大規(guī)模并發(fā)問(wèn)題。

  • 該架構(gòu)在大規(guī)模并發(fā)情況下,比Master推流到Slave流的架構(gòu)節(jié)省了很大的帶寬。

  • 除此之外我們對(duì)nginx-rtmp進(jìn)行了源代碼的修改,支撐了一些如合成,轉(zhuǎn)碼,高級(jí)錄制等功能。

本文為了各位同學(xué)能夠更快的掌握如何搭建的過(guò)程,因此沒(méi)有采用以上的架構(gòu),相信通過(guò)下面的實(shí)踐,各位也能夠搭建相應(yīng)的架構(gòu)。

enter image description here

架構(gòu)圖中黃色標(biāo)識(shí)了我們要使用的直播server。

  • 編譯與部署

創(chuàng)建源碼存儲(chǔ)目錄:mkdir -p /root/rtmp/src

進(jìn)入源碼目錄:

cd /root/rtmp/src

下載nginx源碼并解壓,注意nginx-rtmp對(duì)nginx版本的選擇限制較多,在選擇時(shí)為了少踩不需要的坑,建議根據(jù)官方提示選擇對(duì)應(yīng)的nginx 版本,如圖本文選擇nginx-1.11.5:

enter image description here

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

下載nginx-rtmp模塊源碼:

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

編譯nginx,如果需要調(diào)試消息則打開--with-debug:

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

enter image description here

默認(rèn)編譯到路徑:

/usr/local/nginx

驗(yàn)證編譯是否成功:

enter image description here

創(chuàng)建錄制文件存儲(chǔ)目錄:

mkdir -p /usr/local/nginx/files

rtmp 模塊配置(nginx.conf):

enter image description here

本文所采用的配置如下

user  root;//使用root用戶運(yùn)行nginx
worker_processes  1;//指明了nginx要開啟的進(jìn)程數(shù),一般等于cpu的總核數(shù),如果沒(méi)有出現(xiàn)io性能問(wèn)題,最好不要修改

error_log  logs/error.log  debug;//錯(cuò)誤日志存放路徑;日志級(jí)別為debug,調(diào)試用。
events {
    worker_connections  1024;//每個(gè)工作進(jìn)程的最大連接數(shù)量;
}


http {
    include       mime.types;//設(shè)定mime類型,類型由mime.type文件定義
    default_type  application/octet-stream;
    client_max_body_size 3m;//設(shè)定通過(guò)nginx上傳文件的大小
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';//日志格式設(shè)置
    access_log  logs/access.log  main;//訪問(wèn)日志存儲(chǔ)路徑
    sendfile        on;//指定 nginx 是否調(diào)用sendfile 函數(shù)(zero copy 方式)來(lái)輸出文件
    keepalive_timeout  65;//keepalive超時(shí)時(shí)間
    server {//配置虛擬機(jī)
        listen       8080;//監(jiān)聽端口
        server_name  rtmp.datahq.cn 59.110.237.245;//名稱
    location /stat{//配置統(tǒng)計(jì)頁(yè)面路徑
            rtmp_stat all;
            rtmp_stat_stylesheet stat.xsl;
        }
    location /stat.xsl{//統(tǒng)計(jì)模板路徑
            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;//監(jiān)聽端口
        ping 30s;//活動(dòng)連接檢查周期
        application live{//應(yīng)用名
        live on;//打開直播模式
        meta copy; //是否發(fā)送直播端元數(shù)據(jù)信息
        session_relay on;//打開會(huì)話轉(zhuǎn)發(fā)模式
        drop_idle_publisher 10s;//10s沒(méi)有推流,自動(dòng)斷開直播端
        sync 10ms;//同步流時(shí)間閥值
        record_append on;//打開直播流錄制追加模式
        record_path /usr/local/nginx/files;//錄制文件地址
        record all;//打開錄制功能
        }
    }
}

拷貝統(tǒng)計(jì)模板到ngin配置目錄:

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

啟動(dòng)直播服務(wù)器:

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

打開統(tǒng)計(jì)頁(yè)面控制臺(tái):

http://rtmp.datahq.cn:8080/stat
enter image description here

統(tǒng)計(jì)表各屬性說(shuō)明為:
clients:連接數(shù)
live streams:流名
codec:編碼
bits:分辨率
size:視頻畫面大小
fps:每秒傳輸幀數(shù)
freq:音頻率
chan:音頻聲道
State:流狀態(tài)
Time:流活動(dòng)時(shí)間
其它4個(gè)為輸入與輸出流的每秒傳輸速率。

  • 測(cè)試直播

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

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

enter image description here

打開直播統(tǒng)計(jì)后臺(tái):如果看到已經(jīng)有一個(gè)推流,一個(gè)拉流,并有數(shù)據(jù)傳輸時(shí),說(shuō)明整個(gè)直播鏈路已經(jīng)暢通。

enter image description here

查看直播錄制文件:

enter image description here

此時(shí)看下系統(tǒng)的負(fù)載:可以發(fā)現(xiàn)CPU,內(nèi)存的負(fù)載都很低,可以忽略不計(jì)。

enter image description here
  • 上線

到本節(jié)為止,一個(gè)簡(jiǎn)單的直播平臺(tái)就搭建好了,接下來(lái)我們要做的就是上線,因?yàn)闆](méi)有上線,一切都是零。下面是我們?cè)谏暇€過(guò)程中遇到的一些坑,供各位同學(xué)參考:

  • 系統(tǒng)打開文件數(shù)默認(rèn)太低,造成部分用戶連接不上。

  • 遇到活動(dòng)高峰,網(wǎng)絡(luò)帶寬成為瓶頸,造成收聽用戶卡頓很多。在生產(chǎn)環(huán)境中需要時(shí)刻關(guān)注是否升級(jí)帶寬。

  • 上線盡量選擇在沒(méi)有直播的時(shí)候進(jìn)行。

總結(jié)

今天給大家分享了直播平臺(tái)搭建的一些知識(shí),涉及到了rtmp協(xié)議,直播選型的一些注意點(diǎn),大規(guī)模直播架構(gòu),nginx-rtmp直播服務(wù)器實(shí)戰(zhàn)搭建等。如果各位有直播的需要,可以順著本文的一些知識(shí)點(diǎn)進(jìn)行實(shí)戰(zhàn)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 譯序:截至 Jul 8th,2013 官方公布的最新 Nginx RTMP 模塊 nginx-rtmp-modul...
    河自清閱讀 11,887評(píng)論 2 9
  • 不會(huì)做直播還混什么互聯(lián)網(wǎng) 2016年國(guó)內(nèi)各種直播應(yīng)用如雨后春筍一般涌現(xiàn)出來(lái),各大主打云服務(wù)的國(guó)內(nèi)互聯(lián)網(wǎng)巨頭紛紛推出...
    假裝是小宇閱讀 2,206評(píng)論 1 0
  • 近年互聯(lián)網(wǎng)直播業(yè)務(wù)非常火熱。我也研究了下,發(fā)現(xiàn)nginx上配置視頻直播點(diǎn)播也很容易實(shí)現(xiàn),特分享一下。 一、ubun...
    dagailv閱讀 1,454評(píng)論 0 2
  • 我有一朋友,是典型的人格分裂。 高中寢室23點(diǎn)斷電,他總在22點(diǎn)59分的時(shí)候,說(shuō)一句,這個(gè)世界終將被黑暗籠罩,然后...
    Lux_13閱讀 275評(píng)論 3 4
  • 今天看了一篇文章,是比較受歡迎的一位業(yè)余自由撰寫人寫的,每次寫的文章都很戳心,很受大家歡迎,很多讀者都想認(rèn)識(shí)...
    方苑閱讀 262評(píng)論 0 0

友情鏈接更多精彩內(nèi)容