ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Intel与ARM多片一致性架构对比:从Ring到Mesh再到UPI与CHI的NUMA调优实践

Intel与ARM多片一致性架构对比:从Ring到Mesh再到UPI与CHI的NUMA调优实践 1. 从一颗CPU到一座机房多片一致性到底在解决什么问题单核时代早就过去了现在随便一颗服务器CPU里面都塞着几十个核心再往上走一颗芯片的封装面积和功耗墙已经卡死了继续堆核心的路子。于是工业界很自然地走向了多片——把多个芯片或者多个芯粒、多个插槽、多个节点连起来对外呈现出一台机器、一份内存视图。听起来很美好但真正做过底层系统的人都知道这里最要命的问题不是算力而是一致性。什么叫一致性通俗点说就是我在A芯片上写了一个变量B芯片上立刻要能读到这个新值而且不能读到半新半旧的中间状态。单芯片内部靠硬件缓存一致性协议比如MESI那一套就能搞定因为总线是共享的、延迟是可控的。可一旦跨片物理链路变长、延迟从几十纳秒涨到几百纳秒甚至微秒级共享总线这种玩法直接崩掉必须换成基于消息传递的目录式协议。这就是多片一致性架构要处理的核心命题。Intel和ARM在这个问题上走了两条明显不同的路。Intel是我全都要自己定从环形总线到Mesh再到UPI互联和Snoop Filter目录整套东西是垂直整合的你买它的CPU就得接受它的互联哲学。ARM则是我定规则你们来实现CHICoherent Hub Interface协议加上CMNCoherent Mesh Network互联IP授权给一堆厂商去拼自己的SoC。这两条路没有绝对优劣但理解它们的异同对做服务器选型、做系统调优、甚至做芯片架构评估的人来说是绕不过去的基本功。这篇文章不打算写成教科书而是从工业界实际部署的角度把Intel和ARM在多片一致性上的设计取舍、协议细节、NUMA表现、以及实际调优中会踩的坑一条条拆开讲。适合做服务器底层、虚拟化、高性能计算、以及芯片验证方向的同学参考也适合对NUMA和缓存一致性只有模糊概念、想搞清楚为什么跨片访问会慢的读者。2. Intel的目录式一致性从Ring到Mesh再到UPI的演进逻辑2.1 单芯片内部Ring Bus为什么会被Mesh取代早期Intel的服务器CPU比如Sandy Bridge-EP那一代用的是环形总线Ring Bus。所有核心、LLCLast Level Cache最后一级缓存、内存控制器、IO控制器都挂在一个环上谁要访问谁数据就沿着环一站站传。这个设计在核心数少的时候非常优雅结构简单、延迟低、带宽利用率高而且天然支持缓存一致性——环上每个节点都能偷听到经过的数据snoop机制直接就能工作。但环形总线有个致命问题延迟随节点数线性增长。8个核心的时候最坏情况绕半圈也就几个周期到了20个核心以上环越来越长绕一圈的代价就不可接受了。更要命的是环上任何一个节点要通信都得占用环的带宽核心一多环就成了瓶颈。所以从Haswell-EP开始Intel转向了Mesh网格互联。Mesh把芯片切成一个个小格子每个格子叫一个tile里面可能放一个核心加一块LLC slice也可能放内存控制器或者IO。相邻tile之间点对点连接数据像走迷宫一样从源tile跳到目标tile。Mesh的好处是延迟和节点数的关系从线性变成了近似对数走XY路由横竖各走一段而且带宽可以随着tile数量扩展。这里有个关键设计LLC是分布式切片distributed slice的。也就是说最后一级缓存不是一整块而是被切成很多片每片挂在一个tile上地址通过哈希映射到具体的slice。这意味着一个核心访问某个内存地址数据可能缓存在离它很远的另一个tile的LLC slice里。Mesh负责把这些请求路由过去这就是所谓的片上NUMA雏形。2.2 跨插槽UPI和Snoop Filter目录的分工单芯片内部搞定了接下来是多插槽multi-socket。两颗CPU插在同一块主板上怎么让它们的内存互相可见、缓存保持一致Intel的答案是UPIUltra Path Interconnect替代了更早的QPI。UPI是点对点的串行链路通常每颗CPU有2到3条UPI链路连到其他CPU。比如双路服务器两颗CPU之间用两条UPI互联带宽可以做到很高。但UPI只是路真正决定一致性行为的是Snoop Filter探听过滤器和Home Agent归属代理。我尽量用大白话解释这套机制。假设CPU0的一个核心要读一个地址这个地址的家Home在CPU1的内存控制器上。流程大致是请求先到CPU0的Home AgentHome Agent查一下这个地址的归属发现家在CPU1。请求通过UPI发到CPU1的Home Agent。CPU1的Home Agent查Snoop Filter目录看这个地址的缓存行现在被哪些核心持有、是什么状态。如果目录显示数据在CPU1某个核心的缓存里是Modified状态就直接从那个核心取数据返回不用去内存。如果目录显示没人缓存就去内存取同时更新目录状态。Snoop Filter目录是这套机制的核心。它本质上是一个记录哪些缓存行被缓存在哪里的表。有了它就不需要像早期那样把snoop请求广播给所有核心广播snoop在大规模系统里是灾难而是精准地只问该问的核心。这大幅降低了互联上的流量。但目录是有代价的它要占芯片面积而且目录本身也可能成为瓶颈。Intel的做法是把目录和LLC slice绑定分布式存放这样目录查询也能并行化。2.3 工业界实际部署中的NUMA表现在真实的双路甚至四路Intel服务器上你会看到NUMA节点的概念。一颗CPU加上它直连的内存构成一个NUMA节点。跨节点访问内存延迟大约是本地访问的1.5到2倍带宽也要打折扣。这里有个很多人忽略的点UPI的拓扑不是全连接的。四路服务器里CPU0可能只直连CPU1和CPU2访问CPU3的内存要经过CPU1或CPU2中转延迟进一步增加。所以四路机器上NUMA距离distance是有层级的numactl -H看到的distance值能到20多甚至30而本地是10。实际调优的时候我一般会做这几件事用numactl --hardware看清楚拓扑别假设所有远程节点距离一样。对延迟敏感的应用比如内存数据库用numactl --cpunodebind0 --membind0把进程和内存绑死在同一个节点。对带宽敏感的应用反而要考虑把内存**交错interleave**分布在多个节点用numactl --interleaveall让内存控制器并行工作。注意UPI链路的不对称如果两颗CPU之间的UPI只有一条而另一对之间有两条流量分布会不均这种细节在主板手册里才有。提示很多性能问题不是CPU算力不够而是NUMA没配对。我见过一个案例某服务默认让所有线程在node 0上跑但内存全分配在node 1结果跨节点流量把UPI打满QPS直接掉一半。改一行绑核配置就好了。3. ARM的CHI与CMN把一致性做成可授权的IP3.1 CHI协议到底规定了什么ARM自己不卖CPU成品至少服务器领域主要是授权它卖的是架构和互联IP。在多片一致性这块ARM的核心武器是**CHICoherent Hub Interface协议以及实现它的CMNCoherent Mesh Network**系列互联IP。CHI是一个基于消息的一致性协议。和Intel那套相对封闭的机制不同CHI是公开规范任何拿到授权的厂商都能实现。它把一致性通信抽象成几种通道REQ通道发请求比如ReadShared、ReadUnique、MakeUnique。SNP通道snoop请求问某个缓存行在不在、什么状态。DAT通道传数据。RSP通道传响应比如CompAck、Comp。每个缓存行在CHI里有明确的状态比如IInvalid、UCUnique Clean、UDUnique Dirty、SCShared Clean、SDShared Dirty。这套状态机比MESI更细主要是为了支持更复杂的场景比如clean unique、cache stashing把数据主动推给某个缓存等。CHI的关键设计理念是分层协议层定义消息语义互联层CMN负责路由和物理传输。这样厂商可以用同一套协议搭出从手机SoC到数据中心CPU的不同规模系统。3.2 CMN的Mesh结构和HN-F节点CMN本质上是一个二维Mesh和Intel的Mesh思路类似但更强调可配置性。CMN里最关键的组件是HN-FHome Node - Fully coherent它相当于Intel的Home Agent加Snoop Filter的结合体。HN-F负责管理一段地址范围的一致性目录directory。接收来自RN-FRequest Node - Fully coherent通常就是CPU核心集群的请求。向其他RN-F发snoop维护缓存状态。对接内存控制器通过SN-FSlave Node。CMN的Mesh里还有**XPCross Point**节点负责路由**MNMiscellaneous Node负责配置和调试。整个网络通过SAMSystem Address Map**把物理地址映射到具体的HN-F和内存区域。和Intel类似CMN也是分布式目录每个HN-F管一段地址目录信息跟着地址走。这样请求可以并行处理不会有一个中心目录成为瓶颈。3.3 多片场景CCIX、CXL和CMN的扩展ARM生态里多片的概念比Intel更宽泛。Intel的多片主要是多插槽而ARM的多片可以是多die封装chiplet比如把多个计算die和IO die封在一起。多插槽通过片间互联连起来。异构计算CPU和加速器之间的一致性。为了支持这些场景ARM生态主要靠CCIX和CXL这类缓存一致性互联协议。CCIX允许不同厂商的芯片之间保持缓存一致CXL则在PCIe物理层上跑一致性协议现在更主流。在CMN里跨片一致性通常通过**CCGCCIX/CXL Gateway**节点实现。CCG挂在Mesh上把本地的CHI消息转换成CCIX/CXL消息发出去收到远程消息再转回CHI。这样从CPU核心的视角看访问远程芯片的内存和访问本地内存在协议层面是一样的只是延迟更高。这里有个实际工程上的难点目录的跨片同步。本地HN-F的目录只记录本地缓存状态远程芯片的缓存状态要么靠远程HN-F自己管要么靠更复杂的分布式目录协议。CCIX/CXL在这块的实现细节各家不同也是验证工作的重点。4. 两条路线的正面对比设计哲学决定了什么4.1 开放协议 vs 垂直整合把Intel和ARM放在一起看最本质的差异是商业模式驱动的设计哲学。Intel是IDM垂直整合制造CPU、互联、协议全是自己的。好处是软硬件协同优化做得极致UPI的延迟、Snoop Filter的容量、Mesh的路由算法全都是为自家核心量身定做的。坏处是生态封闭你想加个第三方加速器想保持缓存一致得看Intel支不支持。ARM是IP授权模式CHI是公开规范CMN是可选IP。好处是灵活厂商可以只买核心自己搭互联也可以买CMN还可以混搭。坏处是碎片化不同厂商的CHI实现可能有细微差异跨片一致性的兼容性需要额外验证。这个差异直接体现在调试体验上。Intel平台你基本只能用Intel那套工具比如VTune、pcm但工具和硬件匹配度高。ARM平台工具链更杂但选择多出了问题可能要自己啃协议规范。4.2 目录实现的细节差异虽然两家都用分布式目录但细节差别不小。维度IntelUPI Snoop FilterARMCHI CMN HN-F目录位置与LLC slice绑定分布式与HN-F绑定按地址分片状态粒度较粗主要跟踪Modified/Shared较细UC/UD/SC/SD多状态Snoop方式定向snoop靠目录过滤定向snoop支持DCTDirect Cache Transfer跨片扩展UPI点对点拓扑受限CCIX/CXL拓扑更灵活可配置性固定随CPU型号定高度可配置厂商可裁剪**DCTDirect Cache Transfer**是CHI里一个很实用的特性snoop的时候如果数据在某个缓存里是Dirty的可以直接从那个缓存传到请求方不用先写回Home再转发。这省了一趟往返对跨片延迟帮助很大。Intel也有类似机制但CHI把它标准化了。4.3 延迟和带宽的实测感受从公开的架构参数和实际测试经验看两家的跨片延迟量级差不多同插槽内跨Mesh大概几十纳秒跨插槽大概100到200纳秒。但带宽扩展性上ARM的MeshCCIX/CXL方案理论上更灵活因为可以堆更多链路Intel的UPI链路数是固定的受CPU型号限制。不过实际表现还要看软件。NUMA感知做得好的系统跨片访问比例低延迟差异就不明显。反过来如果应用到处乱访问内存再好的互联也救不了。5. 落地到系统调优NUMA、绑核与验证的实操细节5.1 看清拓扑再动手不管Intel还是ARM调优第一步永远是看清拓扑。Linux下常用# 查看NUMA节点和距离 numactl --hardware # 查看CPU和NUMA的对应关系 lscpu | grep -i numa # 查看每个节点的内存和CPU cat /sys/devices/system/node/node*/cpulist cat /sys/devices/system/node/node*/meminfo在ARM服务器上numactl --hardware的输出可能和Intel不太一样因为CMN的地址映射方式不同节点划分可能更细。有些ARM平台会把每个HN-F覆盖的地址范围作为一个NUMA节点节点数可能比插槽数多。5.2 绑核策略要分场景绑核不是无脑绑本地就完事得看应用类型延迟敏感型Redis、内存数据库进程和内存都绑同一个节点numactl --cpunodebindN --membindN。带宽敏感型流式计算、视频转码内存交错分布numactl --interleaveall让多个内存控制器并行。混合型主线程绑本地工作线程按数据分片绑不同节点这需要应用自己支持NUMA感知。注意绑核之后一定要验证。用numastat看numa_hit和numa_miss的比例miss高说明内存分配没绑住白绑了。5.3 跨片一致性的验证思路如果你在做芯片验证或者系统集成跨片一致性是最容易出问题的地方。我总结几个验证要点压力测试要覆盖跨片路径故意让两个片上的核心反复读写同一块内存看有没有丢更新或者读到旧值。关注目录溢出目录容量有限如果工作集太大导致目录项被驱逐一致性行为会退化性能骤降。检查snoop风暴如果目录失效snoop可能退化成广播互联带宽瞬间打满。用性能计数器监控snoop流量。跨片原子操作原子操作在跨片场景下最容易出问题要专门测。在ARM平台上CMN有专门的DTMDebug Trace Monitor和性能计数器可以抓CHI消息的流向。Intel平台则可以用uncore性能计数器看UPI和Mesh的流量。这些工具是排查一致性问题的利器。6. 几个容易踩的坑和我的实际体会第一个坑是把NUMA当摆设。很多中间件默认不感知NUMA启动起来所有线程挤在一个节点内存却分散在多个节点。这种配置在低负载时看不出问题一上压力跨片流量就爆。我的习惯是部署新服务前先跑一遍numastat确认内存分配策略符合预期。第二个坑是忽略UPI/CCIX链路的带宽上限。跨片一致性再优雅物理链路带宽是硬上限。如果应用的数据共享模式是高频小数据跨片同步那不管协议多先进都会被链路延迟和带宽卡死。这种场景应该从算法层面减少跨片共享而不是指望硬件。第三个坑是ARM平台上不同厂商的CHI实现差异。CHI是规范但规范允许实现有差异。我遇到过某厂商的CMN配置里HN-F的目录替换策略比较激进导致某些访问模式下目录命中率低性能比预期差不少。这种问题只能靠实际压测发现看规范是看不出来的。第四个坑是虚拟化环境下的NUMA透传。虚拟机里看到的NUMA拓扑可能是假的vCPU和物理NUMA的映射关系如果没配好跨片访问会非常严重。KVM下要用numatune和vcpupin把vCPU和内存都绑到物理节点别偷懒。最后分享一个我常用的快速判断方法如果一台多路机器的性能明显低于单路机器的两倍先别怀疑CPU去看NUMA。十有八九是跨片访问比例太高。用perf stat -e抓一下node-loads和node-load-misses这类事件跨节点访问的比例一目了然。这个习惯帮我省了无数次瞎调参数的时间。
返回列表