2026/10/24 22:28:51

RLC协议状态机与定时器:LTE可靠传输的底层逻辑

RLC协议状态机与定时器:LTE可靠传输的底层逻辑 简介面向LTE无线接入网研发、协议栈实现与测试岗位工程师的学习资料聚焦TD-LTE数字蜂窝移动通信网Uu接口中的RLC协议。内容依据中国通信标准化协会技术报告系统规定E-UTRA RLC子层结构、RLC实体、上下层业务关系、功能划分以及与对等层通信的协议数据元、格式和参数并说明未知或错误协议数据的处理方式同时覆盖确认模式等关键机制可帮助读者理解RLC在数据传输与差错校正中的职责边界。资源包共1个doc文件约1.74MB为中文协议文本适合作为协议查阅与实现对照的案头文档。目前已有493人学习适合需要梳理Uu接口协议分层、准备协议栈开发或测试用例设计的读者参考使用。1. RLC 协议为什么 LTE 的“可靠传输”不靠重传次数堆出来很多人第一次翻 LTE 协议栈会觉得 RLC 这一层“没什么存在感”——上有 PDCP 做加密和头压缩下有 MAC 做调度和 HARQRLC 夹在中间好像只是把数据切一切、编个号。但真正在链路层调过参数的人会告诉你掉话、速率上不去、切换后业务卡顿最后追下去十有八九落在 RLC 的状态变量和定时器上。RLC 协议真正解决的问题不是“重传”而是在一个底层 HARQ 已经会重传、上层又要求按序交付的环境里如何用最少的反馈把“哪些收到了、哪些没收到、什么时候该等、什么时候该放弃”讲清楚。这份 TD-LTE Uu 接口技术要求第 7 部分把 TM、UM、AM 三种实体、发送/接收窗口、t_Reordering、t_PollRetransmit、t_StatusProhibit 这些机制一条条写成了可实现的规范。搞懂它你才能明白为什么 LTE 的可靠传输不是靠“多传几遍”堆出来的而是靠窗口和定时器把不确定性收敛掉。2. 三种模式的分工TM、UM、AM 到底在取舍什么2.1 TM 实体为什么它连 RLC 头都不给透明模式是三种模式里最“反直觉”的一个。按规范描述发送 TM RLC 实体从上层收到 RLC SDU 后不做分段、不做级联也不在 TMD PDU 里加任何 RLC 头直接往下层交。接收侧同样收到 TMD PDU 就原样往上分发。这意味着 TM 实体根本不提供序列号也就没有重排序、没有重复检测、没有重传。那它存在的意义是什么看它绑定的逻辑信道就明白了BCCH、DL/UL CCCH、PCCH。这些信道传的是广播信息、公共控制信息和寻呼信息特点是“一次性、面向小区内所有终端、对时延敏感但对个别丢失不敏感”。如果给寻呼消息加一个 RLC 头再编个 SN接收侧还得维护窗口状态纯属给终端增加无谓的状态机负担。TM 的设计动机就是当上层业务本身不需要 RLC 级别的可靠性保证时把这一层的开销压到零。这里有个容易踩的细节TM 不分段意味着上层交下来的 SDU 必须能塞进下层通知的传输机会里。实际实现中TM 实体通常只处理固定或受控大小的消息不会出现“SDU 太大塞不下”的情况。如果你在实现里给 TM 加了分段逻辑那已经不是规范里的 TM 了。2.2 UM 实体单向可靠性的边界在哪里UM 实体绑定在 DL/UL DTCH 上做分段、级联、加 RLC 头、编 SN接收侧做重复检测、重排序、丢失检测但不请求重传。这是它和 AM 最本质的区别UM 承认“有些 PDU 就是会丢”它只负责把收到的按序整理好、把等不到的东西在合理时间内放过去而不是死等。规范里 UM 接收侧维护一个以 VR(UH) 为基准的重排序窗口窗口范围是(VR(UH) – UM_Window_Size) SN VR(UH)。收到一个 UMD PDU 时先判断它是否落在窗口内、是否重复再决定丢弃还是放进接收缓存。放进去之后如果这个 SN 落在窗口外就推进 VR(UH)把窗口外能重组的 SDU 按 SN 升序往上交如果 VR(UR) 落在窗口外就把 VR(UR) 拉回VR(UH) – UM_Window_Size。这一套状态推进的逻辑核心目的只有一个不让一个丢失的 PDU 把整个接收缓存无限期卡住。t_Reordering 就是那个“后悔药”。当 VR(UH) VR(UR)说明有空洞启动定时器超时后直接把 VR(UR) 推到 VR(UX)的第一个未收到 SN把空洞之前能交的都交上去。这样即使中间丢了一个包后续数据也不会被永久阻塞。UM 的取舍很清晰用“可能丢一点”换“不会因为一个包卡死整条链路”适合语音、流媒体这类对时延敏感、对少量丢包可容忍的业务。2.3 AM 实体ARQ 和 HARQ 为什么要叠两层AM 实体是三种模式里状态最复杂的发送部分和接收部分各自维护窗口和一组状态变量。发送侧窗口由 VT(A) 和 VT(MS) 界定VT(A) SN VT(MS)内的 PDU 才允许下发接收侧窗口由 VR(R) 和 VR(MR) 界定。AM 同时支持分段、级联、重分段、ARQ 重传、轮询和状态报告。一个常见疑问是MAC 层已经有 HARQ 了为什么 RLC 还要做 ARQ因为两者解决的问题不在一个时间尺度上。HARQ 是快速反馈、基于传输块的重传次数有限失败后就把“这个块没救回来”的事实往上报RLC ARQ 是慢速反馈、基于 PDU 序列号的它负责把 HARQ 漏掉的那些洞补上。规范里 AM 发送部分明确写了“传输 RLC 控制 PDU 优先于数据 PDU重传数据 PDU 优先于新数据 PDU”这个优先级顺序就是为 ARQ 服务的状态报告先走欠的账先还新数据往后排。AM 的重分段能力也值得单独说。当一个待重传的 AMD PDU 塞不进当前传输机会时发送部分可以把它重新分段成多个 AMD PDU 段而且规范明确写了“重分段的分段数量没有限制”。这给了实现很大的灵活性底层给的授权忽大忽小RLC 不用死等一个刚好合适的传输机会而是把大 PDU 拆小分批送。代价是接收侧要按“字节段序号”来管理重复检测比 UM 的整 PDU 粒度复杂得多。3. 状态变量与窗口RLC 的“账本”是怎么记的3.1 UM 接收侧的四个变量和一次收包决策UM 接收侧的核心状态变量是 VR(UR)、VR(UH)、VR(UX)。VR(UR) 是“下一个期望按序收到的 SN”VR(UH) 是“已收到的最高 SN 加一”VR(UX) 是 t_Reordering 启动时记下的快照。收到 SN x 的 UMD PDU 时决策顺序大致如下收到 SN x 的 UMD PDU 若 VR(UR) x VR(UH) 且 x 之前已收到 - 丢弃重复 若 (VR(UH) - UM_Window_Size) x VR(UR) - 丢弃窗口外旧包 否则 - 放入接收缓存 放入缓存后 若 x 落在重排序窗口之外 VR(UH) x 1 重组并向上分发窗口外可交付的 SDU 若 VR(UR) 落在窗口之外 VR(UR) VR(UH) - UM_Window_Size 若缓存中存在 SN VR(UR) 的 PDU VR(UR) 推进到下一个未收到的 SN 重组并分发 SN 新 VR(UR) 的 SDU 若 t_Reordering 在运行且满足停止条件 停止并重置 t_Reordering 若 t_Reordering 未运行且 VR(UH) VR(UR) 启动 t_ReorderingVR(UX) VR(UH)这段伪代码对应规范 5.1.2.2.2 和 5.1.2.2.3 两节。几个参数的含义需要说清楚UM_Window_Size决定了接收侧最多能容忍多大的乱序范围窗口越大抗乱序能力越强但接收缓存和状态维护成本越高VR(UX)的作用是给 t_Reordering 超时后的推进设一个下界避免超时后把还没等到的包直接跳过太多。t_Reordering 超时时VR(UR) 被推到“SN VR(UX) 的第一个未收到 PDU”然后如果还有空洞就重启定时器。这套逻辑的本质是用定时器把“等”这件事量化等多久由 VR(UX) 和窗口共同决定而不是无限等。3.2 AM 发送窗口VT(A)、VT(S)、VT(MS) 三者的关系AM 发送侧的状态变量更多但核心就三个VT(A) 是“最早未被肯定应答的 SN”VT(S) 是“下一个新 PDU 要用的 SN”VT(MS) 是“发送窗口上界”满足VT(MS) VT(A) AM_Window_Size。发送窗口的有效范围是VT(A) SN VT(MS)任何 SN 落在窗口外的数据 PDU 都不允许下发。这个窗口机制解决的是“发送方不能无限往前跑”的问题。如果没有窗口发送方可以一直发新数据接收方的缓存和状态变量会无限增长而且一旦某个早期 PDU 丢了后面所有 PDU 都得在接收侧等着重排序压力全压在接收端。窗口把“在途未确认数据”的数量限制住让收发双方的状态空间有界。收到肯定应答时如果应答的 SN 等于 VT(A)发送部分就把 VT(A) 推进到“VT(A) 到 VT(S) 范围内最小的未被肯定应答的 SN”。这里有个容易忽略的点规范说的是“最小的未被肯定应答的 SN”不是简单地 VT(A)1。因为 STATUS PDU 可能一次性确认多个 PDU也可能有空洞VT(A) 必须跳到第一个真正没被确认的位置。如果某个 RLC SDU 的所有相关 AMD PDU 都被确认了还要向上层发“发送成功指示”——这就是 AM 模式对 PDCP 的交付保证。3.3 AM 接收窗口与字节段粒度AM 接收侧的窗口由 VR(R) 和 VR(MR) 界定VR(R) SN VR(MR)为窗口内。和 UM 不同的是AM 的重复检测粒度是字节段一个 AMD PDU 可能被重分段成多个段接收侧要记录每个 SN 下哪些字节段已经收到。规范 5.1.3.2.2 写得很明确收到包含 SNx 的 AMD PDU 字节段 y 到 z 的 PDU 时如果 x 在窗口外或 y 到 z 之前已收到丢弃否则放入缓存并把其中重复的字节段丢掉。这个设计直接来自 AM 的重分段能力。如果只按整 PDU 做重复检测重分段后的段就没法正确合并。字节段粒度让接收侧可以“拼图”同一个 SN 下不同段可能从不同传输机会到达只要所有字节段凑齐这个 AMD PDU 就算完整收到。VR(MS) 就是用来跟踪“哪些 SN 还没凑齐所有字节段”的t_Reordering 超时后 VR(MS) 被更新为“SN VR(X) 的第一个未凑齐的 PDU”触发状态报告把缺口告诉发送方。4. ARQ 与轮询STATUS 报告什么时候发、发给谁4.1 轮询的触发条件不是想发就发AM 发送部分通过 P 域poll 位触发对等实体回 STATUS 报告。规范给了几类触发条件PDU_WITHOUT_POLL pollPDU、BYTE_WITHOUT_POLL pollByte、发送后发送缓存和重传缓存都空、或者没有新数据能发窗口延迟。这几个条件覆盖了不同场景前两个是“发够了就问问”后两个是“没得发了赶紧确认一下好推进窗口”。轮询不是免费的。每发一个带 P 域的 PDU就要启动或重启 t_PollRetransmit如果对等实体没回 STATUS定时器超时后要重传并再次轮询。所以 pollPDU 和 pollByte 设得太小STATUS 报告会过于频繁反向链路开销上去设得太大窗口推进慢吞吐受影响。这是典型的参数调优取舍没有放之四海皆准的值。4.2 STATUS 报告的触发与禁止接收侧触发 STATUS 报告的来源有三类收到 P 域为 1 的 PDU、t_Reordering 超时检测到接收失败、以及规范里提到的其他触发。但触发不等于立刻发还要过 t_StatusProhibit 这一关如果 t_StatusProhibit 没在运行就在下一个传输机会构造并下发 STATUS PDU如果在运行就等它超时后的第一个传输机会再发而且期间多次触发也只发一个。这个“状态禁止定时器”的设计动机是防止 STATUS 风暴。设想接收侧连续收到多个带 P 域的 PDU如果每个都立刻回一个 STATUS反向链路会被状态报告淹没而且这些报告内容高度重叠。t_StatusProhibit 把反馈合并、限频用一点反馈延迟换反向链路效率。规范里还特别注了一句P 域为 1 的 PDU 如果 x VR(MS) 或 x VR(MR)触发 STATUS否则延迟触发直到条件满足——这是为了保证状态报告在 HARQ 重排序之后发避免基于乱序到达的中间状态做出错误判断。4.3 重传计数与 maxRetxThresholdAM 发送部分对每个 AMD PDU 维护 RETX_COUNT。首次重传时置 0之后每次“该 PDU 或它的部分不再等待重传”时加一。当 RETX_COUNT 达到 maxRetxThreshold向上层指示“已达到最大重传”。这个机制是 RLC 的“止损线”ARQ 不能无限重传否则一个永远收不到的 PDU 会把整个承载卡死。达到阈值后往上报告由上层决定是重建、释放还是别的处理。这里有个实现上的坑RETX_COUNT 的加一条件是“不再等待重传”而不是“每次重传就加一”。因为一个 PDU 可能被重分段成多个段分多次发送规范用“不再等待重传”这个状态来界定一次完整的重传尝试避免分段导致计数虚高。5. 避坑与排查RLC 实现里最容易翻车的几件事5.1 现象切换后业务卡住STATUS 报告一直不发原因通常是 t_StatusProhibit 配置过大或者状态报告触发条件判断有误。切换过程中接收侧可能积压了多个触发事件如果 t_StatusProhibit 没超时这些触发会被合并延迟。排查时先看接收侧是否在 t_StatusProhibit 运行期间持续触发但从未下发 STATUS PDU再看 VR(MS) 是否长时间不更新。解决方式是核对 t_StatusProhibit 的配置值和触发逻辑确认“延迟触发直到 x VR(MS) 或 x VR(MR)”这个条件没有被实现成永久等待。5.2 现象UM 业务偶发大面积乱序交付原因多半是 t_Reordering 超时处理里 VR(UR) 推进逻辑写错。规范要求超时后 VR(UR) 更新为“SN VR(UX) 的第一个未收到 PDU 的 SN”如果实现里误写成“VR(UX) 本身”或“VR(UH)”就会把还没等到的包直接跳过造成上层看到空洞。排查时抓接收侧状态变量日志对比超时前后 VR(UR)、VR(UX)、VR(UH) 的变化是否符合规范 5.1.2.2.4 节。解决是按规范逐条核对状态推进顺序特别注意“先更新 VR(UR)再重组分发再判断是否重启定时器”这个次序。5.3 现象AM 重传次数异常增长RETX_COUNT 很快打满常见原因是重分段后 RETX_COUNT 的加一条件判断错误。如果实现里每发一个分段就加一一个 PDU 被拆成多段重传几次就会虚高到阈值。规范说的是“该 PDU 或它的部分不再等待重传”时才加一。排查时看 RETX_COUNT 的增长是否和“完整重传尝试次数”一致而不是和“分段发送次数”一致。解决是把计数点放在“一次重传尝试结束”的位置而不是每次下发分段时。5.4 现象窗口延迟导致吞吐上不去发送侧 VT(MS) 长时间不推进新数据发不出去表现为“有数据但发不了”。根因可能是 STATUS 报告丢失或轮询没触发。检查 pollPDU、pollByte 是否设得过大导致长时间不轮询以及 t_PollRetransmit 超时后是否正确重传并重新轮询。另一个可能是接收侧 VR(MS) 更新逻辑有误导致状态报告里漏报缺口。排查时同时看发送侧 VT(A)/VT(S)/VT(MS) 和接收侧 VR(R)/VR(MS) 的日志确认缺口是否被正确报告和确认。5.5 现象TM 承载上出现“SDU 太大塞不下”TM 不分段如果上层交下来的 SDU 超过下层传输机会能承载的大小实现里没有合法处理路径。这通常不是 RLC 本身的问题而是上层对 TM 承载的使用方式不对或者传输机会通知的大小计算有误。排查时确认该承载是否真的应该用 TM以及下层通知的 RLC PDU 总大小是否包含了必要的开销。解决要么调整上层数据大小要么重新评估该业务是否适合 TM。6. 设计取舍RLC 为什么把复杂度放在状态机上回头看这份规范RLC 最值得琢磨的地方不是某个具体过程而是它把“可靠性”拆成了几层不同时间尺度的机制HARQ 管快速重传RLC ARQ 管慢速补洞t_Reordering 管乱序容忍t_StatusProhibit 管反馈限频窗口管状态有界。每一层都在做一个取舍——用多少状态、多少延迟、多少反馈开销换多少可靠性。一个有意思的对比是 UM 和 AM 的接收侧。UM 只有 VR(UR)、VR(UH)、VR(UX) 三个变量重复检测是整 PDU 粒度AM 多了 VR(R)、VR(MR)、VR(MS)、VR(H)、VR(X)重复检测细到字节段。这个复杂度差异不是随意的而是由“是否支持重传和重分段”决定的一旦允许重传和重分段接收侧就必须能表达“这个 SN 下哪些字节收到了、哪些没收到”状态空间自然膨胀。规范没有试图用一套统一的状态机覆盖三种模式而是让 TM 极简、UM 中等、AM 完整各取所需。另一个取舍是定时器的角色。t_Reordering、t_PollRetransmit、t_StatusProhibit 三个定时器分别对应“等乱序”“等状态”“限反馈”它们都不是为了“保证正确”而存在而是为了“在不确定的情况下做出可接受的决策”。协议不能假设底层永远不丢包、不能假设对等实体永远及时回复所以用定时器把“等多久”变成一个可配置、可验证的量。这也解释了为什么 RLC 的参数调优这么依赖场景定时器值本质上是把业务特征时延容忍度、丢包率、往返时间编码进协议行为里。我自己的习惯是每次碰到 RLC 相关的异常先把收发两侧的状态变量按时间轴拉出来对照规范里状态推进的条件逐条核对而不是先去调定时器参数。因为大多数“玄学”问题最后都能在某个状态变量的推进条件里找到根因——定时器只是把问题暴露出来的那个触发器。希望这份规范里的状态机和过程描述能帮你在下次排查链路层问题时少走一点弯路。本文还有配套的精品资源点击获取