使用SRS構建多網環境下的流媒體服務集羣 1. SRS簡介 2. 模型抽象與相關概念 3.系統實現 4. 結語

1. SRS簡介

  SRS(Simple RTMP Server) 是國人寫的一款非常優秀的開源流媒體服務器軟件,可用於直播/錄播/視頻客服等多種場景,其定位是運營級的流媒體服務器。SRS支持RTMP/HLS/FLV,高效、穩定、易用,簡單而快樂(readme中的描述)。
  在行業IM(即時通信)軟件項目中,我們使用多個SRS服務器構建流媒體服務集羣用於音視頻會話。行業IM軟件是面向行業的即時通信軟件(類似微信),在行業應用中,網絡環境比較複雜,需要考慮多網下的互聯。比如在實際部署中,IM系統會部署在公安網,視頻網,政務網等網絡中(網絡之間通過網閘互聯,這些網閘的聯通方向有可能是單向,如網絡1只能向網絡2發起連接,網絡2不可向網絡1發起連接)。通信的雙方可能會跨網進行音視頻會話,這就需要流媒體服務集羣需要具備跨網調度媒體流的能力。
  SRS集羣可以通過內部配置邊緣和源站來實現媒體流的調度。但在多網互通的環境下,會將流的壓力都集中到源站服務上,當然通過配置源站集羣可以解決這個問題,但是這樣會帶來更多的資源消耗。我們設計了一種簡單易用的媒體流調度模型與服務實現SRS服務器集羣在多網之間的媒體流調度。

2. 模型抽象與相關概念

  對於某個網絡中的客戶端,只能從本網SRS節點(以下簡稱S節點)中獲取所屬音視頻會話中的流。在進行音視頻交互時附着在本網某個S節點上,通過這個S節點推送自己的流。當需要獲取對端客戶端的流時,從本網某個附着對端客戶端的S節點上拉取對端客戶端的流。
  多網環境下,對於一個媒體會話,會話中的多個客戶端可能分佈在不同網絡中,每個客戶端只能訪問本網中的S節點進行推拉流。若某個客戶端想要在本網中訪問對端(在另外一個網絡)的流,需要將對端在另外網絡中的流(附着在另外網絡的S節點上)調度到本網的某個S節點上。
  多網環境下,每個網絡中需要有一個S節點控制器(以下簡稱SC)來進行本網內,多網間S節點的音視頻流調度。
  實現原理如圖1所示:



  該結構中:
  1. 網絡1中,客戶端ClientA附着在SRS_A1上。網絡2中,客戶端ClientB附着在SRS_B2上。
  2. VC將SRS_B2上的ClientB流調度到網絡1的SRS_B1上。
  3. VC將SRS_A1上的ClientA流調度到網絡2的SRS_A2上。
  使用該結構:ClientA可以在網絡1中使用SRS_B1訪問ClientB的流;ClientB可以在網絡2中使用SRS_A2訪問ClientA的流。

3.系統實現

3.1 系統架構

  在多網環境下,每個網絡中部署一個SC,用於本網內S節點的註冊發現,本網內S節點間,本網S節點與外網S節點之間的音視頻碼流調度。整體流媒體服務集羣如圖2所示:


  在此集羣結構中,我們定義:某個網絡內,某客戶端附着的S節點稱爲這個客戶端的源節點(source),承載源節點媒體流(非客戶端直推到該節點)的節點稱爲這個客戶端的代理節點(proxy)。如在網絡1中:在SC1的調度下,SRS_A1是ClientA的源節點,SRS_B1是ClientB的代理節點;在網絡2中,在SC2的調度下,SRS_A2是ClientA的代理節點,SRS_B2是ClientB的源節點。
  對於一次客戶端ClientA和客戶端ClientB進行的一次雙向音視頻會話而言,ClientA登錄在網絡1中,ClientB登錄在網絡2中。在網絡1中,需要由SC1分配給它一個推流節點SRS_A1用於 ClientA推送自己的流,分配一個拉流節點SRS_B1用於ClientA拉取ClientB的流。這樣對於任何一個作爲視頻源的客戶端,在它所登錄的網絡中有一個源節點用於推流(作爲視頻源),在其它網絡中可能存在一個代理節點用於向其它客戶端提供該視頻源的流。這些流由各網中部署的VC進行調度。
  在各網之間分配的推拉流節點資源之間以一次會話爲一個集合,放在redis緩存中,被稱爲S節點資源表。
  本網內SC調度S節點的信息也以一次會話爲一個集合,被稱爲S節點調度表,放在redis緩存中。
  創建和銷燬作爲視頻源的S節點觸發創建和銷燬源V節點的事件,由IM系統的應用網關通知到其它網絡中的應用網關及SC。其它網絡中的SC根據該事件實施節點之間的調度與資源的清除。

3.2 應用接口

3.2.1 客戶端接口

  主要爲兩個接口:
  開始推拉流接口,定義爲HTTP POST請求,參數定義如下:

參數名 必選 類型 說明
accessToken string 客戶端登錄獲取的sessionId
userCode string 推拉流的用戶,字段中攜帶域,形式爲"userCode@Domain"
oprType string 推拉流類型:PUSH-推userCode用戶的流,PULL-拉userCode用戶的流
sessionSn string 本次音視頻會話的唯一標識
protocol string 客戶端使用的協議: http-客戶端使用HTTP協議;https-客戶端使用HTTPS協議;rtmp-客戶端使用RTMP協議。該字段不填的話默認返回http協議

  客戶端向S節點推拉流之前,調用SC的該接口發送推拉流的信息,接口返回客戶端使用的S節點。
  停止推拉流接口,定義爲HTTP POST請求,參數定義如下:

參數名 必選 類型 說明
accessToken string 客戶端登錄獲取的sessionId
userCode string 推拉流的用戶,字段中攜帶域,形式爲"userCode@Domain"
oprType string 推拉流類型:PUSH-推userCode用戶的流,PULL-拉userCode用戶的流
sessionSn string 本次音視頻會話的唯一標識

3.2.2 S節點間接口

  S節點間接口實現一個SRS服務器向另一個SRS服務器之間開始或停止推拉流的操作。爲HTTP POST請求,媒體流協議使用rtmp。接口參數定義如下:

參數名 必選 類型 說明
opt string 操作類型,可選值:push,pull,stop,push:向URL裏面指定的地址推流,pull:從URL裏面指定的地址拉流,stop:指定URL停止推拉流
urls List<string> 推拉流的URL,URL裏面的地址即爲推拉流的地址,URL的schema目前固定爲’rtmp’,其他值將返回錯誤

  如對於如下請求:

{
    opt:"pull",  //Can pull, push or stop
    urls:["rtmp://192.168.1.1:1935/live/a@default_1",
    "rtmp://192.168.1.2:1935/live/b@default_2"]
}

  表示當前S節點向IP爲192.168.1.1的S節點拉名爲“a@default_1”的流,向IP爲192.168.1.2的S節點拉名爲“b@default_2”的流。

3.3 調度算法

3.3.1 客戶端開始推拉流操作

  SC的調度操作由客戶端觸發。客戶端的觸發指令爲三元組(操作類型,用戶編碼,音視頻會話標識),算法定義如下:
  推流算法如下:

名稱:推流調度算法
輸入參數:
nodeName, //客戶端登錄網絡名稱,(“nodename@domain”形式,由域名與網絡名組成)
userCode, //用戶編碼,攜帶域名
sessionSn //音視頻會話ID
輸出參數:
     vstreamerAddr //附着的V節點地址
過程:
vstreamerResource = findVResource(sessionSn); //在全局資源表中查找該會話的節點資源
//1.判斷是否本網內是否已有source節點
if(null != vstreamerResource){
  vNodeResource = vstreamerResource.get(nodeName); //獲取本網的資源列表
  vAddr = vNodeResource.getAddr(userCode); //獲取userCode的source節點
  if(null != vAddr)
     {
        //修改V節點類型爲source,如果是已經爲“source”的不用修改
         ModifySourceType (vNodeResource,“source”); 
         Return vAddr; //已經存在推流節點,返回
}
}
//2. source節點不存在,創建source節點
vresource = vstreamerResource.createNode(nodeName,”source”);
vAddr = dispatch(nodeName, userCode); //在本網內爲userCode分配一個source節點

//3.返回source節點並將該資源推送到其它網絡
forwordOtherNode(nodeName, userCode, vAddr); //將分配的source節點通知其它網絡
Return vAddr;

  對於客戶端推流操作,SC的調度算法主要思想是:首先在全局資源表中查找本網該用戶是否已經分配了源節點,如果沒有,則在本網中分配一個作爲該用戶的源節點。並將創建該source節點信息發佈到其它網絡中。
  對於客戶端拉流操作,SC的調度算法如下:

名稱:拉流調度算法
輸入參數:
nodeName, //客戶端登錄網絡名稱,(“nodename@domain”形式,由域名與網絡名組成)
userCode, //用戶編碼,攜帶域名
sessionSn //音視頻會話ID
輸出參數:
     vstreamerAddr //附着的V節點地址
過程:
vstreamerResource = findVResource(sessionSn); //在全局資源表中查找該會話的節點資源
//1.判斷是否本網內已有source節點或proxy節點
if(null != vstreamerResource){
  vNodeResource = vstreamerResource.get(nodeName); //獲取本網的資源列表
  vAddr = vNodeResource.getAddr(userCode); //獲取userCode的source節點
  if(null != vAddr)
     {
         Return vAddr; //已經存在source或proxy節點,返回
}
}

//2. 拉流節點不存在,創建proxy節點
vresource = vstreamerResource.createNode(nodeName,”proxy”);
vAddr = dispatch(nodeName, userCode); //在本網內爲userCode分配一個proxy節點

//3.在V節點資源表中查找其它網絡的source節點,並實現推拉流調度
vSourceAddr = findOtherNode(userCode, sessionSn);
if(null != vSourceAddr){
   //在它網的source節點與本網的proxy節點之間實現推拉流調度,需要考慮網絡方向
   pullPushStreamer(vSourceAddr, vAddr,sessionSn,userCode);
}

Return  vAddr;

3.3.2 監聽創建source節點事件

  客戶端在自己所登錄的網絡內向SC請求推流操作,實際上是在本網絡內增加一個該用戶視頻源,由SC分配一個source節點。該source節點需要廣播到其它網絡中,因爲其它網絡中可能有需要該用戶視頻流的proxy節點。需要將該source節點的流調度到proxy節點中。
  當一個網絡內發生客戶端的推流事件(由SC分配source節點)時,由本網的SC廣播給其它網絡的SC。當SC收到其它網絡分配的source節點時,其調度算法如下:

名稱:監聽來自它網的source節點
輸入參數:
nodeName, //source節點所在網絡
userCode, //用戶編碼,攜帶域名
sessionSn, //音視頻會話ID
vSourceAddr //source節點的地址
輸出參數:
     無
過程:
    //寫入本網的V節點資源表
writeResource(nodeName, userCode, sessionSn, vSourceAddr); 
//在本網的V節點資源表中查找本網該會話的節點資源
vstreamerResource = findVResource(sessionSn); 
//查找本網內是否有用戶爲userCode的proxy節點 
vProxyAddr = vstreamerResource.searchProxyAddr(userCode,”proxy”);
//如果本網內有userCode的proxy節點,進行調度
if(null != vProxyAddr){
   pullPushStreamer(vSourceAddr, vProxyAddr,sessionSn,userCode);
}

4. 結語

  本文中我們介紹了一種使用SRS構建多網環境下的流媒體服務集羣的模型、思路與方法。該思想同通過視頻源的需求關係實現了多個SRS服務器之間的媒體流調度,客戶端使用簡單的接口即可獲取分配到的SRS服務實例,與複雜的IM通訊服務流程與信令實現瞭解耦。
  在實際應用中,由於多網之間存在單向通信,網閘之間需要進行SRS服務地址與端口映射等複雜情況,我們的實現代碼要複雜的多,但基本思想仍然遵循本文所描述的思想。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章