ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

LTE MAC层令牌桶算法与逻辑信道优先级调优实战

LTE MAC层令牌桶算法与逻辑信道优先级调优实战 1. 从一张投诉工单说起LTE MAC层的令牌桶到底在管什么先说一个我在现场遇到过的真实场景。某个地市的用户报障说家里用了一台LTE无线路由器白天刷视频、打游戏都还正常一到晚上家里人一起用就出问题一台设备开着下载其他设备的游戏延迟直接飙到几百毫秒连微信语音都断断续续。后台抓了信令和MAC层的log把上行调度的分配过程一条条摊开看最后落在了一个很不起眼的地方——逻辑信道优先级过程里的令牌桶参数。这就是LTE MAC层令牌桶算法要解决的事。它不是一个独立的功能模块而是嵌入在MAC层逻辑信道优先级Logical Channel PrioritizationLCP过程中的一套速率控制机制。它的职责很明确给每一条逻辑信道划一条保底跑道和一块突发额度让语音、信令这类小包业务永远不会被大流量业务饿死同时又允许视频、下载这类业务在空闲时攒一点信用、集中发一发不至于把资源卡得太死。很多做外场测试的朋友会问这不是基站调度器该管的事吗其实要分两层看。调度器eNB/gNB里的Scheduler决定的是这个TTI总共给你多少上行授权而MAC层逻辑信道优先级里的令牌桶决定的是这一笔授权在终端内部、在你自己的多条逻辑信道之间怎么分。前者是外部资源后者是内部经营。终端侧分不匀外场测试的吞吐和时延数据一样会难看。这篇内容适合谁看做LTE/5G协议栈开发的、写基站调度算法的、研究终端Modem和CPE固件的以及常年跑外场做上行优化和投诉定位的。涉及到的核心词汇是LTE、MAC层、令牌桶算法我会从原理讲到参数计算再落到外场测试和无线路由器场景里的坑尽量让刚接触协议栈的人也能顺下来。2. 令牌桶算法的底层逻辑三个参数定生死2.1 令牌产生速率PBR每个逻辑信道的保底速率在LTE的逻辑信道配置里每一条逻辑信道会带一组参数其中最核心的一个叫PBRPrioritised Bit Rate优先级比特速率单位是kB/s。你可以把它理解成这条逻辑信道每秒能领到多少令牌。令牌是抽象的信用额度攒够了才能发送数据攒不够就得排队。关键在于它叫优先级位速率而不是保证位速率。PBR只保证在资源不足的时候每条逻辑信道至少能分到这么多它不保证你在资源充足时被限制在这个速率。也就是说PBR是一个下限保障不是上限封顶。真正做上限封顶的是基站侧调度器的PBR/GBR/MBR配合以及APN级别的AMBR。终端内部的令牌桶主要干的是保底这件事。每个传输时间间隔TTILTE里是1ms逻辑信道的令牌变量Bj会增加PBR乘以TTI时长这么多令牌。1ms就是0.001秒所以每TTI增加的令牌量是 PBR ÷ 1000单位是kB。这个换算后面算参数的时候会反复用到务必记清楚。2.2 桶深BSD决定了你能攒多少、突发多大第二个参数是BSDBucket Size Duration桶深持续时间单位是ms。桶的最大容量等于PBR乘以BSD。翻译成人话就是这条逻辑信道最多能攒多少令牌取决于它每秒的保底速率和它被允许攒多久。为什么要有桶深这个上限如果令牌可以无限攒一条低优先级逻辑信道在空闲很久之后突然爆发就会一次性吃掉大量资源把高优先级业务的时延搅乱。桶深就是给突发加了个天花板让信用不能无限透支。桶深的大小直接决定了令牌桶对突发的容忍度。桶深设小了业务稍微突发一下就超桶多余的令牌被丢弃突发数据只能排队等下一个TTI时延抖动变大桶深设大了突发容忍度高但低优先级业务可能攒一大笔信用后集中爆发挤压高优先级业务的空间。所以桶深是一个典型的两头都不能过的参数得根据业务的突发特性和时延要求来定。2.3 令牌桶和漏桶LTE为什么选了前者很多人会把这个机制和漏桶算法搞混或者干脆以为就是一个东西。漏桶的逻辑是不管你来多少数据我都以恒定速率往外放多余的要么丢要么缓存。它把流量整得极其平滑但代价是不允许任何突发一旦业务本身有突发特性就会额外引入排队时延。令牌桶不一样。空闲的时候令牌在桶里攒着来一波突发数据只要桶里有足够令牌就可以一次性发出去不用等。它允许突发同时用桶深给突发设了上限兼顾了平滑性和灵活性。LTE MAC层为什么选令牌桶我觉得根子在业务的突发性。视频编码有I帧P帧TCP有慢启动和拥塞窗口增长网页加载是一堆小包集中爆发这些业务天生就不是匀速的。如果用漏桶强行整流端到端时延和用户体验都会变差。令牌桶允许它们在一定范围内抢一下同时又靠PBR保住底线业务的速率这个取舍是很务实的。需要提醒的是LTE这套机制管的是终端内部的逻辑信道分配和我们在交换机上做的端口限速、和AP侧的带宽管理虽然都叫令牌桶但作用点和目的不完全一样别混着套参数。3. LTE MAC层里令牌桶的落点逻辑信道优先级过程3.1 每个逻辑信道都有一个Bj变量逻辑信道优先级过程是MAC层每个TTI都要跑一遍的。为了让令牌桶落地协议里给每条配置了PBR的逻辑信道维护一个变量Bj中文一般叫桶内令牌数或者当前信用额度初始值是0单位是字节。Bj的更新有两步每个TTI先往里加 PBR × TTI 的令牌也就是前面说的PBR÷1000 kB然后如果超过桶深上限就把它截断到桶深值。这个过程不管你这一TTI有没有被调度、有没有发数据都会执行。也就是说一条长期不发数据的低优先级逻辑信道Bj会一直攒最多攒到桶深上限就不再涨了。这里有个容易被忽略的细节Bj的累加和截断是每个TTI都做的和有没有授权无关。所以在外场测试里如果一条逻辑信道长期占用不到资源它的Bj会长时间顶在桶深上限这本身不是故障但它意味着一旦有资源这条信道会优先把攒下的信用花掉可能短时抢占高优先级业务的份额。这个现象在排查高优先级业务偶发时延尖峰的时候是很有用的线索。3.2 分配过程分两步先保底再按严格优先级吃掉剩余整个分配过程可以概括成一个两阶段的流程。第一阶段是按优先级从高到低遍历所有Bj大于0的逻辑信道给每条分配资源但分配量不超过它当前的Bj值。分完之后从Bj里扣掉实际分配的量。这一步的意义就是兑现保底速率——只要桶里有信用按优先级顺序满足你。第二阶段是如果还有剩余的上行授权没用完就按严格优先级顺序再遍历一遍所有逻辑信道这次不管Bj是多少直接按优先级把剩余资源分下去。这一步是资源有富余就尽量用满避免资源浪费。用一段伪代码把逻辑理清楚写协议栈的朋友可以直接对照实现// 每个TTI执行grant 为本TTI的上行授权字节数 void lcp_process(int grant) { // 第一步按优先级降序优先满足 Bj 0 的逻辑信道 for (lch in sort_by_priority_desc(logical_channels)) { if (lch.Bj 0) { int alloc min(lch.Bj, grant); assign_resource(lch, alloc); lch.Bj - alloc; grant - alloc; if (grant 0) break; } } // 第二步还有剩余授权按严格优先级继续分配 if (grant 0) { for (lch in sort_by_priority_desc(logical_channels)) { if (lch.has_data()) { int alloc min(lch.pending_data, grant); assign_resource(lch, alloc); grant - alloc; if (grant 0) break; } } } // 第三步更新每个逻辑信道的令牌并做桶深截断 for (lch in logical_channels) { lch.Bj lch.PBR / 1000; // 每TTI增加的令牌单位kB if (lch.Bj lch.bucket_size) { lch.Bj lch.bucket_size; } } }注意不同厂商的实现里Bj的累加可能放在分配之前也可能放在分配之后只要保证每个TTI加一次、并且按桶深截断逻辑上是一致的。对照实现时不要死抠顺序要看它最终对时延和吞吐的影响。3.3 令牌桶和BSR、调度器之间的配合关系这里必须把三者的关系摆清楚否则调参很容易调错地方。BSRBuffer Status Report是终端告诉基站我还有多少数据要发。它上报的是逻辑信道组LCG里待发送数据的总量是一个聚合值不区分每条逻辑信道里各自有多少。调度器拿到BSR之后结合信道质量、公平性、QoS等一整套逻辑决定这个TTI给这个终端多少上行授权授权大小会随信道变化剧烈波动。逻辑信道优先级过程也就是令牌桶所在的地方拿到的就是这个授权然后在终端自己内部把这些资源分给各条逻辑信道。所以分工是这样的调度器管总数令牌桶管内部分配BSR管上报需求。你调令牌桶参数影响的是内部怎么分影响不了基站给你多少。如果外场发现是授权本身就不够那再怎么调PBR也救不回来得从调度器、覆盖、干扰这些方向找。这个边界感一定要有不然现场会绕很大的弯。4. 参数怎么算PBR、BSD和实际速率的换算4.1 单位换算与桶深计算一步步来令牌桶的参数计算难点几乎全在单位上我见过不少人在这里翻车。捋一遍PBR单位是kB/sTTI是1ms即0.001s所以每个TTI往桶里加的令牌是 PBR 乘以 0.001等于 PBR ÷ 1000单位kB。桶深等于PBR乘以BSDBSD单位是ms换算成秒是除以1000所以桶深的kB数等于 PBR × BSD ÷ 1000。举个具体例子。假设一条VoLTE语音逻辑信道QCI1PBR配置为48 kB/sBSD配置为100 ms。桶深就是 48 × 100 ÷ 1000 等于 4.8 kB。每个TTI增加的令牌是 48 ÷ 1000 等于 0.048 kB也就是约49字节。VoLTE一个语音包采用AMR-WB时RTP载荷加各种头大约在几十到一百多字节量级每20ms发一个。20ms是20个TTI这段时间攒的令牌约是 0.048 × 20 等于 0.96 kB约980字节攒够一个语音包绰绰有余。桶深4.8 kB能扛住几个包的连续突发这个配置对语音来说是够用的。再看一个视频业务QCI2假设PBR512 kB/sBSD200 ms。桶深是512 × 200 ÷ 1000 等于102.4 kB。每TTI增加0.512 kB令牌也就是约524字节。视频的I帧可能几百kB甚至上兆桶深102.4 kB能扛一个中等大小的突发但扛不住一个完整I帧这意味着大I帧会被拆分到多个TTI发送会引入一点时延但不会丢包通常可以接受。算这些参数的时候我的经验是把每TTI增加多少字节这个数字算出来贴在配置表旁边因为外场排查看log的时候你一眼就能判断这个Bj增长速度合不合理比盯着kB/s的配置值直观得多。4.2 不同QCI的典型配置参考下面这张表是我把常见厂商的默认配置和外场验证过的经验值整理出来的具体项目还是要以运营商规范为准这里给的是量级参考不是唯一解。QCI业务类型典型PBR (kB/s)典型BSD (ms)桶深 (kB)说明1会话语音VoLTE48~96100~2004.8~19.2保底要够语音包节奏桶深不用太大2会话视频256~1024200~50051.2~512桶深要能扛I帧突发3实时游戏32~128100~2003.2~25.6时延敏感桶深宜小4缓冲流视频128~512300~50038.4~256允许较大突发5IMS信令16~64100~5001.6~32优先级高速率需求低9默认承载1~8300~5000.3~4低优先级兜底防饿死即可看这张表要抓住一个思路PBR是保底节奏通常贴合业务的最小稳定速率需求BSD是突发容忍度时延敏感业务BSD取小吞吐型业务BSD取大。QCI1这种语音业务PBR只要够语音包的发送节奏就行桶深也不用大因为语音要的是准时不是快。QCI2的视频业务PBR要覆盖平均码率桶深要能缓冲I帧这两者配合不好就会在视频开头卡一下。4.3 参数配置的几个硬性原则第一个原则高优先级业务PBR必须够用。所谓够用是指它的PBR要能覆盖业务最小时延下的包到达速率。VoLTE每20ms一个包那你PBR至少要能在20ms内攒够一个包。如果PBR配小了Bj涨得慢令牌攒不够语音包就得在buffer里多等几个TTI抖动和丢包就来了。第二个原则桶深不要盲目调大。桶深越大低优先级业务能攒的信用越多突然爆发时占用的资源越多高优先级业务的时延尖峰就越明显。有的现场为了把吞吐数字做上去把低优先级信道的桶深调得很大结果就是下载一起来语音质量就掉得不偿失。第三个原则参数之间要联动看。PBR和BSD单独看没意义桶深是两者乘积真正影响突发行为的是桶深。调参的时候先定桶深目标再围绕桶深去分PBR和BSD思路会清楚很多。5. 外场测试中的真实表现三种典型症状5.1 小区边缘上行受限Bj长期顶在桶深上外场测试里小区边缘的场景最能把令牌桶的问题暴露出来。用户从中心往边缘走SINR下降MCS降级基站给的上行授权越来越少。这个时候终端内部的逻辑信道拿到的资源也跟着缩水。我在路测里反复见过一个现象在弱场区域某些逻辑信道的Bj长时间顶在桶深上限不动也就是伯令牌一直是满的。很多人第一反应是桶坏了其实恰恰相反这说明这条信道一直攒令牌却花不出去因为授权太少根本轮不到它。这种情况下即使你把PBR和桶深往上调也不会有任何改善因为瓶颈在无线侧的授权不在终端内部。判断方法很简单把log里每个TTI的授权大小和Bj一起看。如果授权本身就很小甚至为零Bj又长期满仓那就是外部资源问题往覆盖、干扰、调度策略上找如果授权正常但Bj一直不动才有可能是参数或逻辑问题。这个区分能帮你省下大量无效调参的时间。5.2 VoLTE语音断续PBR配小了VoLTE断续是最典型的高优先级业务被饿死的例子。语音逻辑信道QCI1优先级最高理论上应该最先被满足。但如果PBR配得偏小Bj的token积累速度跟不上语音包的发送节奏就会出问题。具体怎么出问题语音包每20ms到一次你要在20ms内攒够一个包的令牌。如果PBR只有24 kB/s每TTI加24字节20个TTI攒480字节遇到包稍微大一点、或者RTP头、PDCP头、RLC头占得多一点就不够了。这时语音包就得等下一个20ms周期累积起来PDCP层的丢弃定时器一超包就丢了听感上就是断续。这件事我印象很深因为一开始大家怀疑是覆盖问题、是核心网问题最后查出来就是PBR配小了。教训是语音业务的PBR要按最坏情况下包在20ms内能被攒够来配宁可留点余量别抠那一点点数值。同时BSD也不用大语音不需要攒那么多信用桶深小一点反而能让令牌更快地回收到Bucket里以应对波动。5.3 LTE无线路由器下的多终端争抢令牌桶是最后一道闸回到开头那个投诉。LTE无线路由器CPE这个场景很特殊一台设备上挂着手机、平板、电视、电脑所有终端的上行流量都要先汇聚到CPE的Modem里再走LTE上行发出去。这个时候CPE内部MAC层的逻辑信道分配就成了家庭内部谁先发的最后一道闸。家庭内网里视频上传、网盘同步、游戏、语音各占一条或几条逻辑信道。如果低优先级的大流量逻辑信道桶深配大了它攒够了信用就能在某个TTI集中吃掉大量授权把游戏和语音挤到后面几个TTI表现就是游戏突然卡一下、语音突然糊一下。这类问题的定位得把CPE侧的上行MAC log和设备侧的业务流量做时间对齐看是不是某个业务爆发时正好对应了时延尖峰。我的经验是无线路由器这种多业务汇聚的场景低优先级逻辑信道的桶深要克制PBR保底够用即可不要为了单个业务的峰值吞吐把桶深撑大。宁可让大流量业务慢一点、平一点也要保证语音和游戏的时延稳定。这是家庭场景下用户体验的底线。5.4 上行突发业务打不准节奏还有一类不那么典型但挺烦人的场景TCP慢启动或者短连接小包密集的业务上行数据包一会儿一小串、一会儿又空一阵。令牌桶对这种节奏非常敏感。如果桶深太小突发一来令牌就不够多余的包只能排队。如果桶深够突发能被平滑接住用户体验就顺。排查这类问题不能只看平均值。要把短时间窗比如100ms内的包到达速率和Bj的变化对齐看看突发那一刻桶里有没有足够令牌。很多时候平均速率看着完全正常但瞬时突发没被接住用户该卡还是卡。这也是为什么我一直强调调令牌桶要看抖动和突发不能只盯着平均吞吐。6. 常见问题速查表与调参心得6.1 问题与解决思路速查现象可能原因排查方向处理建议Bj长期顶在桶深不降授权不足或该信道无数据对比每TTI授权大小属正常或外部资源问题勿盲目调参低优先级业务时延尖峰桶深过大突发抢占资源看突发TTI的资源分配调小BSD或桶深限制其突发额度高优先级业务随机丢包PBR不够令牌攒不上算每TTI令牌量对比包节奏适当上调PBR保证包节奏弱场吞吐上不去无线侧授权瓶颈看MCS、SINR、授权大小优化覆盖和调度令牌桶无关视频开头卡顿桶深扛不住I帧算I帧大小对比桶深增大BSD增大桶深容忍突发语音抖动优先级配置或PBR问题看高优先级信道是否最先被满足核对优先级映射和PBRCPE下游戏卡顿低优先级业务抢占上行对齐业务爆发与MAC分配收紧低优先级桶深和PBR上行吞吐不达预期PBR上限或调度联合限制区分终端内部限制与外部授权明确瓶颈在哪一层再动手6.2 调参的顺序和一些踩坑经验调令牌桶参数我个人的顺序是先定优先级映射再定PBR保底最后定桶深。优先级映射错了后面怎么调都别扭。确认每条逻辑信道的优先级和QCI对应关系是正确的这是地基。PBR的确定以最小时延下能攒够一个包为底线。特别是语音和信令这类小包高频业务底线算清楚再往上留百分之二三十余量基本就稳妥了。桶深靠BSD来调原则是时延敏感取小、吞吐型取大。定桶深之前先估算业务的典型突发大小比如视频I帧大约多大桶深至少要能覆盖这部分突发否则大帧会被拆散时延就会冒出来。几个我踩过的坑也一并说说。第一别照抄别家的参数。不同厂商默认优先级映射不一样业务模型也不一样抄过来的参数可能正好是错的方向。第二改完参数一定要在外场复测尤其要在弱场和多业务并发下复测实验室向好不代表外场向好。第三log采样率要够高令牌桶是每TTI级别的动作采样太粗会漏掉突发那一刻的关键信息。第四怀疑令牌桶之前先用半天时间确认不是调度器和覆盖的问题这两个方向的概率其实比令牌桶参数配错更高。6.3 关于外场测试的一点补充做外场测试的时候我习惯把上行方向的log按授权—Bj—发送三个维度做时序对齐。授权是基站给的Bj是终端内部信用的发送是实际动作。三者对齐之后资源不够信用不够分配失衡这三种问题一眼就能分辨比单看吞吐数字有用得多。尤其是LTE无线路由器这类汇聚设备内部多业务互相影响不做时序对齐根本看不出来是谁挤了谁。这个习惯帮我定位过很多次那种数据看着都对、用户就是体验差的疑难问题也让令牌桶这块的调参从玄学变成了可以有序推进的排查流程。我个人在实际操作中的体会是令牌桶这套机制的设计意图很朴素——给每条业务留一条保底的道同时留一点突发的余地剩下的交给优先级。所有参数调来调去其实都在回答同一个问题这门业务保底多少才够能突发多大才不伤别人。把这个想明白了参数就自然有了。
返回列表