## 性能基准
### 服务器的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设置)