SRS-RTMP合并读
作者:罗上文,微信:Loken1,公众号:FFmpeg弦外之音
SRS 为了提高 RTMP 上行的性能,开发出了 Merged-Read 的功能。Merged-Read 可以减少 TCP read 的次数,因为每次读 TCP 通道,都是一次系统调用。
减少 TCP read 的次数,性能就提升了。开启 Merged-Read 的方法如下:
上图有有两个选项,mr 就是开不开启 Merged-Read,而 mr_latency 是延迟,默认值是 350ms,这个延迟其实就是 sleep 多久。
如果某一次 SRS 从 TCP 通道里面拿到的数据量少于 SRS_MR_SMALL_BYTES
(4096)字节, SRS 就会 sleep 350毫秒。就是这个意思。
我们来看一下这些配置在 SRS 代码里的应用,如下:
可以看到,SRS 有一个 on_read 函数,如果读到的数据太少,他就会休眠。休眠 350ms 之后,TCP 通道里面基本就会有 350ms 的数据量了,那下次读 TCP 通道,就会一次性拿到更多的数据。
其实无论开不开启 Merged-Read ,SRS 都是一次性把 TCP 通道的数据读出来,然后放到 buffer 的。虽然 RTMP chunk 需要经过 3 次 read 才能读完整,但是这 3 次 read 通常是在内存读的,而不是读 3 次 TCP 通道。
因为 RTMP 有 chunk 的机制,为了节省流量,导致他的头部是变长的。读取一个完整的 chunk,需要先读取一字节的数据,前面 2 位决定 这个 chunk 的头部长度。假设头部长度是 12,就需要继续读取 11 字节的数据,因为之前已经读了一个字节。
经过两次读取,才能拿到 12 字节的完整头部,然后才能知道 Body Size 的大小,假如是 143 字节,又需要继续读取 143 字节的 Body 数据,这样才算读完一个 chunk。
这个过程用到的函数如下:
上面一共读了 3 次 ,但是这 3 次通常不是全部次从 TCP 通道读数据,他们是从 buffer
里面读的。
关于 FFmpeg 是怎么把一条消息拆成多个 chunk 发送的,SRS 又是怎么把多个 chunk 合并成一个消息的,请阅读《FFmpeg是如何生成connect请求的》《SRS是怎么解析connect包的》
参考资料: