暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

从体系结构到数据库:千面内存(序)

IT知识刺客 2025-01-29
133

写公众号一年,41篇原创,11万字: 

知乎粉丝数也突破了1万,有1.1万了。

有些地方还是颇感意外,本来觉得大伙喜欢看故事、听八卦,硬核的技术,流量一定惨不忍睹。颇出我意料的,我文章的流量之王,竟然是最深入的文章:

深入突破基础软件开发(大结局)

跟着苍老师学体系结构:深入突破基础软件开发(一)

《深入突破基础软件开发》系列一和大结局,各有5万上下的流量,两篇合起来10万+了,着实让我意外。因为这是我出道以来,写过的最深入的技术文章,没有之一。    

《深入突破基础软件开发》主要讲CPU执行阶段流水线的情况。

现代底层硬件复杂度十分惊人,潜藏着十分巨大的能效潜力,如果能更加了解你的硬件,就能更好的释放硬件潜力,这是基础软件开发者的必修课。

如果连一条指令如何在CPU中被执行的,都说不清楚,这可不是合格的基础软件开发者。

为了感谢腾讯肯把流量推给深度文章,IT知识刺客正在策划蛇年第一个系列:从体系结构到数据库:千面内存》。

这个系列是讲内存的。

内存,是代码的舞台,是除CPU之外,最影响性能的设备。我们每时每刻都在使用它,但却不了解它。因为没有必要了解。

在现代软件工程的分层抽象思想下,内存被抽象为一个线性、一维的大数组,数组的下标就是内存地址,你给我地址,我给你数据。

对于应用层程序开发者,抽象后的内存层简单易用,而且针对性的做了足够的优化,实无必要再向下学习、研究内存设备的原理。

但对于基础层软件开发,则完全不同。抽象层做的优化,有时可能会起到反作用。

以内存抽象层为例,CPU假定开发者多以连续或小步阀、固定步阀访问内存,并因此增加预测读取机制。

比如,CPU发现你访问完地址12345的内存,又访问12346、12347、12348……,CPU会提前把12349、12350、12351……等地址处的数据,先从内存读进Cache,这就是CPU的预测机制。

这个预测机制效果如何呢?

做个简单测试,一看便知:    

图1

图1是执行一条简单SQL期间,CPU L2 Cache的情况。

目标SQL执行了两次,下面perf也进行了两次统计。

第一次是正常执行。第二次执行时,我关掉了CPU预读机制。因此,第二次perf统计结果中,l2_rqsts.all_pf只有94,而第一次执行时,all_pf还有11,986。

注:

l2_rqsts.all_pf是L2完成的CPU硬件预取请求次数。pf,就是pre-fetch的缩写。

打开CPU预测访问(第一次执行),31581/50004,L2 Miss率为63.1%。

关闭CPU预测访问(第二次执行),22826/38412,L2 Miss率为59.4%。

关闭CPU预测L2 Miss率下降了4个百分点,而且perf统计的执行时间也从1.89秒下降到1.77秒。    

对数据库来说,CPU的预测机制板上钉钉是帮了倒忙。

注:

   测试SQL是OLTP型简单SQL,如果是OLAP型SQL,要另当别论。

CPU的硬件预取,就是基础数据抽象层为我们做的优化,只需要一个极简单的测试,就能证明它并不总是有效。

但如果你足够了解基础数据抽象层,则可以做到扬长避短,最大程度发挥其作用、避免负面影响。

(我再强调一边,对于应用层开发者来说,这样做没有意义,不如更加关注业务逻辑等等)

再看个和内存直接相关的吧:

图2

这是访存性能测试图,在后续《从体系结构到数据库:千面内存》系列文章中,再详细讲解其意义,先简单说下。

Y轴是访存延时,单位是周期。因为这是从CPU角度得到的延时,因此这里的周期是CPU的时钟周期。

如果CPU主频是3GHz,3个周期1纳秒。所以Y轴只要除以3,就是以纳秒为单位的延时。

这其实是一张散点图,散点太多,连成了一片。

每一个点,是以固定间隔重复访问6次内存后的平均值(排除了L1~L3 Cache的影响)。    

蓝、橙、灰三种颜色,对应三种访存间隔计算方式。

访存指令,使用Intel SIMD指令集中的vmovntdqa指令,它属于AVX2指令集,可一次读写32个字节(256 bit)。

相比传统的mov指令,矢量指令vmovntdqa没有那么多优化,完成的工作也相应少些,更容易反应真实的访存延迟。

但要注意,指令手册中虽然说vmovntdqa将绕开各级Cache,但实际并不会。

虽然做了一系列的工作,可以看到,图2的散点图中,访存延迟仍存在巨大的波动。低至270周期左右,高至400周期以上。

为什么存在如此大的波动?

举个小例子,前面说了,矢量指令vmovntdqa并不会绕过各级Cache,数据还是要先写入Cache,再读入ymm寄存器。当Cache满后,新的读取只能等待,等Cache腾出空间,再写入Cache,这一次访存延时必然更高。

还有其他原因,有的是统计程序本身造成的,等等吧,波动是难免的。但有一点值得注意,波动虽然会让延迟增高,却无法让延迟更低。

简单点说,波动会让一个200周期的访存,因为一些原因,增加到300周期,却无法让它降低到150周期。因此,图2散点图的下边缘,可以做为访存的真正延时。按照这个思路,我对图2橙、蓝、灰分别按下边缘进行了拟合处理:    


图3

将橙、蓝、灰散点图下边缘,拟合为三条橙、蓝、灰的线后,规律阅然纸上。

前面说了,橙、蓝、灰对应三种不同的间隔计算方式,其中蓝线的间隔基数最大,需要的内存也更多,测试的后半段,间隔甚至跨了NUMA节点,我把NUMA的影响在图上标记一下:

图4

蓝线后半段,延时陡然升高,其实是跨了NUMA节点。

有了NUMA做对比,很容易就能发现,橙线的前半段,延时一直低于蓝、灰,而且延时差距,和NUMA几乎不相上下

这说明访存存在着和NUMA影响相当的因素,如果能明确这个“因素”的原理,合理的按排数据结构,甚至能取得和NUMA Aware一样的提升。    

NUMA Aware是什么量级的提升呢,给你点信息感受一下:

以上宣传来自个别国库(国产数据库)头部玩家官网或搜索引擎,连右上图中非技术线的领导,都被拉到台上NUMA-Aware了。右下的NUMA-Aware多实例架构,更是在官网首页,独自撑起了国库头部玩家的一条产品线。

现在有了影响和NUMA相当的“因素”,国库头部玩家,又可以再Aware一次、再开一条产品线了。

(不过这次Aware会有点难,因为这个神秘的因素是什么呢,总要先找到它,再Aware它吧。我出十块钱,赌国库头部玩家这次Aware不了。再出十块,赌他们的NUMA-Aware也是吹牛B的水货)

那么,内存中,是什么神秘的因素潜藏着如此巨大的性能潜力?

从体系结构到数据库:千面内存》,敬请期待。

文章转载自IT知识刺客,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论