news 2026/5/25 16:19:02

为什么我的 DPDK 程序明明没有锁,却还是性能很差?一次排查让我彻底理解 false sharing

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
为什么我的 DPDK 程序明明没有锁,却还是性能很差?一次排查让我彻底理解 false sharing

我早期做DPDK多核开发时,总有一个认知:只要没有锁,性能就一定很好。

因为:

  • 没有 mutex
  • 没有 spinlock
  • 没有 rwlock
  • 全部 lockless

理论上:应该扩展性极强。

但我曾经遇到一个非常诡异的问题:

程序架构完全无锁:

  • 每核独立 RX queue
  • per-core statistics
  • 独立 mempool cache
  • 无共享 ring

看起来已经非常“DPDK 化”。但性能却始终上不去。

更奇怪的是:随着 core 数增加:性能不仅没提升。反而下降。

例如:

2 核

8 Mpps

4 核

11 Mpps

8 核

10 Mpps

CPU 全部打满。但吞吐增长极差。

第一次遇到时,我怀疑过:

  • NUMA
  • mbuf cache
  • RX queue 配置
  • descriptor 不够
  • PCIe 带宽

最后才发现:

真正的问题是:false sharing

而这个问题,也是多核高性能程序里最隐蔽、最容易被忽略的问题之一。

一、问题现场

程序很简单:

每个 lcore:

  • 独立收包
  • 独立统计
  • 独立处理

统计结构:

struct worker_stats { uint64_t rx_pkts; uint64_t tx_pkts; uint64_t drops; };

然后:

struct worker_stats stats[MAX_CORE];

每个核:更新自己的:

stats[lcore_id]

看起来完全没问题。

因为:没有锁。

二、现象却很奇怪

perf 结果:

大量 cache miss

同时:

snoop hit cache invalidation

异常高。

三、为什么没有锁还会 cache 冲突

这是理解 false sharing 的关键。

很多人以为:只有:多个线程访问同一个变量 才会冲突。

其实:CPU cache 的粒度不是变量。

而是:cache line

通常:

64 bytes

四、什么是 cache line

CPU cache 不会:

一次只加载:8 字节

而是:整块加载。

例如:

64-byte cache line

五、问题就出在这里

虽然:

stats[0] stats[1]

是不同变量。

但它们:可能位于:同一个 cache line。

六、于是发生什么

例如:

core0

更新:

stats[0].rx_pkts++

core1

同时更新:

stats[1].rx_pkts++

虽然逻辑上互不相关。

但物理上:同一个 cache line。

七、MESI 协议开始工作

CPU 为了保证缓存一致性:

使用:cache coherence protocol

例如:MESI

八、于是 cache line 被疯狂抢夺

过程类似:

core0 修改 ↓ cache line exclusive ↓ core1 修改 ↓ invalidate core0 ↓ core0 再修改 ↓ invalidate core1

不断抖动。

九、这就是 false sharing

即:“逻辑上不共享”、“物理上共享”,导致 cache line 竞争。

十、为什么 DPDK 特别容易遇到

因为:DPDK 本身:

极高 PPS

极高 cache 敏感度

多核持续写入

busy polling

cache line 抖动会被无限放大。

十一、为什么 core 越多性能反而越差

因为:参与竞争的 core 增多。cache coherence traffic 激增。

最终:CPU 大量时间浪费在:cache sync

而不是:真正处理包。

十二、如何确认 false sharing

perf 非常关键。

例如:

perf stat

关注:

cache-misses

LLC-load-misses

snoop hits

remote HITM

如果:

HITM 很高

通常意味着:cache line 争用。

十三、真正修复方法

后来做了一个简单修改:

struct worker_stats { uint64_t rx_pkts; uint64_t tx_pkts; uint64_t drops; } __rte_cache_aligned;

十四、__rte_cache_aligned 是什么

这是 DPDK 中非常经典的宏。

作用:cache line 对齐。

通常:

64 bytes aligned

十五、这样会发生什么

现在:

stats[0] stats[1]

分别位于:不同 cache line。

十六、于是竞争消失

core0:只修改自己的 line。

core1:也只修改自己的。

不再互相 invalidation。

十七、优化效果非常明显

优化前:

CorePPS
28 Mpps
411 Mpps
810 Mpps

优化后:

CorePPS
28 Mpps
415 Mpps
828 Mpps

扩展性完全恢复。

十八、一个更隐蔽的问题:ring head/tail

false sharing 不仅发生在 stats。

还经常发生在:

ring producer index

consumer index

queue state

flow counter

这些高频写变量。

十九、为什么 DPDK 到处都有 cache align

你会发现:DPDK 源码里大量:

__rte_cache_aligned

以前很多人只是:“照着写”。

其实背后都是:避免 false sharing。

二十、进一步理解 cache friendly design

高性能程序优化:

很多时候已经不是:算法复杂度。

而是:cache topology。

包括:

cache line

NUMA

prefetch

memory locality

这些。

二十一、为什么 false sharing 特别难发现

因为:

没有锁

没有崩溃

没有错误日志

CPU 也很高

程序“看起来正常”。

只是:性能奇差。

二十二、一个经典误区

很多人认为:

无锁 = 高性能

其实:真正昂贵的:不一定是锁。

而是:cache coherence。

二十三、进一步理解现代 CPU

现代多核 CPU:真正贵的操作:往往不是:

add mul branch

而是:

跨核 cache 同步

因为:

涉及:

  • interconnect
  • snoop
  • invalidate
  • memory ordering

二十四、为什么 DPDK 如此强调 per-core

DPDK 的设计哲学之一:per-core everything

即:

per-core mempool cache

per-core RX queue

per-core statistics

per-core flow

本质都是:避免共享。

二十五、这次排查真正学到什么

以前我以为:多核优化就是:避免锁。

后来才意识到:真正困难的是:避免 cache line 共享。

这也是为什么:

很多高性能程序:代码看起来很“浪费内存”。

因为:它们在用空间换 cache efficiency。

二十六、工程经验总结

DPDK 中:高频写变量:必须:

cache aligned

per-core

避免共享

尤其:统计计数器。

二十七、总结

为什么 DPDK 程序明明没有锁,却还是性能很差?

很多时候不是:

  • 算法问题
  • 网卡问题
  • NUMA 问题

而是:false sharing。

通过这个问题,我们真正理解了:

核心概念

  • cache line
  • MESI
  • cache coherence
  • false sharing
  • cache aligned
  • per-core design

这也是高性能网络开发真正进入“底层优化”的开始:

性能竞争的对象,已经不是代码。

而是:CPU cache。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/25 16:17:13

2026年了,还在忍受百度网盘几十KB?聊聊Pandownload现在的提速方案

今天开电脑瞥了眼日期——2026年5月24日。顺手刷了刷贴吧和几个技术小圈子,“百度网盘下载慢”这词儿居然还挂在热搜上。就……怎么说呢,感觉像见了鬼一样,跟十年前一个德性。 所以我憋不住想写点东西。没广告,不带节奏&#xff…

作者头像 李华
网站建设 2026/5/25 16:16:19

Burp Suite全流程实战:真实渗透中的卡点突破与战术决策

1. 这不是“学Burp”,而是用Burp解决真实渗透现场的卡点问题你刚拿到一个客户给的测试授权,目标是某套自研的供应链协同平台——没有文档、没给源码、连登录流程都做了双因子滑块验证。你打开浏览器开发者工具,发现所有请求都带X-Request-ID和…

作者头像 李华
网站建设 2026/5/25 16:15:01

亲测可用:macOS下Claude Code安装与88api中转配置,一篇搞定国内调用

前言 我整理了一份 macOS 下的 Claude Code 完整实操流程,从 Node.js 安装到 Claude Code 配置,再到国内 API 直连方案,每个步骤都附了具体命令和配置示例。 我用的是 88api 作为中转,主要图它国内直连不用翻墙,一个…

作者头像 李华
网站建设 2026/5/25 16:14:01

海水缸自动化系统设计:从硬件选型到智能控制逻辑全解析

1. 项目概述:为什么海水缸需要自动化? 养一缸珊瑚,本质上是在客厅里复制一片微缩的海洋。这片“海洋”的稳定,是里面所有绚丽生命得以存续的基石。水温波动超过1度、光照时间紊乱、钙镁离子浓度失衡、水流突然停滞……任何一个看似…

作者头像 李华
网站建设 2026/5/25 16:12:07

Visual C++运行库一键安装指南:彻底解决Windows应用依赖问题

Visual C运行库一键安装指南:彻底解决Windows应用依赖问题 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过打开软件时弹出"缺少…

作者头像 李华
网站建设 2026/5/25 16:11:48

BiliBiliCCSubtitle终极指南:如何一键下载B站字幕并转换为SRT格式

BiliBiliCCSubtitle终极指南:如何一键下载B站字幕并转换为SRT格式 【免费下载链接】BiliBiliCCSubtitle 一个用于下载B站(哔哩哔哩)CC字幕及转换的工具; 项目地址: https://gitcode.com/gh_mirrors/bi/BiliBiliCCSubtitle 你是否曾经为了获取Bilibili视频的字…

作者头像 李华