序言
在搭建了SRS的邊緣服務器後,可能會有延遲,至少我遇到了.所以整理下2.0version的延遲解決方法.
主要針對的是流媒體服務器的延遲調優,播放器的調優需要根據播放器的類型自行選擇.
SRS也是根據你的情況需要選擇不同的配置組合.來滿足你的直播需要
參數配置說明(根據自己的情況選擇配置).
GOP-Cache(魚與熊掌不可兼得,魚:立即能看 熊掌:低延遲)
什麼是GOP?就是視頻流中兩個I幀的時間距離,如果問什麼是I幀就去百度。
GOP有什麼影響?Flash(解碼器)只有拿到GOP才能開始解碼播放。也就是說,服務器一般先給一個I幀給Flash。可惜問題來了,假設GOP是10秒,也就是每隔10秒纔有關鍵幀,如果用戶在第5秒時開始播放,會怎麼樣?
第一種方案:等待下一個I幀,也就是說,再等5秒纔開始給客戶端數據。這樣延遲就很低了,總是實時的流。問題是:等待的這5秒,會黑屏,現象就是播放器卡在那裏,什麼也沒有,有些用戶可能以爲死掉了,就會刷新頁面。總之,某些客戶會認爲等待關鍵幀是個不可饒恕的錯誤,延時有什麼關係?我就希望能快速啓動和播放視頻,最好打開就能放!
第二種方案:馬上開始放,放什麼呢?你肯定知道了,放前一個I幀。也就是說,服務器需要總是cache一個gop,這樣客戶端上來就從前一個I幀開始播放,就可以快速啓動了。問題是:延遲自然就大了。
有沒有好的方案?有!至少有兩種:
- 編碼器調低GOP,譬如0.5秒一個GOP,這樣延遲也很低,也不用等待。壞處是編碼器壓縮率會降低,圖像質量沒有那麼好。
- 服務器提供配置,可以選擇前面兩個方案之一:SRS就這麼做,有個gop_cache配置項,on就會馬上播放,off就低延遲。
# the listen ports, split by space.
listen 1935;
vhost __defaultVhost__ {
# [email protected]
# whether cache the last gop.
# if on, cache the last gop and dispatch to client,
# to enable fast startup for client, client play immediately.
# if off, send the latest media data to client,
# client need to wait for the next Iframe to decode and show the video.
# set to off if requires min delay;
# set to on if requires client fast startup.
# default: on
gop_cache on;
}
累積延遲(服務器會緩存,但是不能太長,客戶端也會緩存,客戶端只能重新連接服務器)
除了GOP-Cache,還有一個有關係,就是累積延遲。SRS可以配置直播隊列的長度,服務器會將數據放在直播隊列中,如果超過這個長度就清空到最後一個I幀:
# [email protected]
# the max live queue length in seconds.
# if the messages in the queue exceed the max length,
# drop the old whole gop.
# default: 30
queue_length 10;
當然這個不能配置太小,譬如GOP是1秒,queue_length是1秒,這樣會導致有1秒數據就清空,會導致跳躍。
有更好的方法?有的。延遲基本上就等於客戶端的緩衝區長度,因爲延遲大多由於網絡帶寬低,服務器緩存後一起發給客戶端,現象就是客戶端的緩衝區變大了,譬如NetStream.BufferLength=5秒,那麼說明緩衝區中至少有5秒數據。(服務器會一次性發給瀏覽器麼)
處理累積延遲的最好方法,是客戶端檢測到緩衝區有很多數據了,如果可以的話,就重連服務器。當然如果網絡一直不好,那就沒有辦法了。
Min-Latency
當開啓最低延遲配置後,SRS會禁用mr(merged-read),並且在consumer隊列中使用超時等待,大約每收到1-2個視頻包就發送給客戶端,達到最低延遲目標。
測試vp6純視頻流能達到0.1秒延遲,參考#257。配置文件:
vhost mrw.srs.com {
# whether enable min delay mode for vhost.
# for min latence mode:
# 1. disable the mr for vhost.
# 2. use timeout for cond wait for consumer queue.
# @see https://github.com/ossrs/srs/issues/257
# default: on
min_latency off;
}
Merged-Read
RTMP的Read效率非常低,需要先讀一個字節,判斷是哪個chunk,然後讀取header,接着讀取payload。因此上行支持的流的路數大約只有下行的1/3,譬如SRS1.0支持下行2700上行只有1000,SRS2.0支持下行10000上行只有4500。
爲了提高性能,SRS對於上行的read使用merged-read,即SRS在讀寫時一次讀取N毫秒的數據,這個可以配置:
# the MR(merged-read) setting for publisher.
vhost mrw.srs.com {
# about MR, read https://github.com/ossrs/srs/issues/241
mr {
# [email protected]
# whether enable the MR(merged-read)
# default: off
enabled on;
# the latency in ms for MR(merged-read),
# the performance+ when latency+, and memory+,
# memory(buffer) = latency * kbps / 8
# for example, latency=500ms, kbps=3000kbps, each publish connection will consume
# memory = 500 * 3000 / 8 = 187500B = 183KB
# when there are 2500 publisher, the total memory of SRS atleast:
# 183KB * 2500 = 446MB
# the value recomment is [300, 2000]
# default: 350
latency 350;
}
}
也就是說,當開啓merged-read之後,服務器的接收緩衝區至少會有latency毫秒的數據,延遲也就會有這麼多毫秒。
若需要低延遲配置,關閉merged-read,服務器每次收到1個包就會解析。
Merged-Write
SRS永遠使用Merged-Write,即一次發送N毫秒的包給客戶端。這個算法可以將RTMP下行的效率提升5倍左右,SRS1.0每次writev一個packet支持2700客戶端,SRS2.0一次writev多個packet支持10000客戶端。
用戶可以配置merged-write一次寫入的包的數目,建議不做修改:
# the MW(merged-write) settings for player.
vhost mrw.srs.com {
# set the MW(merged-write) latency in ms.
# SRS always set mw on, so we just set the latency value.
# the latency of stream >= mw_latency + mr_latency
# the value recomment is [300, 1800]
# default: 350
mw_latency 350;
}
若需要極低延遲(損失較多性能),可以設置爲100毫秒,SRS大約一次發送幾個包。
結果(推薦極端低延遲的最終配置)
當然,服務器的性能也要考慮,不可以讓一個SRS進程跑太高帶寬,一般CPU在80%以下不會影響延遲,連接數參考性能。
# the listen ports, split by space.
listen 1935;
vhost __defaultVhost__ {
gop_cache off;
queue_length 10;
min_latency on;
mr {
enabled off;
}
mw_latency 100;
tcp_nodelay on;
}