<!-- title: 僵尸上下文：核心网排障实录 -->

# 僵尸上下文：核心网排障实录

## 概述

用户手机显示“已注册”却上不了网，换了新机型才复现；批量测试500台终端只成功375台，报错却指向“签约不允许”——这类现象诡异、日志打架、重启单组件就好的“幽灵故障”，正在成为5G SA核心网运维的新常态。本文以开源核心网Open5GS社区2026年的两个真实工单为解剖样本，完整还原从现象、误导性告警、日志证据链到根因确认的全过程：一例是gNB SCTP闪断后残留的“僵尸UE上下文”，一例是UDM订阅池被非正常下线的终端慢性“漏气”耗尽。两个案例指向同一个运维命题：SBI时代，故障点、告警点与用户感知点经常不在同一个网元上。

## 目录

- 一、故障现场：两通看似不相干的工单
- 二、案例一解剖：SCTP闪断与僵尸上下文
- 三、案例二解剖：订阅池的慢性漏气
- 四、方法论：把两个案例拧成一套排障打法
- 五、给核心网运维人的四条实战启示
- 六、结语

## 一、故障现场：两通看似不相干的工单

2026年4月19日，Open5GS社区（GitHub约2700星的开源5G核心网项目）收到一份数据完整的工单（#4427）：某专网环境，商用5G SA基站（TDD制式，n77频段），核心网为Open5GS v2.7.6运行在Ubuntu 22.04上，终端是一台插了双卡的iPhone 17 Pro Max——一张专网eSIM，一张商用SIM。

现象非常有欺骗性：基站做小区重配置（内部执行lock/unlock，SCTP关联随之断开再重建），重连后gNB重新发起NG Setup并被AMF接受，iPhone重新注册成功，AMF日志里清楚地打印着"Registration complete"。随后iPhone请求PDU会话，SMF正常创建会话、分配了IP地址。一切都对，唯独上不了网。

用户面验证更是把水搅浑：从UPF向UE的IP地址发ping是通的，但ogstun接口上抓不到任何属于该UE的报文——控制面说“会话在”，用户面说“包不来”。iPhone侧显示已附著，每约16秒发起一次重试，反复失败。最诡异的是对照组：同一小区里的iPhone 14完全没有这个问题。

七周后，9月13日，第二份工单（#4789）进来，画风完全不同。一位工程师用Open5GS 2.7.5在Kubernetes单节点上搭了一套完整核心网（AMF/SMF/UDM/UDR/AUSF/NRF/SCP/PCF/BSF全部2.7.5），用PacketRusher做批量注册压测：1台、10台、25台、50台、100台、200台UE，全部干净通过；到500台，只有375台注册成功，其余被拒。UE侧收到的拒绝原因是`5GMM cause: 5GS services not allowed`——5GS业务不允许。

“services not allowed”这个cause，在任何一本教材里都指向签约数据问题：该用户没开户、号段没导入、签约被限制。但这位作者核对后发现签约数据没有任何问题，而且一个现象暴露了真相：**只重启UDM一个组件，其他什么都不动，同样的500台立刻500/500全部通过**。

375不是当前这轮压测的容量上限，而是前几轮测试留下的“遗产”。有一个池子被之前的测试悄悄填满了。

两份工单，一个关于“单台新型手机上不了网”，一个关于“批量注册莫名被拒”，看似不相干。往深处剖开，它们是同一个病灶的两个切面。

## 二、案例一解剖：SCTP闪断与僵尸上下文

### 事件时间线

| 时间点 | 事件 | 关键证据 |
| --- | --- | --- |
| T0 | 基站小区重配置，内部lock/unlock | SCTP关联秒级断开 |
| T1 | SCTP重建，gNB发送NG Setup Request | AMF接受，NG关联重新建立 |
| T2 | iPhone重注册 | AMF日志：Registration complete |
| T3 | iPhone请求PDU会话 | SMF创建会话、分配IP |
| T4 | SMF向AMF发送N1N2消息传送 | SMF日志：HTTP response error [400] |
| T5 | 会话被删除，iPhone每约16秒重试 | AMF日志：No UE context / No RAN UE Context |
| T6 | 重启open5gs-amfd与open5gs-smfd | UE重连即恢复 |

### 三行日志拼出的真相

这份工单最有价值的地方，是作者贴出了三行互相矛盾的日志：

```
[smf] ERROR: [imsi-xxxx:1] HTTP response error [400]
[amf] ERROR: No UE context [imsi-xxxx]
[amf] ERROR: No RAN UE Context : AMF_UE_NGAP_ID[64]
```

SMF说“我在给AMF送N1N2消息（用来把下行NAS消息透传给手机）时被回了400”；AMF说“这个IMSI我没有上下文”“这个AMF_UE_NGAP_ID（64）我没有RAN侧上下文”。一边是刚刚还打印过Registration complete的AMF，一边是宣称找不到这个UE的AMF——同一个网元，对同一个用户，前后几分钟内给出了相反的答案。

把三条日志按时间排开，结论就浮出来了：**SCTP闪断时，AMF没有把相关UE上下文清理干净**。旧关联下的AMF-UE上下文、RAN-UE上下文、以及关联到SMF的会话状态，有一部分成了“僵尸”——它们占着位置，却不再与任何活着的NG关联挂钩。当基站重连、手机重注册后，新注册流程建立的上下文与残留的旧状态发生了冲突：会话在SMF侧创建成功，但N1N2消息送达AMF时撞上了不完整/错位的上下文，被回以400；随后会话拆除，手机进入16秒一次的循环。

这也解释了用户面的怪象：UPF能ping通UE地址，说明IP分配和隧道转发配置在数据层面是存在的；但ogstun上没有该UE的报文，因为控制面的会话根本没能在正确的上下文上站稳——一份悬空的会话，撑不起真实的流量。

至于为什么iPhone 17 Pro Max更明显而iPhone 14没事，工单作者只记录了现象，未深究机理。合理的推测方向是新机型注册行为更激进、重注册更快，更容易踩中残留窗口，但这一点在工单中并无验证，读者自行排查同类问题时不必先入为主。标准层面，NGAP（3GPP TS 38.413，RAN3工作组负责，2017年Rel-15立项，目前Release 18版本仍在演进）本身允许并要求gNB与AMF在传输层重建后重新协商NG关联，问题在于关联重建之后，受影响的UE级上下文是否被完整回收——这属于实现层面的状态机闭环问题，各厂家具体行为以其官方文档为准。

### 处置与验证

作者的临时处置非常干脆：在gNB重连后重启amfd和smfd，残留状态清空，UE下一次尝试即成功。这是典型的“重启能好”故障——而重启之所以有效，恰恰反证了根因是内存中的状态残留，而非配置或签约数据。

## 三、案例二解剖：订阅池的慢性漏气

### 先看懂这个池子

Open5GS的UDM里有一个SDM订阅池：终端注册时，AMF会到UDM创建一条订阅数据变更订阅；PDU会话建立时，SMF也会创建一条。默认配置下池子大小为`max.ue（1024）× 每UE上限（4）= 4096`条。正常流程下，终端隐式去注册时AMF会退订，SMF也会跟着退订，池子是有进有出的。

### 误判与自我纠错：一次教科书级的排障迭代

这份工单的曲折之处在于，作者最初报的根因是错的，而一个月后他自己用更严格的实验推翻了它——这个纠错过程本身，比结论更值得运维人细读。

第一版报告说：每台UE消耗8条订阅、下线后永不回收、AMF全程无日志。9月23日，项目核心维护者acetcom介入，要求作者开启AMF与UDM的debug日志复现。10月1日，作者带着完整日志回来了，承认三处都错了：

- 每UE实际是**2条**订阅（AMF一条+SMF一条），不是8条；
- 订阅**会被**隐式去注册机制回收，并非永不回收；
- AMF其实**有**报错日志，第一轮没开够日志等级没看到。

### 真正的根因：状态机在突发流量下“断链”

修正后的完整链条是这样的（以下数字均来自作者10月1日公布的实测日志）：

压测中作者用kill命令直接杀掉RAN模拟器，模拟“不干净的下线”——没有任何Deregistration Request。真实世界里，这对应着基站掉电、光缆被挖断、容器被OOMKill。此时：

1. SCTP断开，AMF删除gNB，随后在同一瞬间为500台UE逐台发起SM上下文更新（upCnxState置为DEACTIVATED）——一个500连发的SBI突发；
2. 第一轮杀进程，500台中156台的更新发送失败（Connection reset by peer）；第二轮，143台失败；
3. AMF接着试图向这些UE下发NAS消息，撞上`gNB has already been removed`，流程放弃。这批UE**永远停在CM-CONNECTED**：不进CM-IDLE，就永远不会启动可达定时器，也就永远不会触发隐式去注册；
4. 隐式去注册的定时链条本是：杀进程后780秒（T3512的540秒+240秒）报"Mobile Reachable Timer Expired"，再过780秒执行"Implicit De-registered"，然后AMF退订、释放SM上下文，SMF跟着退订。357台UE在同一秒涌入这条链，其中22台又因同样的SBI错误失败（16台Connection reset、6台SBI事务已移除），日志定格在`NG context has already been removed (nas-path.c:975)`；
5. 35分钟后清点：500台中仍有165台滞留在AMF，它们的324条订阅滞留在UDM。只有重启UDM才能清空。

于是池子成了只进不出的“漏斗”：每压测一轮、每真实断链一次，就永久吃掉一批配额。500台只上375台，不是容量上限，是历史欠账。而UDM日志里反复打印的`Maximum number of SDM Subscriptions [4096] reached`与`udm_sdm_subscription_add() failed`，AMF一个字都没提；UE拿到的又是那个误导性的"5GS services not allowed"。**报错的网元、沉默的网元、感知故障的用户，三方各说各话。**

作者还给出了一条绕过配置：把UDM配置里的`global.max.ue`从默认调高（如8192），报错即消失——但这只是抬高堤坝，不解决泄漏。真正的转机来自版本对照：同一套实验原封不动跑到2.8.0上，两次杀进程500台全部干净走完，无一次SBI错误，最终仅剩6条订阅属于测试床上常驻的两台UERANSIM终端。维护者将该工单标记为“非Open5GS缺陷”归档，但作者留下的那个追问很有分量：如果在现行代码上，gNB丢失后的SM上下文更新在SBI侧失败，这个UE后续还有谁会来释放它？

## 四、方法论：把两个案例拧成一套排障打法

两个案例，故障形态不同，排查路径却高度同构。复盘之后可以沉淀为一套可复用的打法。

```mermaid
flowchart TD
    A["现象：有号没网或批量被拒"] --> B["先看UE侧NAS拒绝原因"]
    B --> C["对齐三方日志 AMF/SMF/UDM"]
    C --> D{"日志能否互相印证"}
    D -->|能| E["按告警点直接定位"]
    D -->|不能| F["控制变量：单组件重启验证"]
    F --> G["负载复现：批量压测重演"]
    G --> H["版本对照：新旧版跑同一脚本"]
    H --> I["证据链闭合后再谈修复"]
```

案例一中那次失败会话的完整消息链，值得每个核心网工程师在脑海里过一遍：

```mermaid
sequenceDiagram
    participant U as 手机
    participant G as gNB
    participant A as AMF
    participant S as SMF
    G->>A: NG Setup重连被接受
    U->>A: 重注册成功
    U->>A: 请求PDU会话
    A->>S: 创建会话分配IP
    S->>A: N1N2消息传送
    A->>S: 返回400 残留上下文冲突
    S->>S: 删除会话
    U->>U: 每16秒重试仍失败
```

两个案例的关键要素对照如下：

| 维度 | 案例一（#4427） | 案例二（#4789） |
| --- | --- | --- |
| 表面现象 | 单台手机注册成功但无数据 | 500台批量注册仅375台成功 |
| 误导信号 | 控制面全绿、UPF可ping通UE | UE报"5GS services not allowed"，像签约问题 |
| 真实根因 | SCTP闪断后UE上下文残留 | SBI突发失败致UE滞留、订阅池只进不出 |
| 决定性线索 | 三行互相矛盾的ERROR日志 | 单独重启UDM后500/500全过 |
| 定位手段 | 日志时间线对齐 | 批量压测+逐条清点SBI请求 |
| 恢复动作 | 重启amfd+smfd | 重启UDM、调高global.max.ue |
| 后续 | 关联工单继续跟踪 | 2.8.0复测通过 |

案例二还留下了一份值得抄进运维手册的参数账本：

| 参数 | 值 | 含义 |
| --- | --- | --- |
| SDM订阅池容量 | 4096 | 默认max.ue 1024 × 每UE上限4 |
| 每UE实际订阅数 | 2条 | AMF注册一条+SMF会话一条 |
| T3512 | 540秒 | 周期性注册更新定时器 |
| 可达定时器触发 | 断链后780秒 | T3512的540秒+240秒 |
| 隐式去注册 | 可达后再780秒 | 到期后AMF/SMF依次退订 |
| UE重试周期 | 约16秒 | 案例一中iPhone的会话重试间隔 |

## 五、给核心网运维人的四条实战启示

**第一，故障点、告警点、感知点三分离，是SBI时代的常态而非意外。** 案例二里，UDM在拼命报错，AMF一声不吭，UE收到的却是一个指向签约数据的cause。传统TDM/七号信令时代“哪个点告警就是哪里坏”的直觉，在HTTP/2+SBI的分布式事务链条上全面失效。日常巡检必须建立“跨NF日志对齐”的习惯：同一个IMSI，把AMF、SMF、UDM（必要时加AUSF/PCF）的日志按时间戳拉通看，单点日志的“正常”毫无意义。

**第二，“重启大法”要升级成“控制变量重启法”。** 案例二中作者单重启UDM、其他全不动，一步就把故障域从“整个核心网容量不足”收窄到“UDM一个池子”；案例一重启amfd+smfd即愈，反证了状态残留。重启本身不丢人，丢人的是全量重启——它既破坏现场，也提供不了任何定位信息。正确的姿势是：一次只动一个组件，动前抓状态、动后验现象，把每次重启变成一次假设检验。

**第三，把“杀进程”纳入例行演练。** 两个案例的引爆点都不是什么罕见攻击或超大规模冲击，而是一次最普通不过的SCTP闪断——基站重配置、光缆施工、电源抖动，每天都在现网发生。区别在于：断链瞬间恰逢SBI突发，一部分跨NF事务失败，状态机就断了链。压测脚本里“优雅去注册后统计成功率”只能证明happy path，“kill -9之后等35分钟再看池子余额”才能暴露真实运行周期能否自愈。案例二作者逐条清点每SUPI的POST/DELETE请求、用callbackReference区分AMF与SMF订阅的做法，值得直接抄走。

**第四，版本对照是最后的“审判”。** 案例二从2.7.5到2.8.0，同一脚本、同一环境，结果从“324条订阅滞留”变成“零滞留”——一次干净的对照实验，胜过十轮猜测。这也提醒升级窗口的价值：很多“疑难杂症”的最终答案不在你的参数表里，而在下一个版本号的changelog里；反过来，割接前用真实现网流量形态（含非正常断链）做回归验证，应该成为5G核心网割接预案的标配动作，而不是可选项。

## 六、结语

这两份工单没有登上任何新闻头条——没有断网时长、没有用户数、没有监管通报。但它们比大多数头条故障更值得运维人精读：一个是新型终端踩中残留上下文的16秒死循环，一个是500台终端的“历史欠账”填满4096格池子；一个靠三行矛盾日志破案，一个靠单组件重启锁定。它们共同演示了5G核心网运维的残酷新现实：故障不再以“整网瘫痪”的面目出现，而是以“个别用户有号没网”“批量注册莫名被拒”的碎片形态渗出，每一条碎片背后，都是某个网元里一份没人认领的僵尸上下文。

标准协议（如TS 38.413定义的NGAP）把重建与恢复的框架画得很完整，但框架之下的每一个状态机闭环，都要靠实现去兑现，靠运维去验证。手机侧那句轻描淡写的“5GS业务不允许”，背后可能是UDM日志里刷屏的池子告警、AMF日志里一行被忽略的`gNB has already been removed`。把这三种日志在心里接上线，才算真正吃下了5G时代的排障饭。

## 参考来源

1. [3GPP TS 38.413 — NG-RAN; NG Application Protocol (NGAP)](https://www.3gpp.org/dynareport/38413.htm) — 3GPP官方规范页：NGAP由RAN3工作组负责，Rel-15起步，Release 18最新版本18.5.0于2025年3月进入变更控制，本文NG关联重建与UE上下文的标准背景来源
2. [Open5GS Issue #4427 — AMF/SMF stale UE context after gNB SCTP reconnection causes PDU session failure (HTTP 400)](https://github.com/open5gs/open5gs/issues/4427) — 案例一原始工单：专网环境iPhone 17 Pro Max"注册成功无数据"的完整现象、日志与复现步骤
3. [Open5GS Issue #4789 — UDM SDM subscriptions pool fills and registrations fail as "5GS services not allowed"](https://github.com/open5gs/open5gs/issues/4789) — 案例二原始工单：含作者初始误判、维护者介入、10月1日debug级复测的全部数据（156/143/22台失败明细、35分钟滞留清点、2.8.0对照结果）
4. [Open5GS GitHub仓库](https://github.com/open5gs/open5gs) — 开源5G核心网项目主页，本文涉及组件版本（v2.7.5/v2.7.6/v2.8.0）的载体
5. [PacketRusher压测工具（gradiant容器镜像）](https://github.com/open5gs/open5gs/issues/4789) — 案例二作者批量注册500台UE所使用的负载生成工具，随工单公布的镜像标识为gradiant/packetrusher

---
> 本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵**爱卫生**（微信ID: gprshome201101）维护，聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。
> 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。

> [!tip] 51学通信知识星球
> **星主：爱卫生**（微信：gprshome201101）——公众号「51学通信」创办者，19 年通信行业运维与讲师经验，著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书（各大电商平台有售）。
> **星球定位**：深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域，主打运维岗位与信令分析。
> **当前规模**：5200 篇主题 / 990 个回答，198 元/年。
> **加入福利**：加入星球后请加爱卫生微信，拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题，另有群内分享。
> **AI 加持**：51学通信知识星球已作为 skill 接入 WorkBuddy，使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例，做总结、找文档和 PPT 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
