一、一个几乎所有团队都会经历的过程很多 DPDK 项目在最初设计时都非常简单。控制面负责配置下发Session创建Session删除策略更新数据面负责收包查表转发于是系统通常会设计成这样---------------- | Control Plane | --------------- | v ---------------- | Session Table | --------------- | v ---------------- | Data Plane | ----------------控制面和数据面共享同一套状态。控制面直接修改数据面直接读取。代码实现非常简单。甚至很多项目上线初期运行良好。然而随着用户规模增加。问题开始逐渐暴露。二、第一次性能问题假设系统拥有100万 Session此时控制面每秒钟需要处理新增Session 删除Session 修改PDR 修改FAR QoS更新与此同时数据面正在处理数千万 PPS流量。于是控制面开始修改session-pdr new_pdr;数据面同时读取pdr session-pdr;此时会出现一个问题同步三、共享状态的代价很多开发者认为读写一个指针而已代价很小。实际上在现代多核CPU中。共享状态的代价远超想象。因为CPU必须保证Cache一致性例如Worker0读取SessionWorker1更新Session此时CPU缓存必须同步。这意味着Cache Line失效 重新加载 重新同步系统开始浪费大量CPU周期。四、为什么性能问题总是后期才出现因为小规模测试中Session数量少 控制面更新少同步成本并不明显。但运营商环境不同。例如1000万用户即使只有1%用户发生变化。也意味着10万Session变更每一次变更都会影响数据面。此时共享状态开始成为灾难。五、VPP为什么很少直接共享状态很多人研究VPP时会发现一个特点。VPP并不鼓励多个线程共享业务对象原因很简单。VPP团队早就认识到共享是昂贵的他们更倾向于状态归属即谁拥有 谁管理而不是所有人共享六、运营商系统真正害怕什么很多人认为运营商设备最害怕吞吐不足实际上运营商更害怕状态不一致例如控制面认为Session已经删除而数据面认为Session依然存在那么计费错误QoS错误安全策略错误都会发生。因此一致性比性能更加重要。七、第一代解决方案加锁很多团队最先想到pthread_rwlock_t控制面写锁。数据面读锁。理论上解决了问题。但实践很快发现性能暴跌原因很简单。数据面最怕等待即使只等待几十纳秒在千万PPS场景下。也会放大成严重瓶颈。八、第二代方案RCU随后很多团队引入RCU思想。即Read Copy Update控制面复制新对象数据面继续访问旧对象更新完成后切换指针这种方式显著降低了锁竞争。Linux内核大量采用这种设计。九、RCU为什么仍然不是终点因为RCU解决的是同步问题而没有解决归属问题数据面依然访问全局状态随着系统规模继续扩大。新的问题出现NUMA Cache Miss 跨核访问十、Shared-Nothing思想的出现于是运营商级设备开始转向Shared-Nothing即没有共享状态例如TEID ↓ Hash Worker0 TEID ↓ Hash Worker1 TEID ↓ Hash Worker2每个Worker拥有Session PDR FAR QER自己的副本。十一、状态归属的重要性此时控制面不会直接修改Session而是发送Update Message例如Add Session Delete Session Update PDR消息进入对应Worker。Worker自行更新。于是状态归属清晰十二、为什么消息驱动越来越流行消息驱动有一个巨大优势单写原则即一个对象 只有一个Owner例如Session属于Worker3那么任何修改都必须通过Worker3完成。不会出现多个线程同时修改的问题。十三、UPF中的典型实践在5G UPF中常见设计N4 Processor | v Control Message | v Worker Queue | v Worker Update SessionN4线程只负责解析PFCP。不直接修改数据面状态。数据面线程负责真正更新。这种架构已经成为行业主流。十四、为什么这样扩展性更强因为随着CPU核心增加。共享架构扩展曲线1核 100% 2核 170% 4核 250% 8核 320%逐渐下降。而Shared-Nothing1核 100% 2核 195% 4核 390% 8核 770%接近线性增长。原因就在于同步成本消失十五、未来的数据面架构趋势从近几年发展看无论VPP商用UPF智能网卡云原生数据面都在向同一个方向演进控制面 ↓ 消息 数据面 ↓ 状态归属 Worker ↓ Run-To-Completion这已经成为现代高性能数据面的主流设计模式。十六、从代码优化到架构优化很多工程师最开始学习DPDK时。关注的是Prefetch SIMD Burst Zero-Copy这些当然重要。但当系统发展到运营商级规模时。决定性能上限的往往不是代码优化而是架构优化而控制面与数据面的解耦。正是其中最关键的一步。十七、总结很多DPDK项目最初都采用共享状态设计。这种架构简单直接。但随着用户规模、CPU核心数和业务复杂度增长。共享状态逐渐演变成性能瓶颈一致性风险扩展性障碍因此现代运营商级系统越来越倾向于消息驱动 状态归属 Shared-Nothing Run-To-Completion其核心思想只有一句话不要让多个线程共同管理一个对象。当控制面负责下发意图数据面负责维护状态Worker负责拥有对象时系统不仅能够获得更好的性能也能获得更强的可扩展性和长期稳定性。这也是现代UPF、VPP以及高性能数据面系统共同遵循的架构原则。