1. 程式人生 > >基於nginx-rtmp-module模組實現的HTTP-FLV直播模組nginx-http-flv-module(二)

基於nginx-rtmp-module模組實現的HTTP-FLV直播模組nginx-http-flv-module(二)

      由於《基於nginx-rtmp-module模組實現的HTTP-FLV直播模組nginx-http-flv-module(一)》內容已經很長,所以後續的更新將記錄在這兒。非常感謝網友們的測試反饋和程式碼提交!專案地址:https://github.com/winshining/nginx-http-flv-module。有問題或者建議,可以加Q群:711969608詳聊。目前已經有很多個人和廠商準備將本模組商用,據網友反饋,國外已經有直播網站在用這個模組。準備商用的廠商中最著名的是華為,網友和廠商陸續反饋過不少bug,修復後功能已經越來越穩定,在此表示感謝。

2018-06-04:一家CDN廠商正式上線nginx-http-flv-module,使用RTMP方式,開gop_cache配置(關閉interleave配置,開啟會卡頓或者沒有聲音,目前暫時不知如何修復),他們的客戶包括映客和微吼。

2018-06-28:一家網路視訊廠商正式上線nginx-http-flv-module,使用HTTP-FLV方式,不開gop_cache配置,目前還沒開全量,等待觀察穩定性。

2018-07-28:應一部分網友的需求,已經提供RHEL6(CentOS 6)和RHEL7(CentOS 7)的rpm安裝包,見nginx-http-flv-module-packages

        nginx-http-flv-module與nginx-rtmp-module的功能對比:

功能 nginx-http-flv-module nginx-rtmp-module 備註
HTTP-FLV × nginx-http-flv-module支援HTTPS-FLV
GOP快取 ×
vhost ×
省略listen配置 x
JSON風格的stat x
RTMP 302 Beta × nginx-http-flv-module作為伺服器或者客戶端

2018-03-09更新:

最近這段時間主要在不同平臺測試模組的穩定性,目前播放這一塊沒發現問題,由於條件限制,除了FreeBSD平臺沒測試過,Windows 7,Debian 7.x和macOS Sierra都測試過了,由於Nginx官方對Windows支援不太好,沒用Windows平臺最強大的IOCP介面(使用的select),所以導致Windows平臺上執行效率不太高,表現在推流等待時間長,3s+,首屏時間很長,4s+,select本身原因限制客戶端個數,預設是1024。推流等待時間和首屏時間最短的是macOS Sierra,本機上測試時基本上是秒推秒開。昨晚專門注意了一下,在macOS Sierra下編譯時,SO_REUSEPORT和TCP_FASTOPEN兩項都支援,前者讓Nginx的每個子程序都可以listen,都有一個專門的accept佇列,解決了驚群效應;後者則是在發起SYN時就已經攜帶實際資料,而不是握手完畢後再傳輸實際資料。秒推秒開可能跟這兩個選項有關。但是macOS Sierra並不支援將某個程序繫結到某個CPU上,所以可能程序上下文切換會有開銷,系統負載較大時可能效率不如Linux。由於macOS Sierra是公司的電腦,所以未做壓力測試。我的筆記本裝的是Debian 7.x,因為核心版本較低,所以macOS Sierra上支援的兩個選項都不支援。測試時推流等待時間和首屏時間都介於Windows 7和macOS Sierra之間,在伺服器上測試時(系統CentOS 6.4,支援SO_REUSEPORT但是不支援TCP_FASTOPEN)跟macOS Sierra上差不多,但是考慮到伺服器的CPU效能強大得多,所以負載不高情況下,macOS Sierra的表現是最好的。由於macOS Sierra是從Mac OS X更新來的,而Mac OS X的底層最初是在FreeBSD基礎上開發的,所以推測在FreeBSD上的表現應該也不錯。

另外最近在嘗試新增RTMP 302重定向轉HTTP 302重定向的功能,由於很多播放器不支援RTMP 302重定向,但是支援HTTP 302重定向的功能基本上是標配,實測VLC是支援的。目前功能基本上已經完成,但是困擾的地方還是使用HTTP框架的傳送介面時,連結串列在長時間播放後會形成環,所以進展不下去了,沒有更新到github上。下面是nginx的rtmp主要配置片段和VLC播放時的HTTP 302重定向截圖:其中推流是在名為hls的application上推的(FFmpeg也不支援RTMP 302重定向,所以只能往hls推)。

application myapp {

    ...;

    rewrite '^/myapp/(.*)' '/hsl/$1';

}

1.HTTP 302重定向抓包簡略圖

2.HTTP 302重定向抓包詳情圖

2018-03-15更新:

有網友反饋on_play指令不能使用,經除錯,是因為加入的ngx_http_flv_live模組的順序有問題,現修改為不改變模組順序的前提下,經過一些狀態的修改繞過它,後續再呼叫其中的一些函式,以保證與原來的nginx-rtmp-module的功能一致。

2018-03-16更新:

部分網友們提出的CORS(跨域)功能已經可用,HTTP-FLV的回覆資料不再使用硬編碼,而是使用部分HTTP框架的程式碼重寫了。另外,on_connect功能有問題,暫時不能用,等待修復。

2018-03-18更新:

on_connect的問題已經修復。

2018-03-20更新:

修復因為要查詢的application不在第一個server塊中造成找不到對應的on_connect和on_play的bug,經查是由於沒有匹配到正確的server配置,已修復。

2018-03-22更新:

很久之前有網友提出過設定idle_streams為off(預設為on)時,使用HTTP-FLV方式播pull會失敗,現已修復。

2018-03-25更新:

有網友使用flv.js播放nginx-http-flv-module拉的直播流,發現一個bug:當(1)使用的Nginx版本號為1.13.9,(2)播放器為flv.js,(3)播放pull的流時,會出現無法播放的情況,經查是因為flv.js傳送了HTTP頭“Connection: keep-alive”,nginx-http-flv-module在向上遊發起請求時,下游請求一般在上游請求還沒有返回時就已經返回,但是Nginx從版本1.13.1起,刪除了一個r->blocked判斷,而“Connection: keep-alive”導致ngx_http_finalize_request呼叫ngx_http_set_keepalive,這個函式會呼叫註冊的cleanup函式來關閉下游的請求,導致播放失敗。已經修復。也正是在除錯這個bug的過程中,發現nginx-http-flv-module在開啟gop_cache配置項的情況下,flv.js跟其他主流的播放器(如vlc)相比,首屏時間是最快的,幾乎沒有延遲,使用的pull源是香港衛視的直播源:rtmp://live.hkstv.hk.lxdns.com/live/hks

2018-03-27更新:

順手改點程式碼就有bug,真是惱火。最近為了響應一些網友要求新增定製的HTTP頭的功能,修改了傳送功能,再次嘗試將Nginx的HTTP框架的filter介面引入,還是失敗了,所以簡單粗暴地把最後一個filter模組和header_filter模組挑出來,刪除了很多用不上的程式碼。github上編譯用的是Nginx官方的穩定版本nginx-1.12.2。結果今天有網友反饋編譯不過去,經查剛好這幾個找不到的巨集是在我從修改nginx-rtmp-module就一直使用的nginx-1.11.10中加入的,而網友用的版本低一些就編譯不過去,已經修復。

2018-03-29更新:

前幾天有網友反饋使用nginx-1.13.1以及以上的版本與nginx-http-flv-module一起編譯時,使用flv.js播放pull流會失敗,見2018-03-25更新,結果修復了那個問題,又出了先推流,然後使用flv.js播放會失敗的問題,真是隨手改出bug,問題已經修復,最新版本的Nginx和稍微舊一些的版本(nginx-1.11.10)都已經測試通過。

2018-04-05記錄:

這次不是更新:)昨天有網友反饋使用flv.js播放推流時,一直播放不了,我還以為nginx-http-flv-module又出問題了,自己測試了一下,用最新的nginx-1.13.10一起編譯,播放推流和拉流都沒問題,又用官方的穩定版nginx-1.12.2一起編譯,還是沒問題,晚上準備看看哪兒出問題的時候,網友反饋是瀏覽器限制了flv.js的數量,他用的是Chrome,據測試單瀏覽器只能開6個flv.js,今天中午我用Firefox測試了一下,也是同樣的問題,第7個flv.js播放不了,然後開VLC播放,沒有問題,由此可以確認不是nginx-http-flv-module的問題。不過這是個很重要的資訊,瀏覽器對flv.js的播放支援是有數量限制的,Chrome和Firefox的限制數量都是6個,其他瀏覽器未測試。

2018-04-06更新:

之前的統計資料一直沒有把http-flv直播的accepted數量和輸出計入,現已新增。現在對flv.js的支援已經穩定,下面是使用flv.js播放的截圖:

一個商用廠商反饋視訊源是純視訊時,不管使用什麼播放器,播放連線沒問題,但是一直接收不到視訊資料,經除錯發現是因為判斷純音訊的邏輯有bug,導致nginx-http-flv-module在傳送音視訊資料的介面中無限迴圈了,現已修復。

2018-04-14更新:

有網友昨天反饋開啟gop_cache選項時,推流會導致記憶體洩露,已查明是推流關閉時沒有釋放gop cache模組分配的記憶體造成的,已修復。另外,據網友反饋,多程序模式下,on_connect和on_play指令有問題,暫時別在多程序模式下用這兩個指令,等待修復。

2018-04-15更新:

一個商用廠商反饋隨機閃斷測試時,記憶體會不斷增長,懷疑有記憶體洩露,晚上除錯時確認確實有記憶體洩露,是由於沒有釋放ngx_http_request_t結構中的記憶體池造成的,已修復。

2018-04-21更新:

有網友反饋多程序模式下,使用on_play進行鑑權操作,但是在推流的時候,本地relay(接受推流的子程序將流推給別的子程序)也會執行on_play鑑權,這是不太合理的(但是其實並不算bug),因為之前已經進行過鑑權了。現在將本地relay的on_play操作去掉了,nginx-http-flv-module並不關心on_play用來做什麼,但是考慮到本地relay不應該再執行on_play操作了,修改的程式碼也比較簡單,恢復也很容易,所以先暫時這樣修改。另外網友@qqzzzx 反饋的壓測崩潰的問題已經修復一部分,現在還存在的問題是壓測群斷後會有記憶體洩露的問題,修復後會更新到github上。

2018-04-25更新:

壓力測試崩潰的問題已經修復,捎帶解決了可能出現的CPU使用率過高的問題,已壓力測試1個多小時(srs-bench自帶的測試視訊,500路HTTP-FLV和200路RTMP),暫未發現問題,歡迎反饋bug。

2018-05-12更新:

有網友反饋開啟gop_cache選項,某些情況下壓力測試會特別耗費記憶體,不確定是不是有記憶體洩露。壓測多次不能復現,網友提示壓測工具和伺服器不在同一主機上比較容易復現。按照這種方式壓測果然比較容易復現,但是出現耗費記憶體比較大的情況下,停止壓力測試,然後再次壓力測試且併發數不變,記憶體不會增長,證明不是記憶體洩露的問題。後來反覆檢視原始碼後,猜想是因為傳送GOP的時候,一次性將GOP資料放入傳送環形陣列中,由於Nginx是非同步非阻塞的,所以Nginx不一定會馬上將資料從環形陣列中真正傳送到網路(如伺服器和客戶端之間的網路頻寬不足的情況下),造成已分配的記憶體不能馬上迴圈使用,而且真正傳送完GOP後,已分配的記憶體不再釋放(在記憶體池中,並且與連線無關,只跟配置結構體有關)。後續的資料傳輸不像GOP資料是一次性全部發送,所以導致回收的記憶體不能被充分使用,有很大一部分閒置了。現將gop cache模組修改為使用自己獨立的記憶體池,等GOP傳送完後,釋放這個記憶體池。

2018-05-14更新:

修復了一個2018-05-12更新引入的記憶體洩露的bug,屬於程式碼久了看不懂,然後一改就出問題的情況抓狂。修復高版本gcc編譯工程失敗(在網上查了一下,gcc-7.x.x在添加了某些編譯選項時,會檢查switch的case是否有fall through)的bug,不過我手頭沒有很高版本的gcc,所以可能還存在一些沒被發現的編譯錯誤,目前正等待網友的回覆。

2018-05-16更新:

白天編譯安裝了gcc-7.2.0,找出了所有的fall through編譯警告(Nginx的編譯選項中被視為錯誤),已修復bug。

2018-05-18記錄:

這次不是更新,2018-05-12更新中我猜想壓力測試(使用的工具是srs-bench)時開啟gop_cache選項會特別耗費記憶體的原因,今晚經過檢視日誌,發現之前的猜想其實不是主要原因。從日誌中可以看到Nginx在接收資料時一直都是128位元組,而在配置中如果沒有指明chunk_size配置項時,預設是4096個位元組,就是說伺服器傳送Set Chunk Size協議控制訊息後,客戶端並沒有響應Set Chunk Size協議控制訊息,所以伺服器一直沿用之前的128位元組,最糟糕的情況下,會導致nginx-http-flv-module在接收到資料後,分配記憶體對資料進行打包時,用(4096+RTMP頭最大大小)這麼多位元組的空間來打包128位元組的資料,白白浪費了32倍多的資料。使用ffmpeg進行對比測試,ffmpeg是會響應Set Chunk Size協議控制訊息的,所以不會造成記憶體浪費。已經給SRS(Simple-RTMP-Server)的作者提issue了。後續有空我會更新nginx-http-flv-module對這種異常的處理。

2018-05-20更新:

某些情況下特別耗費記憶體的問題已經修復,如果耗費使用量還很大,那麼可能是由上面說的那個次要原因引起的了。

2018-06-14更新:

修復一個網友反饋的問題,ngx_stat_active引數在執行一段時間後值不正確,經查是由於重複減去操作造成的,已修復,不影響正常功能使用。

2018-06-19更新:

同步了幾個nginx-rtmp-module的pull requests裡的bug修復,基本上都是一些很明顯的bug,大的修改沒同步過來。另外,目前在nginx-http-flv-module基礎上添加了直接推送fmp4的功能,今晚已經實現直接推送純視訊的fmp4到支援MSE(Media Source Extensions,目前iOS上的Safari不支援)的瀏覽器中播放,後續會將音訊一起加上。

2018-06-25更新:

推送fmp4的基本功能已經基本完成。有網友推了支援JSON格式的stat的PR,已經合併,試用了下,感覺非常不錯,另外修復了一個小bug。

2018-06-29更新:

將stat中原有的rtmp資訊修改為http-flv,鑑於已經有兩個廠商分別正式商用RTMP(開啟gop_cache)和HTTP-FLV(不開gop_cache),釋出了里程碑版本1.2.4。

2018-07-09更新:

修復了3個小bug:開啟DASH功能時,有可能因為從檔案中讀取的資料為0導致無限迴圈;修復xml方式的stat中不能顯示nginx-http-flv-module的版本號的問題(網友的PR);修復HEAD請求沒有配置flv_live的locations時返回405(Method Not Allowed)的bug。

2018-07-20更新:

修復了一個日誌記錄bug,剛好把client和server對調了。

2018-07-30更新:

修復一個潛在的導致記憶體洩露的問題和一個與nginx-1.15.2編譯出錯(高版本的Linux核心支援SO_REUSEPORT(詳情見2018-03-09更新),nginx-1.15.2修改了一個函式的引數型別)的問題。

其他文章: