4、流量整形原理:漏桶算法、令牌桶算法、整形与监管的区别、车载场景下的整形需求

各位好,我是老K。今天咱们聊聊流量整形。说实话,这个知识点在车载网络里特别容易被忽视,但恰恰又是决定通信质量的关键一环。

我刚开始做车载项目时,总觉得流量整形是IT领域的事,跟咱们汽车电子关系不大。直到有一次,一台ADAS样车在高速测试时,摄像头数据流突然把CAN总线给冲垮了——嗯,从那以后我再也不敢小看流量整形了。

4.1 漏桶算法:最朴素的限流思路

漏桶算法,说白了就是一个带漏洞的水桶。你往桶里倒水,不管倒得多快,水从底部漏出去的速度是恒定的。如果桶满了,多余的水就溢出去,丢掉。

在车载网络里,漏桶算法怎么用?我举个例子:

// 漏桶算法的简化实现
class LeakyBucket {
    int capacity;    // 桶容量(最大突发量)
    int leakRate;    // 漏出速率(字节/毫秒)
    int waterLevel;  // 当前水位
    long lastTime;   // 上次漏水时间
    
    bool sendPacket(int packetSize) {
        long now = getCurrentTime();
        // 先漏水:根据时间差计算漏掉了多少
        int leaked = (now - lastTime) * leakRate;
        waterLevel = max(0, waterLevel - leaked);
        lastTime = now;
        
        // 检查桶是否还能装下这个包
        if (waterLevel + packetSize <= capacity) {
            waterLevel += packetSize;
            return true;  // 允许发送
        } else {
            return false; // 丢弃或缓存
        }
    }
};

这个算法的好处是简单、稳定。输出速率绝对平滑,不会出现忽快忽慢的情况。我在做车载以太网AVB流整形时,就经常用这个思路来保证音视频流的稳定输出。

注意:漏桶算法有个硬伤——它不允许任何突发。哪怕网络空闲了很久,你想突然发一个大数据包,它也不答应。这在车载场景下有时候会出问题。

4.2 令牌桶算法:更灵活的整形方案

令牌桶算法就聪明多了。它不像漏桶那样死板,而是允许一定程度的突发。怎么做的?

想象一个桶,里面不断有令牌以固定速率往里放。每个数据包要发送,必须先拿到足够数量的令牌。如果桶里有令牌,你就可以一次性拿走很多,实现突发传输。如果令牌不够,那就得等。

// 令牌桶算法的简化实现
class TokenBucket {
    int maxTokens;      // 最大令牌数(桶容量)
    int tokenRate;      // 令牌生成速率(个/毫秒)
    int currentTokens;  // 当前令牌数
    long lastTime;      // 上次更新时间
    
    bool sendPacket(int packetSize) {
        long now = getCurrentTime();
        // 先补充令牌
        int newTokens = (now - lastTime) * tokenRate;
        currentTokens = min(maxTokens, currentTokens + newTokens);
        lastTime = now;
        
        // 检查是否有足够的令牌
        if (currentTokens >= packetSize) {
            currentTokens -= packetSize;
            return true;  // 允许发送
        } else {
            return false;  // 令牌不足,等待
        }
    }
};

我个人习惯在车载以太网网关里用令牌桶做流量整形。为什么?因为车载通信有很强的周期性特征——比如传感器数据每10ms发一次,但偶尔会有突发的大包(比如紧急事件触发的诊断数据)。令牌桶能很好地处理这种场景。

经验之谈:我曾经在一个项目中,把令牌桶的容量设得太大,结果网关在启动瞬间被大量数据包冲垮了。后来我把桶容量限制在最大帧长的2-3倍,问题就解决了。记住:令牌桶的突发能力是双刃剑。

4.3 整形与监管的区别:一字之差,天壤之别

很多新手分不清流量整形和流量监管。我刚开始也犯过这个错。其实它们的区别很简单:

对比项 流量整形(Shaping) 流量监管(Policing)
处理方式 缓存+延迟发送 直接丢弃或标记
对延迟的影响 增加延迟(缓存导致) 不增加延迟(直接丢)
适用场景 对丢包敏感的场景 对延迟敏感的场景
车载典型应用 音视频流、诊断数据 安全关键控制信号

说白了,整形是「你先等等,我慢慢发」;监管是「超了?直接扔掉,别废话」。

在车载网络里,我一般这样用:

  • 整形:用在非安全关键但需要可靠传输的场景。比如OTA升级包、日志数据。这些数据丢了要重传,不如缓存一下慢慢发。
  • 监管:用在安全关键的控制信号。比如制动指令、转向指令。这些信号延迟不得,超了就丢,丢了下个周期再发新的。

核心要点:整形和监管不是二选一的关系。我在实际项目中经常把它们组合使用——先监管过滤掉明显违规的流量,再整形平滑剩余的正常流量。这样既保证了安全性,又提高了带宽利用率。

4.4 车载场景下的整形需求:跟IT网络完全不同

你想想看,车载网络跟办公室网络能一样吗?当然不一样。车载场景有几个独特的需求:

4.4.1 确定性延迟要求

车载网络最核心的要求就是确定性。你不能说「大部分情况下延迟小于1ms」,你得说「最坏情况下延迟不超过1ms」。这对整形算法提出了很高的要求。

我做过一个测试:在CAN FD网络上,用漏桶算法做整形,最坏情况延迟比平均延迟大了3倍。后来改用时间感知整形(TAS),才把抖动控制在可接受范围内。

4.4.2 多优先级混合传输

车载网络里,控制信号、传感器数据、音视频流、诊断信息都在同一根线上跑。整形时必须考虑优先级:

  • 高优先级(如制动信号):基本不做整形,直接走快速通道
  • 中优先级(如传感器数据):做轻度整形,保证带宽但不增加太多延迟
  • 低优先级(如日志、OTA):做深度整形,充分利用空闲带宽

4.4.3 带宽资源有限

车载网络的带宽是固定的,不像IT网络可以随时扩容。CAN FD最高也就8Mbps,车载以太网虽然能到100Mbps甚至1Gbps,但跟IT网络的10G、40G比起来还是小巫见大巫。

所以整形时必须精打细算。我习惯的做法是:先做带宽预算,给每个数据流分配一个「硬上限」和「软上限」。硬上限是绝对不能超的,软上限是允许短时间突发的。

4.4.4 温度与老化影响

这个点可能很多人没想到。车载电子器件的工作温度范围很宽(-40°C到125°C),温度变化会影响晶振精度,进而影响整形算法的计时精度。

我曾经在夏天做路试时发现,车内温度到70°C后,令牌桶的速率偏差达到了15%。后来我们加了一个温度补偿模块,才把偏差控制在2%以内。

避坑指南:车载整形算法一定要考虑最坏情况。不要用「平均速率」来设计整形参数,要用「最大可能速率+安全余量」。我曾经吃过这个亏,在实验室跑得好好的,一上车就出问题——因为车载环境比实验室恶劣太多了。

4.5 小结:选对算法,事半功倍

说了这么多,总结一下我的经验:

  • 漏桶算法:适合对输出速率要求绝对平滑的场景,比如音视频流。但要注意它不允许突发。
  • 令牌桶算法:适合需要一定突发能力的场景,比如传感器数据+诊断数据的混合流。但要注意控制桶容量。
  • 整形 vs 监管:整形保可靠性,监管保实时性。根据业务需求选,也可以组合使用。
  • 车载特殊需求:确定性延迟、多优先级、有限带宽、环境适应性——这些是车载网络整形的四大挑战。

最后说一句:流量整形不是万能的。它解决的是「流量过载」的问题,解决不了「带宽不足」的问题。如果带宽本身就差得远,再好的整形算法也白搭。所以,做车载网络设计时,先把带宽预算算清楚,再谈整形策略。

下一章,咱们聊聊具体的车载网络QoS配置实战,包括CAN FD和车载以太网的配置案例。到时候我会分享一些我在项目里踩过的坑,希望对你有帮助。