存储一致性模型研究——Research of Memory Consistency Model
一致性模型:
所谓存储一致性模型(Memory Consistency Model),实际上是系统设计者与应用程序员之间的一种约定。如果应用软件遵从一定的规则访问虚内存系统,则应用软件可获得正确的存储访问结果;反之,若破坏约定的规则,则存储访问的正确性不受保证。
从某种意义上来讲,存储一致性模型对共享存储系统中多处理机的访存次序作了限制,从而对性能有影响。分布式共享存储系统(DSM)的一个根本目标就是让一个通过局域网连接起来的工作站集群,共享单一的分页虚地址空间,使在工作站集群之上运行程序的效果类似于程序在单机之上的运行。在最简单的变体中,每页存在于一个确定的机器中,对本地页面的查询速度等同于对内存的访问速度,而访问远程机器的页面查询请求将引发段违例信号(SIGSEGV),这将导致程序陷入到操作系统之中,由操作系统来处理缺页中断,操作系统随之发送一个消息至远程机以找到所需的页面并等待远程机将该页面回送过来。本地机器获得远程页面之后,引发段违例信号的指令将被重启并能继续往下执行。
为达到上述目标,需要构造一个虚内存子系统,由它来捕获在DSM系统中的页面访问错及负责从网络上的其它结点处取回数据并完成必要的同步操作。
当应用程序的数据相关性比较大时,这种对每一可写页面只维护一个副本的策略将引发严重的性能瓶颈。维护多个副本的策略能减缓性能的瓶颈效应,但又带来一个新的问题,即如何在多个副本之间维护数据的一致性?为解决这个问题,提出了一致性存储模型。大致来说,按照对一致性的要求由强到弱的顺序,可区分为以下几类。
严格一致性模型(Strict Consistency)
这是对一致性要求最严格的一种模型,它由以下条件来描述:任何对内存位置X的读操作将返回最近对位置X进行写操作而存入的值。
在DSM系统中,这是一种理想模型,但受网络延迟的影响,不可能实现。在DSM系统中实现的多种一致性模型,都是对严格一致性模型在不同程度上的放松;而在单机环境下,任何存储访问序列都满足严格一致性的要求。
顺序一致性模型(Sequential Consistency)
顺序一致性对存储器的限制较严格一致性稍弱,顺序一致性的存储器要满足以下的条件:
- 每个进程内部各个操作的顺序是确定不变的;
. - 假如所有CPU上的进程都对某个存储单元执行操作,那么,它们的操作顺序是确定的,即任一进程都能感知到这些进程同样的操作顺序。
上述条件的含义是指,当多个进程分别在不同的机器上并行执行时,只要所有的进程都保持同样的顺序访问存储器,那么,任何有效的交叉访问执行都是可接受的。在顺序一致性模型中,时间不再是影响一致性的因素,它关心的是:所有进程必须能感受到一致的内存访问序列。
顺序一致性模型不确保进程的一次读操作能够返回由另一进程所写入的最新值。
因果一致性模型(Causal Consistency)
它是对顺序一致性模型的弱化,它要求在具有潜在因果关系的操作之间保持其一致的顺序。一般性的描述如下:有潜在性因果相关的写操作必须以同样的顺序被各进程所感知,而并发的写操作在不同的机器上可以有不同的顺序。
在因果一致性的存储管理系统中,上述操作序列是合法的,而在顺序一致性或严格一致性模型中,它们是非法操作。
管道一致性模型(Pipelined RAM)
管道一致性模型是对因果一致性模型的进一步弱化,它满足以下条件:由某一个进程完成的写操作能够被所有别的进程按序地感知到,而从不同进程中来的写操作对不同的进程可有不同的顺序。
弱一致性模型(Weak Consistency)
尽管PRAM模型与较之严格的一致性模型相比,能够获得更好的性能,但因为它对同一个进程(源)所产生的结果仍然作了必须按序地送达所有别的进程的要求,故对很多应用程序而言,仍然受到了模型的限制。并非所有的进程都要求看到所有的写操作的结果,让它们按序地看到写操作的结果则更是没有必要。在此,模型的开销能够严重地影响应用程序的性能。考虑到运算的中间结果在大多数情况下并没有必要传播出去的情况,我们必须对一致性要求作进一步的放松,我们只有在需要传播写操作结果的时候才将结果传播出去,除此之外,一切都是完全并行的。为了同步操作的目的,在弱一致性模型中引入同步变量。
弱一致性模型必须满足的条件:
- 对同步变量的访问满足顺序一致性的要求。
. - 对同步变量的访问,只有在以前的写操作在各处都完成之后才能完成。
. - 对数据的操作(读或写),只有在以前的对同步变量的访问完成之后才能完成。
.
第一点说明所有的进程都能以同样的顺序感知到所有对同步变量的访问。当一个进程访问某同步变量时,它会把对该同步变量的访问广播出去,在该进程对该同步变量的操作成功之前,任何别的进程对同步变量的访问都将被阻塞。
第二点说明对同步变量的访问会导致对内存进行刷新的结果。当一个同步访问完成之后,那么,所有先前的写操作可以同时确保已完成。当某进程对一个共享数据作了更新之后,它可以通过同步操作将新值传播出去。
第三点说明当一个进程在读一个共享数据(非同步变量)时,通过同步操作,它能获得该共享数据的最新值。
释放一致性模型(Release Consistency)
对于同步变量的访问,弱一致性模型有一个问题:就是无法区分进程是准备进入临界区还是已经完成对共享变量的操作而准备退出临界区,其后果就是进程在以下两种情况下都必须采取同步操作:
- 将局部写操作的结果传播出去。
. - 从别的机器上收集共享数据的最新值。
.
如果能将进入和退出临界区这两个动作区分开来,则能实现一种更为高效的存储一致性模型─释放一致性模型。释放一致性模型提供了两类同步操作:Acquire和Release。某进程将要进入临界区时执行Acquire操作,退出临界区时执行Release操作。也可以不用临界区而用栅栏(Barrier)同步来实现释放一致性协议。栅栏是一种同步机制,它要求所有的进程全都到达程序的某一同步点之后,各个进程才能继续往下执行。
借助于Acquire和Release操作,我们可以把某些特殊的共享变量保护起来,并维护它们的一致性。当然,应用程序必须确知它需要维护其一致性的数据,这也给应用程序的编制增加了一些协议开销,但整体性能提高了
通常,如果一个分布式共享存储系统满足释放一致性,则它必须遵从以下的规则:(1)某进程只有在成功地完成Acquire操作之后,才能确保对一般共享变量(非共享同步变量)访问的正确性。(2)某进程只有在完成对共享数据的读写操作之后,Release操作才能完成。(3)Acquire和Release操作必须满足管道一致性要求。
为了更进一步提高性能,另外一种实现释放一致性模型的协议被称之为懒释放一致性(Lazy Release Consistency),与之对应,一般的实现被称之为勤释放一致性(Eager Release Consistency)。它们之间的区别在于,勤释放一致性协议在Release操作结束之后,将所有已修改的数据传送给所有别的进程,这样,别的进程都拥有此最新数据的一个副本并可在本地访问它们。但实际情况是有可能别的进程并不需要该共享数据,这样就浪费了带宽并给程序带来不必要的延迟。懒释放一致性协议在Release操作结束之后,并不急于传送新的数据,而是在别的进程执行Acquire操作之后,由别的进程向它提出获取新数据的请求时,它响应该请求并把共享数据的最新值传送给特定的进程,这样,系统的性能又获得了提高。
单项一致性模型(Entry Consistency)
另外一种用于提高临界区操作并行性的一致性模型是由Bershad等人于1993年提出的单项一致性模型。它要求编程人员在临界区的开始和结束时使用Acquire和Release操作,但与释放一致性不同的是:它要求每个共享变量都与某同步变量相关联,同步变量可以是锁或者栅栏。以并行访问一个数组的不同元素为例,它要求给不同的数组元素加不同的锁,只有当对同步变量的Acquire操作完成之后,相关的共享数据才得到一致性保证。单项一致性模型也不同于懒释放一致性模型,后者并不将共享数据与锁或栅栏相关联,而是在对同步变量作Acquire操作之后,才能确定它需要哪些共享数据。
因为只有少量的共享变量需要同步,所以如果将每一个同步变量与多个共享数据相关联,则会减少对同步变量的Acquire和Release操作的开销。同时,它还允许多个包含不同变量的临界区并行操作,从而提高了并行性。它的代价主要是每个共享变量均要与一个同步变量相关联,从而带来一些开销及复杂性。
同步变量的使用规则如下:
每个同步变量有一个当前拥有者(即最近获取到该同步变量的进程),拥有者可以对临界区进行重复的操作而无需在网络上发送任何消息。这时,一个想获得此同步变量的进程需要给当前拥有者发送一个消息,以获得对同步变量操作的所有权及与此同步变量相关联的共享变量的值。在非互斥的情况之下,允许多个进程同时拥有某同步变量,但只能对共享数据进行读操作,而不能写。满足单项一致性的条件是:
- 在当前拥有者对数据的更新操作未完成之前,不能执行另一进程对同步变量的Acquire操作。
. - 如果某进程以互斥模式访问某同步变量,则在该进程释放此同步变量之前,任何别的进程即使是在非互斥模式下都将无法获得该同步变量。
. - 如果某进程以互斥模式访问一个同步变量,则在该进程完成操作之后,任何进程对此同步变量的后继非互斥访问,都只有在成为该同步变量的拥有者之后才能完成。