8.2.5 分布式共享存储器

虽然RPC有它的吸引力,但即便是在多计算机里,很多程序员仍旧偏爱共享存储器的模型并且愿意使用它。让人相当吃惊的是,采用一种称为分布式共享存储器(Distributed Shared Memory,DSM)(Li,1986;Li和Hudak,1989)的技术,就有可能很好地保留共享存储器的幻觉,尽管这个共享存储器实际并不存在。有了DSM,每个页面都位于如图8-1所示的某一个存储器中。每台机器有其自己的虚拟内存和页表。当一个CPU在一个它并不拥有的页面上进行LOAD和STORE时,会陷入到操作系统当中。然后操作系统对该页面进行定位,并请求当前持有该页面的CPU解除对该页面的映射并通过互连网络发送该页面。在该页面到达时,页面被映射进来,于是出错指令重新启动。事实上,操作系统只是从远程RAM中而不是从本地磁盘中满足了这个缺页异常。对用户而言,机器看起来拥有共享存储器。

实际的共享存储器和DSM之间的差别如图8-21所示。在图8-21a中,是一台配有通过硬件实现的物理共享存储器的真正的多处理机。在图8-21b中,是由操作系统实现的DSM。在图8-21c中,我们看到另一种形式的共享存储器,它通过更高层次的软件实现。在本章的后面部分,我们会讨论第三种方式,不过现在还是专注于讨论DSM。

阅读 ‧ 电子书库
图 8-21 实现共享存储器的不同层次:a)硬件;b)操作系统;c)用户层软件

先考察一些有关DSM是如何工作的细节。在DSM系统中,地址空间被划分为页面(page),这些页面分布在系统中的所有节点上。当一个CPU引用一个非本地的地址时,就产生一个陷阱,DSM软件调取包含该地址的页面并重新开始出错指令。该指令现在可以完整地执行了。这一概念如图8-22a所示,该系统配有16个页面的地址空间,4个节点,每个节点能持有6个页面。

广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元

在这个例子中,如果CPU 0引用的指令或数据在页面0、2、5或9中,那么引用在本地完成。引用其他的页面会导致陷入。例如,对页面10的引用会导致陷入到DSM软件,该软件把页面10从节点1移到节点0,如图8-22b所示。

1.复制

对基本系统的一个改进是复制那些只读页面,如程序代码、只读常量或其他只读数据结构,它可以明显地提高性能。举例来说,如果在图8-22中的页面10是一段程序代码,CPU 0对它的使用可以导致将一个副本送往CPU 0,从而不用打扰CPU 1的原有存储器,如图8-22c所示。在这种方式中,CPU 0和CPU 1两者可以按需要经常同时引用页面10,而不会产生由于引用不存在的存储器页面而导致的陷阱。

阅读 ‧ 电子书库
图 8-22 a)分布在四台机器中的地址空间页面;b)在CPU 1引用页面10后的情形;c)如果页面10是只读的并且使用了复制的情形

另一种可能是,不仅复制只读页面,而且复制所有的页面。只要有读操作在进行,实际上在只读页面的复制和可读写页面的复制之间不存在差别。但是,如果一个被复制的页面突然被修改了,就必须采取必要的措施来避免多个不一致的副本存在。如何避免不一致性将在下面几节中进行讨论。

2.伪共享

在某些关键方式上DSM系统与多处理机类似。在这两种系统中,当引用非本地存储器字时,从该字所在的机器上取包含该字的一块内存,并放到进行引用的(分别是内存储器或高速缓存)相关机器上。一个重要的设计问题是应该调取多大一块。在多处理机中,其高速缓存块的大小通常是32字节或64字节,这是为了避免占用总线传输的时间过长。在DSM系统中,块的单位必须是页面大小的整数倍(因为MMU以页面方式工作),不过可以是1个、2个、4个或更多个页面。事实上,这样做就模拟了一个更大尺寸的页面。

对于DSM而言,较大的页面大小有优点也有缺点。其最大的优点是,因为网络传输的启动时间是相当长的,所以传递4096字节并不比传输1024个字节多花费多少时间。在有大量的地址空间需要移动时,通过采用大单位的数据传输,通常可减少传输的次数。这个特性是非常重要的,因为许多程序表现出引用上的局部性,其含义是如果一个程序引用了某页中的一个字,很可能在不久的将来它还会引用同一个页面中其他字。

另一方面,大页面的传输造成网络长期占用,阻塞了其他进程引起的故障。还有,过大的有效页面引起了另一个问题,称为伪共享(false sharing),如图8-23所示。图8-23中一个页面中含有两个无关的共享变量A和B。进程1大量使用A,进行读写操作。类似地,进程2经常使用B。在这种情形下,含有这两个变量的页面将在两台机器中来回地传送。

阅读 ‧ 电子书库
图 8-23 含有两个无关变量的页面的伪共享

这里的问题是,尽管这些变量是无关的,但它们碰巧在同一个页面内,所以当某个进程使用其中一个变量时,它也得到另一个。有效页面越大,发生伪共享的可能性也越高;相反,有效页面越小,发生伪共享的可能性也越少。在普通的虚拟内存系统中不存在类似的现象。

理解这个问题并把变量放在相应的地址空间中的高明编译器能够帮助减少伪共享并改善性能。但是,说起来容易做起来难。而且,如果伪共享中节点1使用某个数组中的一个元素,而节点2使用同一数组中的另一个元素,那么即使再高明的编译器也没有办法消除这个问题。

3.实现顺序一致性

如果不对可写页面进行复制,那么实现一致性是没有问题的。每个可写页面只对应有一个副本,在需要时动态地来回移动。由于并不是总能提前了解哪些页面是可写的,所以在许多DSM系统中,当一个进程试图读一个远程页面时,则复制一个本地副本,在本地和远程各自对应的MMU中建立只读副本。只要所有的引用都做读操作,那么一切正常。

但是,如果有一个进程试图在一个被复制的页面上写入,潜在的一致性问题就会出现,因为只修改一个副本却不管其他副本的做法是不能接受的。这种情形与在多处理机中一个CPU试图修改存在于多个高速缓存中的一个字的情况有类似之处。在多处理机中的解决方案是,要进行写的CPU首先将一个信号放到总线上,通知所有其他的CPU丢弃该高速缓存块的副本。这里的DSM系统以同样的方式工作。在对一个共享页面进行写入之前,先向所有持有该页面副本的CPU发出一条消息,通知它们解除映射并丢弃该页面。在其所有解除映射等工作完成之后,该CPU便可以进行写操作了。

在有详细约束的情况下,允许可写页面的多个副本存在是有可能的。一种方法是允许一个进程获得在部分虚拟地址空间上的一把锁,然后在被锁住的存储空间中进行多个读写操作。在该锁被释放时,产生的修改可以传播到其他副本上去。只要在一个给定的时刻只有一个CPU能锁住某个页面,这样的机制就能保持一致性。

另一种方法是,当一个潜在可写的页面被第一次真正写入时,制作一个“干净”的副本并保存在发出写操作的CPU上。然后可在该页上加锁,更新页面,并释放锁。稍后,当一个远程机器上的进程试图获得该页面上的锁时,先前进行写操作的CPU将该页面的当前状态与“干净”副本进行比较并构造一个有关所有已修改的字的列表,该列表接着被送往获得锁的CPU,这样它就可以更新其副本页面而不用废弃它(Keleher等人,1994)。