过早优化是万恶之源——聊聊FastThreadLocal的Cache line padding

💡 过早优化是万恶之源。                                                                            ——Tony Hoare

作为软件开发人员的一句名言,相信绝大多数小伙伴都有听闻过这句名言,而我在最近阅读netty源码的时候就见识了这么一个有趣的例子。

Netty是一个用于构建高性能、可伸缩的网络应用程序的异步事件驱动框架。它主要关注在网络通信、协议处理和高性能的特性上,是一个基于Java的开源框架。Netty的设计目标是提供简单而强大的 API,使得开发者能够轻松地构建各种网络应用,包括但不限于服务器和客户端。

可能很多开发同学没有直接使用过netty,但它作为一个优秀的通信框架你很有可能在实际项目中已经在使用了,比如国内流行的rpc框架dubbo底层默认就使用netty作为通信层,此外还有Elasticsearch、RocketMQ、Camel等等中间和框架。

如此优秀的框架非常值得一读,而我也在阅读FastThreadLocal中发现了一个有趣的优化。

在 Netty 中,FastThreadLocal 是一种优化过的线程本地存储(ThreadLocal)实现,用于提供更高性能的线程本地变量访问。它的设计目标是减小线程本地存储的性能开销,特别适用于高并发的网络应用场景,如 Netty 所涉及的网络通信框架。

作为其核心原理的InternalThreadLocalMap内有这样一行

// Cache line padding (must be public)
// With CompressedOops enabled, an instance of this class should occupy at least 128 bytes.
public long rp1, rp2, rp3, rp4, rp5, rp6, rp7, rp8, rp9;

故事今天就是围绕这一行展开的,众所周知基于时间局部性和空间局部性原理所以当处理器需要加载内存中的数据时,它会加载整个缓存行,而不仅仅是请求的特定数据,缓存行的大小通常是2的幂,例如64字节。当一个线程修改缓存行中的数据时,整个缓存行都会被标记为"脏",这会导致其他线程中缓存行的数据无效,需要重新加载,这被称为伪共享。

为了避免伪共享和优化多线程程序的性能,可以使用以下方法:

  1. 使用@Contended注解(仅在Java 8及更新版本中可用):该注解可用于类或字段上,可以告诉JVM在生成字节码时添加填充以避免伪共享,原理是在使用此注解的对象或字段的前后各增加128字节大小的padding,使用2倍于大多数硬件缓存行的大小来避免相邻扇区预取导致的伪共享冲突,具体可以参考

RFR (S): JEP-142: Reduce Cache Contention on Specified Fields

  1. 缓存行填充(Cache Line Padding):通过在数据结构的末尾添加一些无关的变量,使得不同线程操作的数据不在同一个缓存行上。这样可以减少伪共享的影响。

而很明显上面的代码就属于第二种,试图通过行填充解决伪共享,看上去好像没什么问题,netty使用各种小技巧的地方也非常多,但这一行在https://github.com/raidyue/netty/commit/ef540815a98dac50769e38b39e5107dc5a313b47 中被改为了

/** @deprecated These padding fields will be removed in the future. */
public long rp1, rp2, rp3, rp4, rp5, rp6, rp7, rp8, rp9;

哎哎哎,刚才还说这一行多么老道,这会怎么就要删除了,提交的log大概是这么说的

我没有看到填充有任何明显的优势。
唯一受保护的其他字段是对 BitSet 的很少更改的对象引用。
填充也使用“long”,这不一定会阻止 JVM 将上述对象引用放入对齐间隙中。

好嘛,原来只是一个拍脑袋的优化,也并没有基准测试的数据。

但代码已经在了删除的它的风险就很高,所以只是写了一行注释要删除却没有真正的删除它。

甚至于还有后续,在https://github.com/netty/netty/pull/12309 中它被改成了这样

/** @deprecated These padding fields will be removed in the future. */
public long rp1, rp2, rp3, rp4, rp5, rp6, rp7, rp8;

细心的小伙伴发现少了一个rp9,因为在之前的某次功能合并中InternalThreadLocalMap增加了一个字段

private ArrayList<Object> arrayList;

导致缓存行填充从128字节破坏为136字节。。。

为此又做了一个修复去掉了一个long field,黑魔法用的多确实容易被反噬。,这就是一个活生生的例子。

甚至于最近还有人提到这个事情https://github.com/netty/netty/issues/12312 有开发者认为如果是为了避免伪共享,那么随着jdk内存布局的调整我们应该使用字节字段进行填充而不是long去做填充。netty的作者估计也是不想在这个事情上多做纠缠,明确在主干分支上已经把这个玩意干掉了,4.x版本后续也会逐步移除它,没有更严格的基准测试之前我们将不会再做填充。

看完这个系列希望各位同学们慎用黑魔法,放下脑子一热的优化,多去借鉴借鉴他人优秀的架构与设计 😎写出更优雅的代码。

原文地址:https://pebble-skateboard-d46.notion.site/FastThreadLocal-Cache-line-padding-0002a7da3f724dddb1b4ed2ed4471818

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容