流媒體服務器的性能可以從抗抖動能力、擁塞率和卡頓率等方面進行分析。當用戶訪問的頻率過高或者并發的數量超過流媒體服務器所能承受的范圍時,必須考慮通過限流來保證接口的可用性,從而防止出現因請求數量過多、壓力過大造成服務器癱瘓等現象。因此,怎樣提高流媒體服務器的抗抖動能力,平滑發送流量,降低卡頓率,減少丟包率是本文描述的重點。
1.流媒體服務器框架設計
前面的CDN的文章對一些相關算法進行了比較分析,對CDN流媒體的關鍵技術也進行了選取。本文就基于Nginx 服務器,結合 HLS 流媒體協議與令牌桶算法,針對流媒體服務器的數據處理模塊、緩存模塊與發送模塊進行設計。
流媒體服務器的數據處理邏輯可分為以下幾個部分:
(1) 數據處理模塊:
數據處理模塊主要負責以下幾個功能:
(a) 接收來自客戶端的請求和來自上級服務器的發送數據。
(b) 負責數據代理轉發,在本地沒有直播緩存數據時,需要向上級 CDN 或者源站發送請求從而獲取數據,再把數據轉發給客戶端。
(c) 將錄制頻道的直播流文件寫入存儲系統,支持回看功能。
(2) 緩存模塊(Cache 模塊):Cache模塊用來從磁盤或者內存中讀取實體文件,解析出文件碼率,分包后對數據包進行時戳標記,并將標記好時戳的數據包壓入數據發送模塊。
(3) 發送模塊(Shaper 模塊):Shaper 模塊的主要功能是將 Cache 模塊輸入的數據發送至客戶端。Shaper 模塊在進行數據處理時會根據當前的發送狀態控制發送速率。Shaper 模塊中的隊列提供 FIFO(先進先出)的數據重傳功能,保證數據在重傳時不會亂序。流媒體服務器框架設計結構圖如下所示:
數據處理模塊在收到來自客戶端的請求后,會根據請求內容從 Cache 模塊中尋找相應資源,如果 Cache 模塊有相應的資源,則直接將數據交由 Shaper 模塊進行發送處理;如果 Cache 模塊中沒有相應資源,則會主動到本地磁盤進行資源查找;如果本地磁盤也沒有相應資源,則會通過數據處理模塊向源站發送請求信息,數據處理模塊接收源站的相應數據并將數據存放在存儲服務器中,最終 Shaper 模塊負責將用戶所請求的內容返回給客戶端。有時,對于一些熱門的視頻業務,數據處理模塊會提前向源站請求資源存入存儲服務器中,當用戶請求到來時可以及時作出響應。
2.流媒體服務器數據處理模塊設計
2.1 數據接收和轉發模塊設計與實現
在處理多客戶端請求時,可以在服務器端創建多個進程,但這種做法顯然有一些弊端,創建進程本身是一個消耗計算機資源的過程,一味地創建進程也無法應對快速發展的業務量。I/O 多路復用技術讓一個進程可以處理多個客戶端需求,使得上述問題得以解決。這里也會涉及到很多優化,所以我們需要考慮到可以使用更優秀的商用框架。
I/O 多路復用技術可以理解為通過一種機制來監視多個文件描述符(文件描述符是計算機術語,用來表示指向文件的引用),當某個描述符就緒,對程序進行相應通知來完成讀寫操作。在 I/O 多路復用的解決方案中,有 select、poll 和 epoll 三種方式,這三種方式的本質都是同步 I/O。當然也可以做到異步。
epoll 模型不僅會告知應用程序有 I/O 時間到來,還會告知 I/O 流的相關信息,因此,應用程序不必遍歷整個文件描述符集合就能定位到 I/O 事件,其時間復雜度為 O(1)。在性能上,select 模型和 poll 模型都會隨著連接數的增加性能急劇下降,而 epoll 模型在處理成千上萬的并發時,性能沒有很大的改變,且其對連接數上限沒有限制。epoll 模型最大的優點在于它只關心活躍的連接,而不關心總連接數,因此在實際的網絡環境中,epoll 的效率遠超于 select 模型與 poll 模型。epoll 除了在開發復雜度上略有難度,在內部使用數據結構、內核空間以及內在處理文件描述符機制等方面都優于 select,最重要的是,epoll 是實現了高并發的基礎。select、poll 與 epoll比較如下圖所示:
Nginx 已有的數據處理模塊就是基于 epoll 技術實現的,采用回調機制(callback)實現所有接收數據相關的函數,數據處理模塊結構圖如下所示:
代理轉發模式下,nginx_http_upstream_init_request 函數作為該模式的入口函數,將此函數注冊到 nginx_http_upstream_process 中,當進入調用鏈時,將需要監控的 epoll 句柄加入到nginx_add_event 中,在和上級源站建立連接成功后或者有數據交互時,epoll 監控到的句柄被觸發,從建立連接,發送請求,接收數據(此過程稱為代理回源)。
在數據接收流程中,ngx_event_accept函數作為該模式的入口函數,在系統啟動時,通過注冊到 nginx_event_process_init 函數中,將需要監控的 epoll 句柄加入到 nginx_add_event中。當有客戶端請求時,epoll 監控的句柄被觸發,進而對連接請求進行處理。
2.2 數據錄制模塊設計與實現
Nginx 目前沒有提供支持 HLS 或者 TS 協議的錄制模塊,本文采用 epoll 異步通知機制,設計錄制模塊,數據錄制模塊異步線程調用關系圖如下所示:
上圖中,Proxy 線程與文件 I/O 線程都是 Nginx 自帶的模塊。Proxy 線程負責接收來自于源站的請求數據,它將每個請求的文件描述符 fd 句柄加載到 epoll 中,再分發到各個錄制線程中,同時通過調用 submit_task()接口把錄制任務傳遞到錄制線程中。錄制線程則是把接收到的錄制任務數據進行整合(包含對錄制任務數據進行拼裝、去重、校驗、容錯等步驟)后,同樣將對應的文件描述符 fd 句柄加載到 epoll 中為 I/O 線程進行調用,同時調用 submit_task()接口進行異步寫盤。在進行異步寫盤時,默認寫盤數據大小一般設置 1MB 作為基本單位,這是因為當寫盤數據大小高于或是低于 1MB 時,內部存儲器調用 read()函數次數過多,會導致 CPU過高,且數據排列組合多,浪費時間。因此選擇 1MB 作為基本單位進行數據寫盤時效率最高。文件 I/O 線程負責接收錄制線程發送來的數據,是 Nginx 已封裝好的模塊,可以直接調用。
2.3 流媒體服務器數據緩存模塊設計
在傳統的 Nginx 流媒體服務器中,只有直播業務會采用緩存機制(Cache),但對于點播業務來講,傳統的 Nginx 流媒體服務器沒有 Cache 機制。點播業務會采用直接讀取磁盤上數據文件的方式,這種方式會導致磁盤 I/O 讀寫頻繁,不僅影響系統效率,還會加速磁盤老化。因此,本節基于 Nginx 流媒體服務器,在點播業務上新增緩存模塊,流媒體服務器會先從 Cache模塊中獲取所需要的數據,如果 Cache 模塊中沒有找到,才會從本地磁盤進行讀取,這大大減少了磁盤的讀寫,從而減少系統開銷,使性能得以優化與提升。
(1)Cache 模塊模型架構
Cache 模塊包含了 Cache 模塊與本地磁盤的交互方式。當客戶端發起請求后,數據接收模塊會根據請求內容在 Cache 模塊中尋找對應文件內容。Cache模塊中的 Cache_read()函數和 Cache_open()函數分別負責對內容資源的讀取與打開。請求來臨時,服務器會根據用戶請求所對應的文件描述符 fd 調用 Cache_read()函數進行內容讀取,之后調用 Cache_open()函數打開文件。若此時從 Cache 模塊中獲取到了相應資源,則直接將資源交由 Shaper 模塊進行發送處理;若沒有從 Cache 模塊中獲取到相應資源,則會根據文件描述符 fd 從本地磁盤中進行查找。
(2)本地磁盤包含兩大模塊,分別為 IO_open 模塊和 IO_read 模塊,其功能與 Cache 模塊中的 Cache_read()函數和 Cache_open()函數類似,負責對內容資源的讀取與打開,但調用方向有所區別。
當在 Cache 模塊中沒有獲取到索要找尋的數據時,會先調用本地磁盤的 IO_open 模塊將文件打開,并將文件描述符 fd 返回給 Cache 模塊中的 Cache_open()函數,之后調用 IO_read模塊進行文件內容讀取,并將讀取的內容返回給 Cache 模塊中的 Cache_read()函數。這樣一來,Cache 模塊中的數據會得到及時更新,當請求相同的資源時會直接從 Cache 模塊中進行讀取,從而減少了對本地磁盤的操作。對于長時間沒有被請求的內容 Cache 模塊會對其定期清理。Cache 模塊模型架構圖如下所示:
Cache 模塊從功能層面來講可以分為兩大部分:
(3) Cache_block:用于存儲文件數據塊的內容和相關信息。
(4) Cache_file:是應用層進行文件操作的基本單元,使用文件句柄 Cache_fd 作為基本憑證。Cache_file 包括兩種 block,分別為 cache_block_list 和 uncached_block_list,如下圖所示:
2.4 Cache 模塊的主要接口設計
Cache 模塊的主要接口設計如下:
(5) Cache_open()
文件打開接口,主要功能如下:
(a) 查看文件狀態。
(b) 在文件 hash 表中查找文件是否已經被打開,如果已經被打開,則刷新引用計數(ref),并直接返回;如果未被打開,則在 hash 表里增加一個表項,并使用 dump_file()接口打開該文件。
(6) Cache_read()
讀文件接口,主要功能如下:
(a) 增加文件引用數。
(b) 在 cache_file 的 block_list 中查找塊是否存在,如果存在則直接返回給調用者;如果未找到,則向空閑塊列表中申請一個新的塊。
(c) 調用 dump_file()接口進行文件讀取。
(d) 將塊加入到 used_list 和 cache_file 中。
(3) File_closed()
文件關閉接口,主要功能如下:
(a) 減少引用計數,一旦引用計數為 0,則執行文件關閉流程。
(b) 同步調用 dump_file()接口來關閉文件。
(c) 同步和異步銷毀 cache_file 文件,其中需要清空 cache_file 文件所擁有的 block_list。
(4) Io_read() 文件預讀接口,主要功能如下:
(a) 檢查 block 是否已經在 cache 中存在,如果存在則無需進行預讀。
(b) 向預讀線程提交預讀任務,預讀從線程中增加文件的引用計數,防止預讀過程中,文件被關閉。
(c) 調用 cache_read()接口,同時回滾文件的引用計數。
(5) Block_aging()
塊老化接口,主要功能如下:
(a) 遍歷 used_list,將引用數為 0 的 block 塊加入老化列表,并按照時間排序。
(b) 遍歷老化列表,將排名靠前的 N 個塊從 used_list 中摘除,放入 free_list,一旦空閑塊數量達到要求(閾值的兩倍),則停止老化。
2.5 Cache 模塊的功能設計與實現
Cache_file 用來存儲一個個的緩存數據塊,數據塊包括兩種,cache_block_list 和 uncached_block_list。在對這兩個模塊進行數據存儲時,可供選擇的數據結構有鏈表、二叉樹、哈希結構等
(1) 鏈表(含單向鏈表、雙向鏈表)鏈表的特點是便于元素的增加與刪除,開銷較小,但在對元素的查找時效率很低。因此其多用在數據量較小,且不需要排序的場景。
(2) 二叉樹(含紅黑樹、平衡二叉樹)
二叉樹的特點是在插入任意元素時都可以自動進行排序,使元素保持有一定的特性。由于二叉樹的空間占用與輸入的數據保持一致,所以不需要為二叉樹預先分配固定的空間。因此,二叉樹多是用在頻繁對數據進行增刪和查詢操作的場景下,在增刪改查的同時需要時刻保證數據的有序排列,且無需預先知道數據量的大小。二叉樹的時間復雜度是 O(log(n))。
(3) 哈希(hash) 哈希結構使用鏈表和數組來管理元素,在理想的哈希算法的支持下可以達到接近數組的隨機訪問效率,因此其使用場景為無需保證元素的有序性且頻繁對數據進行操作的場景。流媒體服務器應用在多用戶直播或點播場景中,此場景的數據特點是數據量大且保存媒體文件時無需排序。當一個用戶請求某一路直播(比如 CCTV2),哈希結構可以快速根據 CCTV2 的 hash 值很快找到對應的緩存塊,從中讀取數據,時間復雜度可以近似達到 O(1)。若使用鏈表或二叉樹,需對緩存中的每項內容進行遍歷,時間復雜度較高。其次,媒體文件本身并無排序需求,不符合二叉樹的使用場景。另外,哈希結構的代碼開發簡便且可維護性較強。綜上選擇使用哈希數據結構對流媒體服務器的 Cache 模塊進行設計開發。
在數據量較大時,哈希結構會產生沖突。解決哈希沖突采用的方案有兩種:第一種是線性探索,相當于在沖突之后建立一個單鏈表,這種情況下,插入和查找以及刪除操作消耗的時間會達到 O(n);第二種方法是開放尋址,這種方法不需要更多的空間,在最壞的情況下,時間復雜度也只會達到 O(n)。
Cache_file 的哈希結構在 Cache 模塊中的實現方式。哈希表的 key 值是由點播或者直播的媒體文件名通過哈希表達式計算得來。每一個 file 文件后又以鏈表的形式存有若干block,當需要查找資源時,只需按照哈希表達式來進行查找即可,這樣的數據查找方式在一定程度上提高了查找效率。Cache_file 的哈希實現方式如下所示:
(4) 在讀取數據入隊之前,Cache 模塊會將數據打上時間戳,時間戳的計算方法模擬令牌桶原理,每一個數據包的時間戳計算公式如下:
T 為當前數據包的 RTC 時間戳,size 為當前數據包的大小,TS 格式下的媒體元數據單位是 1316 字節,speed 為當前流媒體文件碼率,t 為上一個數據包的 RTC 時間戳。從公式可以看出,計算單位時間 1 秒內發送的報文數 n,可利用如下公式:
即給 n 個數據包打上時間戳。即在 time 秒內理論發送數據可以達到如下公式:
從上面的步驟可以看出,通過給數據包打 RTC 時戳的方式,可以計算單位時間內的發包個數,從而對其進行精確控制,實現均勻控制碼率的效果,與傳統令牌桶的實現方式相比,這種時間戳控制方式,在保證速率控制的同時,減少了發送模塊對令牌結構出隊入隊(保證一定的數據包個數),申請內存等操作,提升了系統性能。
3.發送模塊設計
Shaper 模塊即數據發送模塊,主要負責將 Cache 模塊入隊的數據進行發送,并計算發送結果,根據單位時間內發送的字節數 B 計算出當前的鏈路帶寬 b,實時更新每一個發送對端的鏈路速度,針對每一路用戶的數據流進行數據降速或者升速。上面和下面這些公式就說明怎樣去控制發送速率,非常重要。
3.1Shaper 模塊模型架構
流媒體服務器發送模塊的結構如下圖所示,圖中說明了數據的流程。
(1)本系統結合具體的業務場景增加了桶水位線的優化:如果當前媒體文件的碼率為 s,流媒體服務器數據緩存模塊以每 1/s 的精度,從當前 RTC 時鐘自加,給每個數據包作時戳標記。數據發送模塊預先開辟大小為 m 的隊列,將做好時間戳標記且需要發送出去的數據入隊,當數據包到達發送時間后,獲得令牌,出隊發送,每個隊列有一條上水位線 H 和下水位線 L,當網絡阻塞時,若隊列內的數據大于等于 H,則新到的數據不入隊,隊列中的每個數據時戳向后移動 d 個精度,這樣降低了發送速率,減少了網絡擁塞。降低后的速率為 如下計算公式:
當網絡狀況良好,無發送失敗記錄,并且隊列中的數據量在[L,H]之間,則將令牌生成間隔相對提高%d,按緩慢升速發送,如下計算公式:
直到隊列水位線下降到 L 處,為了保留緩存,數據發送速率恢復到媒體文件碼率 s,當數據發送成功后,該數據的令牌被銷毀。所以令牌桶的原理就是通過控制令牌產生的速度,將數據發送碼率平穩在 s 左右,對于每一個連接,令牌桶的數據流量為 B,計算公式如下:
3.2 Shaper 模塊運行機制
Shaper 模塊設計采用異步多線程運行機制,應用添加線程包中的數據來自于本地磁盤或是 Cache 模塊中的數據文件。Shaper 模塊中創建若干個發包線程,這些線程采用異步方式可以對應用添加包中的數據同時進行操作,這樣做的好處就是,當多個請求發來且訪問同一資源時,無需等待資源訪問結束,在空閑等待時同時可以訪問其他資源,提高了服務器的發送效率。如下圖所示:
3.3 令牌桶在 Shaper 模塊中的應用
將具體敘述如何將令牌桶算法應用在 Shaper 模塊中以及應用令牌桶算法對流量整形產生的影響。在服務器的內部存儲池中設計令牌產生模塊,實現以一定速率產生令牌。這些令牌在代碼中的具體實現是一些虛擬的數據包,當流媒體服務器接收數據時,會根據系統設定的匹配規則對接收的數據進行分類,符合規則的數據交由令牌桶處理,而不符合規則的數據包,直接拒之門外。Shaper 模塊的數據來源有兩處,一處是來自 Cache 模塊,一處是來自本地磁盤。不論數據來自哪里,Shaper 模塊都會將收到的數據打包并作時戳標記之后放入隊列。數據包根據時戳會決定何時出隊發送,出隊后的數據包會在內部存儲池中求取令牌,只有拿到令牌的數據包才可發送給客戶端。當數據包沒有獲得令牌(通常是令牌桶中的令牌不足的原因造成),服務器為隊列設置阻塞模式,數據包無法出隊,阻塞在隊列中。若阻塞數據包超過了隊列的上線,則新的數據包無法入隊。因此,我們可以通過控制令牌的產生速率來控制數據包的出隊入隊速率,從而達到對流量的控制。令牌桶在 Shaper 模塊中的應用如下圖所示:
假設令牌桶的容量為 D(單位:字節),產生令牌的速率為 v(單位:字節/秒),輸出數據的最大速率為 V(單位:字節/秒),突發的時間為 s(單位:秒)。當突發數據來臨前假設桶中的容量為 D-C,則有:
經過變型,則有:
由此可以計算出所能承受的突發時間,從而可以根據系統突發時間上限在代碼中進行設置。
令牌桶實現 Shaper 模塊的主要接口如下:
(1) bool Udp Shaper Channel()
此函數實現的功能是以 UDP 方式發送媒體數據,首先根據時間戳下發 ret 數據,之后發送媒體數據,如果成功則返回 True,失敗則返回 False。
(2) void Interleaved Shaper Channel()
此函數首先發送信令(發送信令的時戳為當前時間),再根據時戳決定當前是否要發送媒體數據。若到達發送媒體數據的時間則進行發送;若沒有到達,則等待。由于 TCP 有擁塞控制,當發送失敗時,數據包的時戳時間會改為當前時間加上延遲時間。
(3) void Download Shaper Channel()
此函數功能為下載媒體數據,負責發送碼率的升速與降速。在函數中設置發送碼率的上線發送碼率,同級周期內(1s)若發送失敗率為 0,則提速 5%;若發送失敗率小于 10%,則降速 5%。設置升速時,升速不能超過發送碼率的上線,降速不能低于 12Kbps。
3.4 數據重傳
Shaper 模塊在發送數據包的過程中極有可能發生包丟失等異常情況,本系統在 Shaper 模塊中增加重傳邏輯用以應對此類情況。設計邏輯圖如下圖所示:
Shaper 模塊在進行數據傳輸時,會根據 send()函數返回值對數據是否有丟包進行判斷。例如,在傳輸 10 個數據包的情況下,當 send()返回值為 7 * 1316 字節(1316字節為 TS 格式下的媒體元數據單位),即說明有 3 個數據包在傳輸時發生丟失,此時根據時戳將待傳輸的數據包加入重傳隊列,在下次傳輸數據時優先傳輸重傳隊列中的數據包,之后再對 Cache 模塊中的新數據隊列進行傳輸。具體重傳時間的計算公式如下:
4 流媒體服務器參數優化
Nginx 服務器的配置系統很靈活。只需通過對配置項的增加、修改即可實現第三方模塊的信息提供。將對 Nginx 服務器與內核的配置文件進行相關設置,從而實現流媒體服務器的參數優化。
4.1 流媒體服務器配置文件優化
為了提高 Nginx 服務器的性能,需對流媒體服務器進行參數調優。Nginx 可以通過修改默認安裝路徑下/usr/local/nginx/conf/nginx.conf 的 nginx.conf 文件來進行參數配置。調優模塊分為三類,全局塊、Events 塊和 HTTP 塊。
(1)全局塊,配置文件優化如下:
worker Process_num:4;
worker_cpu_affinity 0001 0010 0100 01000;
(a) worker Process_num 是 Nginx 創建的 worker 進程的個數。Nginx 中基本的網絡事件都由 worker 進程處理,所以 worker 進程的數量對 Nginx 的性能會有很大的影響。如果設置太小,則 Nginx 服務器很難應對高并發的請求數量,浪費了資源;如果設置過多會 導 致 進 程 之 間 的 頻 繁 切 換 , 造成了不必要的開銷 。一 般來說 ,通常將worker Process_num 設置為服務器CPU的內核數量。
(b) worker_cpu_affinity 是為每個 work 進程設置一個固定 CPU 內核。當 Nginx 中的每個worker 進程都處于工作狀態時,可能產生多個 worker 進程爭搶一個內核的現象,設置 worker_cpu_affinity 可以減少因選擇不同 CPU 內核產生的開銷。
(2)Events 塊,配置文件優化如下:
worker_connections:102400;
use epoll;
Events 塊對 Nginx 中事件模塊進行配置來控制和處理訪問連接。
(a) worker_connections 用來設置每個 worker 進程的最大連接數,最大連接數應與全局塊中的 worker File_limit Num 值一樣。
(b) use 用來設置事件驅動模型。在不同操作系統下選取的事件驅動模型也有所不同,對于 linux 系統來說,epoll 模型是較為高效的事件管理機制,在性能方面相對于標準事件模型 select 和 poll 要高很多。
(3)HTTP 塊主要從網絡連接設置、文件緩存設置、Socket 優化設置三部分組成。
HTTP 塊是 Nginx 配置的核心部分,對連接處理行為的設置很多都需要在此塊中進行設置,其中包括負責負載均衡的 upstream 塊,對虛擬主機進行配置的 server 塊,以及反向代理location 塊等。網絡連接設置,配置文件優化如下:
(a) 網絡連接超時設置通過設置連接超時時間上限,可以在請求連接超時后,對其進行關閉,將超時連接所占用的系統資源進行釋放。在面對高并發數量請求時,可以提供更好的資源利用率和服務效率。
tcp_nodelay on;
SO_REUSEPORT
(4)文件緩存設置,配置文件優化如下:
sendfile 指令指定 Nginx 是否調用 Linux 的系統函數 sendfile()來發送文件。如果服務器用來進行下載等對磁盤 I/O 消耗高的操作,可以設置為 off;如果對于普通應用必須設定為 on,sendfile()函數用以提高文件的發送效率。
open_file_cache 指令用于開啟文件緩存功能。 max 為緩存的數量上限,應和worker_connections數量保持一致,inactive 設定一個時間,當文件在此時間內沒被請求,則系統會刪除緩存。
open_file_cache_valid 用來指定檢查緩存有效性的時間間隔。
open_file_cache_min_uses 表示 inactive 時間內文件的最小使用次數,如果小于此值,文件將被刪除。
send_file on;
open_file_cache max = 1024 inactive = 30s;
open_file_cache_valid 60s;
open_file_cache_min_uses 3;
(5)Socket 優化設置,配置文件優化如下:
tcp_nodelay 指令開啟后,服務器將不會對數據進行緩存。reuseport指令用來設置共享 socket。
reuseport 的設置是用來解決 Nginx 中“驚群”問題。“驚群”問題是指一個連接來臨時會喚醒多個進程對其進行搶奪處理。
在連接來臨時,多個 worker 線程共享一個套接字,這時便會出現多個線程去搶占資源的情況。傳統的 Nginx 在處理這個問題時有兩種解決方式:一是配置 accept_mutex on,在 accept()函數調用之前采用鎖機制,獲得鎖的進程才有權對套接字進行處理,但鎖機制會影響服務器的性能,另外,這種方式的弊端是所有的 worker 進程都會被喚醒去爭奪鎖,會對內核資源造成浪費;二是設置 accept_mutex off,這種處理方式雖然少了鎖機制,提高了系統響應能力,但會出現“驚群”問題,在 worker 進程數增多時會對系統帶來一定性能影響。
tcp_nodelay on;
SO_REUSEPORT
注意:以上這些配置文件僅供參考,根據實際情況去優化。
(6)reuseport 允許多個套接字監聽同一端口,圖中 80 端口為 HTTP 默認端口,內核能夠在套接字中對傳入的連接進行負載均衡,自動選擇 worker 進程進行處理,而不必喚醒所有 worker 進程。采用此種方式進行 SO_REUSEPORT 配置時,需將 accept_mutex 關閉。配置如下圖所示:
在 未 開 啟SO_REUSEPORT 配置時,請求來臨時,由一個套接字 socket 進行綁定和監聽并將連接交給各個進程處理;當開啟了 SO_REUSEPORT 配置時,多個進程可以同時綁定和監聽同一個TCP/UDP 端口,請求交由哪個進程處理由內核決定,實現了在內核層面的負載均衡。未開啟和開啟SO_REUSEPORT對比圖如下:
5.Linux 內核參數優化
默認的 Linux 內核參數無法滿足高并發訪問量情況對服務器系統的要求,為了滿足特定場景的使用需要同時對 Linux 內核參數進行設置,而且當 Nginx 服務器用于不同目的時,對于 Linux 參數的要求都會有很大的不同。針對以上情況,本文介紹對 Linux 內核參數的優化,使其能夠提高 Nginx 對并發請求的服務性能。
Linux 內核參數選項是通過修改/etc 目錄下的 sysctl.conf 文件來更改
(1) fs.file--max = 999999 此參數用來限制一個進程可以同時建立的最大連接數。Nginx 服務器通過每個 worker 進程來進行實際的請求響應,所以此參數的設置會影響到 Nginx 的最大并發連接數量。
(2) net.ipv4.tcp_tw_reuse = 1 此參數用來開啟重用功能,可以設置為 1 或 0。當設置為 1 時,服務器上處于 TIME_WAIT狀態的請求連接會被系統重新建立 TCP 連接。
(3) net.ipv4.tcp_fin_timeout = 10 這個參數是用來設置保持在 FIN_WAIT_2 狀態的時間。在一個 TCP 連接關閉過程中,套接字會有一個 FIN_WAIT2 狀態到 TIME_WAIT 狀態的變化,將此參數設置為 10,可以使套接字更快的進入 TIME_WAIT 狀態。
6.總結
本文主要介紹了在CDN與流媒體服務器合作下,當流媒體數據存儲在服務器上,是如何處理,主要劃分為三大模塊,分別為數據處理模塊、數據緩存模塊、數據發送模塊,分別進行了模塊的架構設計、模塊的主要功能的講解,特別在數據發送模塊中設計了令牌桶算法(這個很重要),對于流量控制很有幫助。歡迎關注,收藏,轉發,分享。