我听说有个叫 ScaleMP 的公司是专门做这个的,不过我没用过他们的产品。他们自己创造了个名词 “Virtualization for Aggregation”。
先说结论:在有 InfiniBand 的情况下,把多台机器虚拟成一台机器(众核、大内存、大硬盘),是完全可行的。
多核刚出现的时候,内存总线是所有 CPU 竞争使用的,一个 CPU 从内存取数据时,其他的 CPU 就必须等待。一个朴素的想法是,如果这些计算分布在不同的计算机上,而且任务划分适当,每个计算机上的 CPU 就可以访问自己的内存,互不干扰。基于 “CPU 与内存配对” 的理念,NUMA (Non-Uniform Memory Access) 就是若干个(CPU,内存)组成的系统,CPU 访问自己的内存很快,但访问别人的内存就比较慢。操作系统和应用程序都可以针对 NUMA 做优化,使指令和数据的局部性得以保持。
NUMA 中各 CPU 之间如果通过一条总线连接,则很快这条总线就会堵死,因此 CPU 之间连接的拓扑结构是很有讲究的,事实上跟网络拓扑结构本质上是一回事。网络接口(CPU)A 和 B 通信的同时,C 和 D 也可以通信,事实上 “全线速交换”(full bisection)是交换机的一项重要技术指标,也就是所有网络接口(CPU)可以同时全速收发数据。
然而,定制超级计算机是非常贵的,把若干台 off-the-shelf 的机器虚拟成一台众核、大内存、大硬盘的机器,是很自然的想法。好处是:对时间复杂度较低但空间复杂度很高的任务,可以利用更多的内存;对大任务,简化在机器之间发消息的编程(直接访问就行了);对大量不相关的小任务,降低系统管理员的管理负担。
那么,为什么分布式系统的设计者不这么做呢?简而言之:网络协议栈坑了。
如果使用 socket 和 TCP/IP 协议栈,延迟大约是在 300 微秒左右。300 微秒相比硬盘的 8 毫秒,很快了吧?但内存的延迟是 0.1 微秒,网络和内存之间有 500 倍的差距。如果把本地内存看成是远程内存的缓存,只要缓存命中率从 99% 降到 98%,平均延迟就会增加 83%。这就意味着程序员要精心调整任务在各节点上的分配,提高缓存命中率。
然而,网络的 300 微秒延迟是可以改变的。RDMA(Remote DMA)over InfiniBand 的延迟在 1 微秒以下,RDMA over Ethernet 的延迟可以达到 3 微秒。远程访问的延迟仅比访问本地内存高 10 或者 30 倍,这样程序员精心提高缓存命中率就显得不是那么重要了。比如,从 L1 cache 的 1 纳秒到 L2 cache 的 3 纳秒到 L3 cache 的 15 纳秒到内存的 100 纳秒,每一级都没有很大的跳跃,因此缓存策略就不需要浪费程序员的时间了。
由于 RDMA 绕过了 CPU,分布式系统的另一大敌——单位时间所能处理的事务数——也就很大程度上缓解了。基于 socket 的 bind9 每秒只能处理几万个 DNS 请求,CPU 都耗在协议栈里了;而 RDMA 能够把 10 Gbps 的网络占满,也就是每秒处理数百万个远程内存访问。
此外,SSD 的随机访问延迟大约是 50 微秒,比 TCP/IP 快一个数量级,更重要的是 TCP/IP 网络延迟不稳定,因此宁可从 SSD 里读取数据也不要远程从其他机器上取数据。用过 NFS 之类远程文件系统的都见识过网络不稳定的麻烦,校园网内 1ms 的网络延迟相比机械磁盘的 8ms,按说可以忽略,但实际用起来,本地磁盘比远程磁盘好很多。InfiniBand 和 RoCE 通过流控(flow control)实现了无丢包的网络,延迟稳定。RDMA 的延迟比 SSD 还要快一个数量级,这会改变很多网络系统的设计。
网络的平均延迟、吞吐量、延迟稳定性解决了,阻碍远程内存访问、远程磁盘访问的就只是程序员的惰性了。
最后澄清一点,把多台机器虚拟成一台机器,不等于不需要并行算法了。一些传统算法本来就并行程度不高,连一台机器上的多核都用不好,给更多的核和更大的内存有什么用?要设计专门的算法来提高并行度,这事不能指望计算机自动完成。
下面的论文是“1分钟内排序最多数据”世界记录的保持者,集群的数据存储与负责计算的节点是分开的,交换机之间使用 CLOS 拓扑结构连接以保证全线速交换。
下面的论文实现的 RoCE(RDMA over Converged Ethernet, 在以太网上实现 Remote DMA)比 TCP/IP 协议栈在延迟和吞吐量两个指标上都提高了一个数量级,最坏情况延迟降低了两个数量级。远程读取大约是 3 微秒,远程发消息大约是 10 微秒。