2024年1月21日星期日

udpxy参数设置误区

发现udpxy转发的视频流卡顿/花屏,要不要调整一下参数?
先说一下结论:调整参数没啥用,还很容易适得其反

之前折腾过udpxy的参数,发现几乎没有什么效果,最近由于某个原因看了一下udpxy源码,发现之前存在很多理解上的问题,他这个文档写的非常简略,所以很容易误导,记录一下以备大家继续走弯路。
udpxy的设计是一个单线程处理模式,其核心逻辑是这样工作的,先从源socket读一个或者多个数据包(man文档中叫messages),然后根据不同的协议处理一下,对于RTP协议来说就是去掉packet的header和最后的padding字节,然后把写入HTTP端TCP流,然后再去读后面的数据包,无限循环。这个设计非常简单而且有效,但是也存在一些容易误会的地方。

首先说一下常见的 -B 和 -R 参数,看文档写的是:
-B <sizeK> Buffer size (65536, 32Kb, 1Mb) for inbound (multicast) data [default = 2048 bytes].
-R <msgs> Maximum number of messages to buffer (-1 = all) [default = 1].

看代码发现,这两个参数其实是有关联的,这里的buffer是指接收到多播数据之后处理时的buffer,而一次接受和处理多少个多播消息(message),受控于后面这个参数,如果不改后者,前者设置再大也是没有意义的。而且如果 msgs * 1500 (MTU) 如果大于max buffer size的话,也会直接调大max buffer size,所以本质上只要有这个 -R 参数即可,前面这个选项有点冗余。另外现在很多IPTV流都是MPEG-TS流,这个时候message大小大概在1300多,一次处理一个message和多个message在现在的路由器CPU下性能差距并不大,而一次多读message可能还需要额外的等待,得不偿失。

紧跟着上面参数的还有一个 -H 参数,这个参数是指在数据处理过程中,最多处理时长,默认为1s,超过这个时间就不会继续从多播socket读后续的消息,而是直接转发。这个参数的意义可能仅仅在于如果上面的最大消息数设置过大时,避免处理时间过长导致问题,但对于现在的硬件来说,这个基本上也没啥用。

还有一个参数是 -M ,从文档来说是隔一段时间就重新renew一下多播组的订阅关系,这个参数仅仅在看了一段时间后突然没信号了这种情况才有意义,现在我们大部分IPTV都不会存在这个问题,反而因为重新renew,有可能导致消息的中断和重发,出现问题。

由于UDP是不可靠传输协议,所以RTP有个设计是每个消息包含一个序列号,让接收端可以根据这个序列号重排序,不过udpxy并没有实现重排序,所以如果发生了偶然的需要重排序的情况,udpxy发给下游的数据还是按照接收顺序发送的,这样就可能导致花屏和短暂卡顿,由于udpxy的作者已经明确不维护这个程序了,所以这个问题可能只能等别的项目来解决了。