## 性能基準
### 服務器的top圖
命令是?`top -H -p $(cat objs/srs.pid)`?,看CPU和內存。還有每個CPU的消耗情況(進入top后按數字1),比如us是用戶空間函數,sy是內核函數,si是網卡軟中斷。
### 系統的網絡帶寬圖
命令是?`dstat`?,看出入口帶寬。比如視頻平均碼率是600kbps,那么900個推流時,網卡的recv流量應該是`600*900/8000.0KBps`也就是`67.5MBps`,如果網卡吞吐率達不到預期,那么肯定會出現卡頓等問題,比如可能是系統的網卡隊列緩沖區\[18\]太小導致丟包。
### 服務器關鍵日志
命令是?`tail -f objs/srs.log |grep -e 'RTC: Server' -e Hybrid`?,查看RTC的連接數和關鍵日志,以及進程的CPU等信息。如果連接數達不到預期,或者CPU接近100%,也是有問題的。
### 服務器熱點函數列表
命令是?`perf top -p $(cat objs/srs.pid)`?,可以看到當前主要的熱點函數列表,以及每個函數所占用的百分比。性能優化一般的思路,就是根據這個表,優化掉排名在前面的熱點函數。
## 工具鏈
沒有工具鏈就無法做性能優化,查看網絡帶寬工具`dstat`,查看熱點函數工具`perf`,查看CPU工具`top`。
?`sysctl`:修改內核UDP緩沖區,防止內核丟包。?`GPERF: GCP`:使用GCP分析熱點函數的調用鏈,圖形化展示。?`taskset`:進程綁核后,避免軟中斷干擾,便于查看數據。
對于RTC,很重要的是需要把內核協議棧的緩沖區改大,默認只有200KB,必須改成16MB以上,否則會導致丟包:
~~~
sysctl net.core.rmem_max=16777216sysctl net.core.rmem_default=16777216sysctl net.core.wmem_max=16777216sysctl net.core.wmem_default=16777216
~~~
可以直接修改文件`/etc/sysctl.conf`,重啟也能生效:
~~~
# vi /etc/sysctl.confnet.core.rmem_max=16777216net.core.rmem_default=16777216net.core.wmem_max=16777216net.core.wmem_default=16777216
~~~
如果perf熱點函數比較通用,比如是`malloc`,那我們可能需要分析調用鏈路,看是哪個執行分支導致`malloc`熱點,由于SRS使用的協程,`perf`無法正確獲取堆棧,我們可以用`GPERF: GCP`工具:
~~~
# Build SRS with GCP./configure --with-gperf --with-gcp && make# Start SRS with GCP./objs/srs -c conf/console.conf# Or CTRL+C to stop GCPkillall -2 srs# To analysis cpu profile./objs/pprof --text objs/srs gperf.srs.gcp*
~~~
圖形化展示時,需要安裝依賴`graphviz`:
~~~
yum install -y graphviz
~~~
然后就可以生成SVG圖,用瀏覽器打開就可以看了:
~~~
./objs/pprof --svg ./objs/srs gperf.srs.gcp >t.svg
~~~
還可以使用`taskset`綁定進程到某個核,這樣避免在不同的核跳動,和軟中斷跑在一個核后干擾性能,比如一般軟中斷會在CPU0,我們綁定SRS到CPU1:
~~~
taskset -pc 1 $(cat objs/srs.pid)
~~~
> Note:如果是多線程模式,可以增加參數`-a`綁定所有線程到某個核,或者在配置文件中,配置`cpu_affinity`指定線程的核。
## 內存交換性能
現代服務器的內存都很大,平均每個核有2GB內存,比如:
* ECS ecs.c5.large\[23\], 2CPU 4GB 內存,1Gbps內網帶寬。
* ECS ecs.c5.xlarge\[24\], 4CPU 8GB 內存,1.5Gbps內網帶寬。
* ECS ecs.c5.2xlarge\[25\], 8CPU 16GB 內存,2.5Gbps內網帶寬。
還有其他型號的,比如G5\[26\]每個核是4GB內存,比如R5\[27\]更是每個核高達8GB內存。這么多內存,對于無磁盤緩存型的網絡服務器,直播轉發或者SFU轉發,一般內存是用不了這么多的,收包然后轉發,幾乎不需要緩存很久的數據。
因此,線上的視頻服務器一般內存都是很充足的,有些情況下可以用內存來優化性能的地方,就可以果斷的上內存緩存(Cache)策略。
比如,在直播播放時,SRS有個配置項叫合并寫入(發送):
## 查找優化
STL的vector和map的查找算法,已經優化得很好了,實際上還是會成為性能瓶頸。
比如,RTC由于實現了端口復用,需要根據每個UDP包的五元組(或其他信息),查找到對應的Session處理包;Session需要根據SSRC找到對應的track,讓track處理這個包。
比如,SRS的日志是可追溯的,打印時會打印出上下文ID,可以將多個會話的日志分離。這個Context ID是存儲在全局的map中的,每次切換上下文需要根據協程ID查找出對應的上下文ID。
如果每個包都需要這么運算一次,那開銷也是相當可觀的。考慮根據UDP包查找Session,如下圖:
## UDP協議棧
在直播優化中,我們使用`writev`一次寫入大量的數據,大幅提高了播放的性能。
其實UDP也有類似的函數,UDP的`sendto`對應TCP的`write`,UDP的`sendmmsg`對應TCP的`writev`,我們調研過UDP/sendmmsg\[30\]是可以提升一部分性能,不過它的前提是:
* 在Perf中必須看到UDP的相關函數成為熱點,如果有其他的熱點比UDP更耗性能,那么上sendmmsg也不會有改善。
* 一般并發要到2000以上,UDP協議棧才可能出現在perf的熱點,較低并發時收發的包,還不足以讓UDP的函數成為熱點。
* 由于不能增加延遲,需要改發送結構,集中發給多個地址的UDP包統一發送。這對可維護性上是比較大的影響。
還有一種優化是GSO,延遲分包。我們調研過UDP/GSO\[31\],比`sendmmsg`提升還要大一些,它的前提是:
* 和`sendmmsg`一樣,只有當UDP相關函數成為perf的熱點,優化才有效。
* GSO只能對一個客戶端的包延遲組包,所以他的作用取決于要發給某個客戶端的包數目,由于RTC的實時性要求,一般2到3個比較常見。
還有一種優化的可能,就是ZERO\_COPY,其實TCP的零拷貝支持得比較早,但是UDP的支持得比較晚一些。收發數據時,需要從用戶空間到內核空間不斷拷貝,不過之前測試沒有明顯收益,參考ZERO-COPY\[32\]。
*****
- 前言
- 服務器開發設計
- Reactor模式
- 一種心跳,兩種設計
- 聊聊 TCP 長連接和心跳那些事
- 學習TCP三次握手和四次揮手
- Linux基礎
- Linux的inode的理解
- 異步IO模型介紹
- 20個最常用的GCC編譯器參數
- epoll
- epoll精髓
- epoll原理詳解及epoll反應堆模型
- epoll的坑
- epoll的本質
- socket的SO_REUSEADDR參數全面分析
- 服務器網絡
- Protobuf
- Protobuf2 語法指南
- 一種自動反射消息類型的 Protobuf 網絡傳輸方案
- 微服務
- RPC框架
- 什么是RPC
- 如何科學的解釋RPC
- RPC 消息協議
- 實現一個極簡版的RPC
- 一個基于protobuf的極簡RPC
- 如何基于protobuf實現一個極簡版的RPC
- 開源RPC框架
- thrift
- grpc
- brpc
- Dubbo
- 服務注冊,發現,治理
- Redis
- Redis發布訂閱
- Redis分布式鎖
- 一致性哈希算法
- Redis常見問題
- Redis數據類型
- 緩存一致性
- LevelDB
- 高可用
- keepalived基本理解
- keepalived操做
- LVS 學習
- 性能優化
- Linux服務器程序性能優化方法
- SRS性能(CPU)、內存優化工具用法
- centos6的性能分析工具集合
- CentOS系統性能工具 sar 示例!
- Linux性能監控工具集sysstat
- gdb相關
- Linux 下如何產生core文件(core dump設置)