令牌桶重置引发的诡异现象

295 阅读2分钟

前情简介

这个故事讲起来可能有点费事,前前后后涉及到的东西比较多,我希望尽量能把故事讲清楚,不足之处,还请各位看官包涵。

首先说一下令牌桶

令牌桶是一种常用的流量控制技术。令牌桶本身没有丢弃和优先级策略。原理:
1.令牌以一定的速率放入桶中。
2.每个令牌允许源发送一定数量的比特。
3.发送一个包,流量调节器就要从桶中删除与包大小相等的令牌数。
4.如果没有足够的令牌发送包,这个包就会等待直到有足够的令牌(在整形器的情况下)或者包被丢弃,也有可能被标记更低的DSCP(在策略者的情况下)。
5.桶有特定的容量,如果桶已经满了,新加入的令牌就会被丢弃。因此,在任何时候,源发送到网络上的最大突发数据量与桶的大小成比例。令牌桶允许突发,但是不能超过限制。

画个图可能更直观: 啊,我好像不会画高大上的图啊,将就一下。。

说完令牌桶,再说一下我的应用场景,同样,画个图吧:

大致流程如上图所致,具体的过程更为复杂一些。

应用场景:

奇怪的现象是,当server-phone旋转后,偶现client端屏幕画面卡死现象。

案情侦破

猜测可能的原因:

  • client 解码模块出现异常
  • server 编码模块出现异常
  • server 没有收到client的request
令牌数量VideoSource帧用于编码的帧发送出去帧
requestinputdrawingoutput

逻辑是这样的:

收到令牌: request++
|
|
收到Input(且 request大于0时):request--, drawing++
|
|
监听到encoder的output: drawing++

理论上

request = drawing = output

input 会由于没有request的情况被丢弃

VideoEncoder 收到图像帧到编码完成,输出适用于在网络上传输的 H.264 data 是一个耗时过程。

当屏幕旋转时,由于 ***VideoEncoder*** 会被销毁,然后再创建。

当旋转屏幕时

有drawing未被output --> 丢帧
丢帧                --> client收不到数据
client收不到数据    --> 不再产生令牌request
不再产生令牌request --> server收不到request
server收不到request --> 不再进行drawing

所以解决办法就是,重置Encoder时,要重新计算request:

reqeust = request + drawing;
drawing = 0;

案件总结

要谨慎小心对待每一个异步过程。