精华内容
参与话题
问答
  • 缓存一致性

    千次阅读 2019-01-10 18:39:42
    缓存一致性硬件单核多核缓存一致性协议(MESI)MESI 状态转换 硬件 硬件之间的处理速度不相等,尤其是处理器和内存之间。一般都是内存跟不上处理器的处理速度。 所有在他们之间引入了缓存(cache)。 缓存有2大特点...

    硬件

    硬件之间的处理速度不相等,尤其是处理器和内存之间。一般都是内存跟不上处理器的处理速度。
    所有在他们之间引入了缓存(cache)。
    缓存有2大特点:
    1.时间局部性(被使用过的内存地址很有可能被再次使用到)
    2.空间局部性(被使用的地址周围部分也有可能被使用到,所以将内存中某块地址引入缓存里的时候通常会将周围的也引入缓存中)

    单核

    在这里插入图片描述
    单核单缓存,这种就直来直往,从memory中取出数据通过bus(总线)放入cache,然后cpu访问cache。

    多核

    在这里插入图片描述
    多核下,每个核拥有自己的一级缓存,可能每个一级缓存里面都有一部分的共享内存,即他们保存着memory中相同的一块。
    如果没有约束,这可能会对memory中的数据造成破坏,如果多个一级缓存同时修改了共享区域,并保存至主存中。
    所以引入了 缓存一致性协议(MESI)

    缓存一致性协议(MESI)

    M:被修改(Modified)处理器对缓存的值进行了修改,但是还么同步到主存上,或者发送给其他处理器。
    E:独占(Exclusive)存在于某个缓存中,其他缓存中没有与他相同的地址,且还没有被修改过。
    S:共享(Share)多于一个缓存拥有同一块地址。
    I:无效(Invalid)缓存不在拥有这块地址。

    MESI 状态转换

    在这里插入图片描述
    local 表示当前缓存,remote 表示其他缓存
    例如:
    E表示独享的,就是只有当前缓存存在这块地址,当他被修改了则会从E转换成M
    如果多核(A、B。。。)读取了同样的数据,则他们是S(共享的)。
    A对共享的数据进行了修改,那么S会转换成M,且其他缓存中的S会被转换成I,因为需要进行同步。A将修改的数据同步会主存后,他的状态会变成S,A无法感知他就是唯一的。B如果在读取共享数据,则还是S状态的数据。

    展开全文
  • cpu缓存锁与缓存一致性协议(或者说它的具体实现MESI)是什么关系,我有发现另一篇文章说,缓存锁是基于缓存一致性协议实现的。 那它们两个之间关系是什么,看到很多文章里面说为了解决缓存不一致问题,有几种方案...
  • Redis缓存一致性问题

    千次阅读 2018-11-28 17:27:27
    从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。这种方案下,我们可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,对缓存操作只是尽最大努力即可。也就是说如果数据库写成功,缓存...

    前言

    从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。这种方案下,我们可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,对缓存操作只是尽最大努力即可。也就是说如果数据库写成功,缓存更新失败,那么只要到达过期时间,则后面的读请求自然会从数据库中读取新值然后更新缓存。
    因此,接下来讨论的思路不依赖于给缓存设置过期时间这个方案。

    先更新数据库,再更新缓存

    一、线程安全问题

    假设同时有请求A和请求B进行更新操作,那么会出现如下情景

    1. 线程A更新了数据库
    2. 线程B更新了数据库
    3. 线程B更新了缓存
    4. 线程A更新了缓存

    正确结果应为缓存A数据,但是因为网络原因或者其他原因,导致缓存了B数据,出现脏数据问题。

    二、使用场景问题

    • 若写请求较多,读请求较少,导致缓存数据被频繁更新,浪费性能。
    • 若缓存数据由数据库数据计算得来,则每次写库都要耗费CPU性能做计算更新缓存,浪费性能。

    综上,先更新数据库,再更新缓存不适用于作为redis缓存一致性解决方案。

    先删缓存,再更新数据库

    一、问题

    假设同时有请求A进行更新操作和请求B进行读取操作,那么会出现如下情景

    1. 请求A进行写操作,删除缓存
    2. 请求B查询发现缓存不存在
    3. 请求B去数据库查询得到旧值
    4. 请求B将旧值写入缓存
    5. 请求A将新值写入数据库

    上述情景则会导致缓存不一致问题出现。

    二、延时双删策略

    流程为

    1. 先删除缓存
    2. 再写数据库
    3. 休眠一段时间
    4. 再次删除缓存

    睡眠时间如何确定?
    由于睡眠的原因是为了保证,后续能够删除读库操作误更新的缓存数据,则第二次删除操作应在读库以及更新操作之后,所以睡眠时间应为读库操作时间加上几百毫秒。
    如果数据库采用了读写分离架构怎么办?
    睡眠时间为主从同步延迟时间加上读库耗时加上几百毫秒。
    第二次删除失败解决方案

    1. 若删除失败,将需要删除的key发送至消息队列,另写代码执行删除操作,直到删除成功。
    2. 另起程序,订阅数据库的binlog,对删除失败的key进行删除操作。

    先更新数据库,再删缓存

    问题

    假设同时有请求A进行读取操作,请求B做更新操作,那么会出现如下情景

    1. 缓存刚好失效
    2. 请求A查询数据库,得一个旧值
    3. 请求B将新值写入数据库
    4. 请求B删除缓存
    5. 请求A将查到的旧值写入缓存

    但是,操作3耗时远大于操作2耗时,故这种情况出现的可能性几乎为0,可以忽略不计。
    综上所述,先更新数据库,再删缓存为最优提供缓存一致性解决方案(当然,这里讲的方案不包含各种优化)。

    作者Redis系列文章大全

    Redis入门
    CentOS-7下安装redis-2.8
    Redis配置详解
    Redis数据淘汰策略
    Redis缓存一致性问题
    Redis穿透与雪崩的预防与解决方案
    阻塞IO、非阻塞IO和异步IO
    Redis事物探秘
    Redis持久化浅析
    IO多路复用及select、poll和epoll
    Redis集群-主从复制模式
    Redis集群-哨兵模式

    展开全文
  • 内存模型是怎么解决缓存一致性问题的?

    万次阅读 多人点赞 2018-10-10 09:30:42
    在再有人问你Java内存模型是什么,就把这篇文章发给他这篇...每个CPU会有L1、L2甚至L3缓存,在多核计算机中会有多个CPU,那么就会存在多套缓存,那么这多套缓存之间的数据就可能出现不一致的现象。为了解决这个问...

    再有人问你Java内存模型是什么,就把这篇文章发给他这篇文章中,我们介绍过关于Java内存模型的来龙去脉。

    我们在文章中提到过,由于CPU和主存的处理速度上存在一定差别,为了匹配这种差距,提升计算机能力,人们在CPU和主存之间增加了多层高速缓存。每个CPU会有L1、L2甚至L3缓存,在多核计算机中会有多个CPU,那么就会存在多套缓存,那么这多套缓存之间的数据就可能出现不一致的现象。为了解决这个问题,有了内存模型。内存模型定义了共享内存系统中多线程程序读写操作行为的规范。通过这些规则来规范对内存的读写操作,从而保证指令执行的正确性。

    不知道小伙伴们有没有想过这样的问题:内存模型到底是怎么保证缓存一致性的呢?

    接下来我们试着回答这个问题。首先,缓存一致性是由于引入缓存而导致的问题,所以,这是很多CPU厂商必须解决的问题。为了解决前面提到的缓存数据不一致的问题,人们提出过很多方案,通常来说有以下2种方案:

    1、通过在总线加LOCK#锁的方式。

    2、通过缓存一致性协议(Cache Coherence Protocol)。

    在早期的CPU当中,是通过在总线上加LOCK#锁的形式来解决缓存不一致的问题。因为CPU和其他部件进行通信都是通过总线来进行的,如果对总线加LOCK#锁的话,也就是说阻塞了其他CPU对其他部件访问(如内存),从而使得只能有一个CPU能使用这个变量的内存。在总线上发出了LCOK#锁的信号,那么只有等待这段代码完全执行完毕之后,其他CPU才能从其内存读取变量,然后进行相应的操作。这样就解决了缓存不一致的问题。

    但是由于在锁住总线期间,其他CPU无法访问内存,会导致效率低下。因此出现了第二种解决方案,通过缓存一致性协议来解决缓存一致性问题。

    缓存一致性协议

    缓存一致性协议(Cache Coherence Protocol),最出名的就是Intel 的MESI协议,MESI协议保证了每个缓存中使用的共享变量的副本是一致的。

    MESI的核心的思想是:当CPU写数据时,如果发现操作的变量是共享变量,即在其他CPU中也存在该变量的副本,会发出信号通知其他CPU将该变量的缓存行置为无效状态,因此当其他CPU需要读取这个变量时,发现自己缓存中缓存该变量的缓存行是无效的,那么它就会从内存重新读取。

    在MESI协议中,每个缓存可能有有4个状态,它们分别是:

    M(Modified):这行数据有效,数据被修改了,和内存中的数据不一致,数据只存在于本Cache中。

    E(Exclusive):这行数据有效,数据和内存中的数据一致,数据只存在于本Cache中。

    S(Shared):这行数据有效,数据和内存中的数据一致,数据存在于很多Cache中。

    I(Invalid):这行数据无效。

    关于MESI的更多细节这里就不详细介绍了,读者只要知道,MESI是一种比较常用的缓存一致性协议,他可以用来解决缓存之间的数据一致性问题就可以了。

    但是,值得注意的是,传统的MESI协议中有两个行为的执行成本比较大。

    一个是将某个Cache Line标记为Invalid状态,另一个是当某Cache Line当前状态为Invalid时写入新的数据。所以CPU通过Store Buffer和Invalidate Queue组件来降低这类操作的延时。

    如图:

    cache_sync

    当一个CPU进行写入时,首先会给其它CPU发送Invalid消息,然后把当前写入的数据写入到Store Buffer中。然后异步在某个时刻真正的写入到Cache中。

    当前CPU核如果要读Cache中的数据,需要先扫描Store Buffer之后再读取Cache。

    但是此时其它CPU核是看不到当前核的Store Buffer中的数据的,要等到Store Buffer中的数据被刷到了Cache之后才会触发失效操作。

    而当一个CPU核收到Invalid消息时,会把消息写入自身的Invalidate Queue中,随后异步将其设为Invalid状态。

    和Store Buffer不同的是,当前CPU核心使用Cache时并不扫描Invalidate Queue部分,所以可能会有极短时间的脏读问题

    所以,为了解决缓存的一致性问题,比较典型的方案是MESI缓存一致性协议。

    MESI协议,可以保证缓存的一致性,但是无法保证实时性。

    内存模型

    前面介绍过了缓存一致性模型,接着我们再来看一下内存模型。我们说过内存模型定义一系列规范,来保证多线程访问共享变量时的可见性、有序性和原子性。(更多内容请参考再有人问你Java内存模型是什么,就把这篇文章发给他

    内存模型(Memory Model)如果扩展开来说的话,通常指的是内存一致性模型(Memory Sequential Consistency Model)

    前面我们提到过缓存一致性,这里又要说内存一致性,不是故意要把读者搞蒙,而是希望通过对比让读者更加清楚。

    缓存一致性(Cache Coherence),解决是多个缓存副本之间的数据的一致性问题。

    内存一致性(Memory Consistency),保证的是多线程程序访问内存时可以读到什么值。

    我们首先看以下程序:

    初始:x=0 y=0
    
    Thread1:
    S1:x=1
    L1:r1=y
    
    Thread2:
    S2:y=2
    L2:r2=x
    

    其中,S1、S2、L1、L2是语句代号(S表示Store,L表示Load);r1和r2是两个寄存器。x和y是两个不同的内存变量。两个线程执行完之后,r1和r2可能是什么值?

    注意到线程是并发、交替执行的,下面是可能的执行顺序和相应结果:

    S1 L1 S2 L2 那么r1=0 r2=2
    
    S1 S2 L1 L2 那么r1=2 r2=1
    
    S2 L2 S1 L1 那么r1=2 r2=0
    

    这些都是意料之内、情理之中的。但是在x86体系结构下,很可能得到r1=0 r2=0这样的结果。

    如果没有Memory Consistency,程序员写的程序代码的输出结果是不确定的。

    因此,Memory Consistency就是程序员(编程语言)、编译器、CPU间的一种协议。这个协议保证了程序访问内存时会得到什么值。

    简单点说,内存一致性,就是保证并发场景下的程序运行结果和程序员预期是一样的(当然,要通过加锁等方式),包括的就是并发编程中的原子性、有序性和可见性。而缓存一致性说的就是并发编程中的可见性。

    在很多内存模型的实现中,关于缓存一致性的保证都是通过硬件层面缓存一致性协议来保证的。 需要注意的是,这里提到的内存模型,是计算机内存模型,而非Java内存模型。

    总结

    缓存一致性问题 。硬件层面的问题,指的是由于多核计算机中有多套缓存,各个缓存之间的数据不一致性问题。

    PS:这里还需要再重复一遍,Java多线程中,每个线程都有自己的工作内存,需要和主存进行交互。这里的工作内存和计算机硬件的缓存并不是一回事儿,只是可以相互类比。所以,并发编程的可见性问题,是因为各个线程之间的本地内存数据不一致导致的,和计算机缓存并无关系。

    缓存一致性协议。用来解决缓存一致性问题的,常用的是MESI协议。

    内存一致性模型。屏蔽计算机硬件问题,主要来解决并发编程中的原子性、有序性和一致性问题。

    实现内存一致性模型的时候可能会用到缓存一致性模型。

    思考

    最后,再给大家留一道思考题:

    既然在硬件层面,已经有了缓存一致性协议,可以保证缓存的一致性即并发编程中的可见性,那么为什么在写多线程的代码的时候,程序员要自己使用volatile、synchronized等关键字来保证可见性?

    关于这个思考题的答案,我会在接下来的深入介绍volatile文章中解答。欢迎大家关注我的博客(http://www.hollischuang.com)和公众号(Hollis)第一时间学习。

    在这里插入图片描述

    参考资料

    聊聊原子变量、锁、内存屏障那点事

    Memory Consistency和Cache Coherence

    展开全文
  • 先来梳理下关于高速缓存的一些知识 高速缓存是一种存取速率远比主内存大而容量远比主内存小的存储部件,每个处理器都有其高速缓存。引入高速缓存之后, 处理器在执行内存读、 写操作的时候并不直接与主内存打交道, ...

    先来梳理下关于高速缓存的一些知识

    高速缓存是一种存取速率远比主内存大而容量远比主内存小的存储部件,每个处理器都有其高速缓存。引入高速缓存之后, 处理器在执行内存读、 写操作的时候并不直接与主内存打交道, 而是通过高速缓存进行的。变量名相当于内存地址, 而变量值则相当于相应内存空间所存储的数据。

    从内部结构来看高速缓存相当于一个拉链散列表(ChainedHash Table). 它包含若干桶(Bucket, 硬件上称之为Set), 每个桶又可以包含若干缓存条目(CacheEntry) .
    在这里插入图片描述
    缓存条目可被进一步划分为Tag、Data Block以及Flag这三个部分其中, Data Block也被称为缓存行(CacheLine) , 它是高速缓存与主内存之间的数据交换最小单元 用于存储从内存中读取的或者准备写往内存的数据。 Tag则包含了与缓存行中数据相应的内存地址的部分信息(内存地址的高位部分比特)。 Flag用于表示相应缓存行的状态信息。 缓存行的容量(也被称为缓存行宽度)通常是2的倍数, 其大小在16-256 字节(Byte)之间不等。一个缓存行可以存储若干变量的值, 而多个变量的值则可能被存储在同一个缓存行之中。
    在这里插入图片描述
    处理器在执行内存访问操作时会将相应的内存地址解码。内存地址的解码结果包括 tag、index以及offset这三部分数据。其中,index相当于桶编号,它可以用来定位内存地址对应的桶;

    一个桶可能包含多个缓存条目. tag相当于缓存条目的相对编号, 其作用在于用来与同一个桶中的各个缓存条目中的Tag部分进行比较, 以定位一个具体的缓存条目; 一个缓存条目中的缓存行可以用来存储多个变量,offset是缓存行内的位置偏移, 其作用在于确定一个变量在一个缓存行中的存储起始位置。

    (想自学习编程的小伙伴请搜索圈T社区,更多行业相关资讯更有行业相关免费视频教程。完全免费哦!)

    缓存命中

    根据这个内存地址的解码结果,如果高速缓存子系统能够找到相应的缓存行并且缓存行所在的缓存条目的Flag表示相应缓存条目是有效的, 那么我们就称相应的内存操作产生了缓存命中(CacheHit) 3; 否则,我们就称相应的内存操作产生了缓存未命中(CacheMiss)。

    从性能角度来看,减少缓存未命中

    缓存未命中包括读未命中(Read Miss)和写未命中(Write Miss), 分别对应内存读和写操作。当读未命中产生时, 处理器所需读取的数据会从主内存中加载并被存入相应的缓存行之中。 这个过程会导致处理器停顿(Stall)而不能执行其他指令,这不利于发挥处理器的处理能力。

    缓存未命中不可避免

    由于高速缓存的总容量远小于主内存的总容量,同一个缓存行在不同时刻存储的可能是不同的一段数据, 因此缓存未命中是不可避免的。

    在Linux系统中,我们可以使用Linux内核工具perf来查看程序运行过程中的缓存未命中情况。

    高速缓存通常被称为一级缓存(LI Cache)、 二级缓存(L2 Cache)、 三级缓存(L3 Cache)
    在这里插入图片描述
    在这里插入图片描述
    高速缓存从下到上越接近CPU速度越快,同时容量也越小。现在大部分的处理器都有二级或者三级缓存,从下到上依次为 L3 cache, L2 cache, L1 cache. 缓存又可以分为指令缓存和数据缓存,指令缓存用来缓存程序的代码,数据缓存用来缓存程序的数据L1 Cache,一级缓存,本地core的缓存,分成32K的数据缓存L1d和32k指令缓存L1i,访问L1需要3cycles,耗时大约1ns;

    L2 Cache,二级缓存,本地core的缓存,被设计为L1缓存与共享的L3缓存之间的缓冲,大小为256K,访问L2需要12cycles,耗时大约3ns;

    L3 Cache,三级缓存,在同插槽的所有core共享L3缓存,分为多个2M的段,访问L3需要38cycles,耗时大约12ns;

    一级缓存可能直接被集成在处理器的内核里,因此访问效率非常高。通常包括两部分,一部分用于存储指令,一部分用于存储数据,距离处理器越近的高速缓存,存储速率越快,制造成本越高,容量越小。

    缓存一致性协议

    缓存一致性问题

    多个线程并发访问同一个共享变植的时候,这些线程的执行处理器上的高速缓存各自都会保留一份该共享变撒的副本,这就带来一个新问题一个处理器对其副本数据进行更新之后, 其他处理器如何 “察觉” 到该更新并做出适当反应, 以确保这些处理器后续读取该共享变扯时能够读取到这个更新。这就是缓存一致性问题。

    例如:

    CPU-0读取主存的数据,缓存到CPU-0的高速缓存中,CPU-1也做了同样的事情,而CPU-1把count的值修改成了2,并且同步到CPU-1的高速缓存,但是这个修改以后的值并没有写入到主存中,CPU-0访问该字节,由于缓存没有更新,所以仍然是之前的值,就会导致数据不一致的问题.

    实质

    实质就是如何防止读脏数据和丢失更新的问题。 各个厂家提供了不少解决方案,最后选择了缓存一致性协议。
    总线锁

    当一个CPU对其缓存中的数据进行操作的时候,往总线中发送一个Lock信号。其他处理器的请求将会被阻塞,那么该处理器可以独占共享内存。总线锁相当于把CPU和内存之间的通信锁住了,所以这种方式会导致CPU的性能下降,所以P6系列以后的处理器,出现了另外一种方式,就是缓存锁。

    缓存锁

    如果缓存在处理器缓存行中的内存区域在LOCK操作期间被锁定,当它执行锁操作回写内存时,处理不在总线上声明LOCK信号,而是修改内部的缓存地址,然后通过缓存一致性机制来保证操作的原子性,因为缓存一致性机制会阻止同时修改被两个以上处理器缓存的内存区域的数据,当其他处理器回写已经被锁定的缓存行的数据时会导致该缓存行无效。所以如果声明了CPU的锁机制,会生成一个LOCK指令,会产生两个作用。

    1. Lock前缀指令会引起引起处理器缓存回写到内存,在P6以后的处理器中,LOCK信号一般不锁总线,而是锁缓存。
    2. 一个处理器的缓存回写到内存会导致其他处理器的缓存无效

    X86基于MESI协议的问题。

    MESI (Modified-Exclusive-Shared-Invalid)协议是一种广为使用的缓存一致性协议, x86处理器所使用的缓存一致性协议就是基于MESI协议的。

    MESI协议对内存数据访问的控制类似读写锁,它使得针对同一地址的读内存操作是并发的,而针对同一地址的写内存操作是独占的,即针对同一内存地址进行的写操作在任意一个时刻只能够由一个处理器执行。 在MESI协议中, 一个处理器往内存中写数据时必须持有该数据的所有权。

    为了保障数据的一致性. MESI将缓存条目的状态划分为Modified(更新的)、Exclusive(排外的)、Shared(共享的)和Invalid(无效的)这4种, 并在此基础上定义了一组消息(Message)用于协调各个处理器的读、 写内存操作。
    MESI协议中一个缓存条目的Flag值有以下4种可能:

    •Invalid (无效的.记为I)。 该状态表示相应缓存行中不包含任何内存地址对应的有效副本数据。 该状态是缓存条目的初始状态。

    •Shared (共享的,记为s)。 该状态表示相应缓存行包含相应内存地址所对应的 副本数据。 并且, 其他处理器上的高速缓存中也可能包含相同内存地址对应的副本数据。因此,一个缓存条目的状态如果为 Shared, 并且其他处理器上也存在 Tag 值与该缓存条目的 Tag 值相同的缓存条目,那么这些缓存条目的状态也为 Shared。 处于该状态的缓存条目, 其缓存行中包含的数据与主内存中包含的数据一致。

    •Exclusive (独占的,记为 E) 。该状态表示相应缓存行包含相应内存地址所对应 的副本数据。 并且, 该缓存行以独占的方式保留了相应内存地址的副本数据, 即 其他所有处理器上的高速缓存当前都不保留该数据的有效副本。 处千该状态的缓 存条目, 其缓存行中包含的数据与主内存中包含的数据一致。

    •Modified (更改过的,记为 M) 。该状态表示相应缓存行包含对相应内存地址所做的更新结果数据。 由于 MESI 协议中的任意一个时刻只能够有一个处理器对同一内存地址对应的数据进行更新, 因此在多个处理器上的高速缓存中 Tag 值相同 的缓存条目中, 任意一个时刻只能够有一个缓存条目处于该状态。 处于该状态的 缓存条目, 其缓存行中包含的数据与主内存中包含的数据不一致。
    MESI 协议定义了一组消息 (Message) 用于协调各个处理器的读、 写内存操作,如表11-1 所示。 比照 HTTP 协议, 我们可以将 MESI 协议中的消息分为请求消息和响应消息。处理器在执行内存读、写操作时在必要的情况下会往总线 (Bus) 中发送特定的请求消息,同时每个处理器还嗅探 (Snoop, 也称拦截)总线中由其他处理器发出的请求消息并在一 定条件下往总线中回复相应的响应消息。
    在这里插入图片描述
    MESI协议的处理器读写操作?

    下面讨论在Processor 0上读取数据S的实现。

    设内存地址A上 的数据S是处理器Processor 0和处理器Processor l可能共享的数据。

    下面讨论在Processor 0上读取数据S的实现。Processor 0会根据地址A找到对应的 缓存条目, 并读取该缓存条目的Tag和Flag值(缓存条目状态)。 为讨论方便, 这里我们不讨论Tag值的匹配问题。Processor0找到的缓存条目的状态如果为M、 E或者s. 那么 该处理器可以直接从相应的缓存行 中读取地址 A所对应的数据, 而无须往总线中发送任何消息。Processor 0找到的缓存条目的状态如果为I. 则说明该处理器的高速缓存中并不 包含S的有效副本数据,此时Processor 0需要往总线发送Read消息以读取地址A对应的 数据, 而其他处理器Processor l (或者主内存)则需要回复ReadResponse以提供相应的 数据

    Processor 0接收到ReadResponse消息时, 会将其中携带的数据(包含数据S的数据块) 存入相应的缓存行 并将相应缓存条目的状态更新为S。 Processor 0 接收到的Read Response消息可能来自主内存也可能来自其他处理器(Processor I)。

    Processor I会嗅探总线中由其他处理器发送的消息。Processor I嗅探到Read消息的时候, 会从该消息中取 出待读取的内存地址.并根据该地址在其高速缓存中查找对应的缓存条目。如果Processor I 找到的缓存条目的状态不为I (表11-2所示的情况). 则说明该处理器的高速缓存中有待 读取数据的副本,此时Processor l会构造相应的ReadResponse消息并将相应缓存行所存储的整块数据(而不仅仅是Processor0所请求的数据s) ,. 塞入 “ 该消息。如果Processor1 找到的相应缓存条目的状态为M, 那么Processor1可能在往总线发送ReadResponse消息 前将相应缓存行中的数据写入主内存。Processor1往总线发送ReadResponse之后,相应缓存条目的状态会被更新为 S。 如果 Processor I 找到的高速缓存条目的状态为I, 那么 Processor 0所接收到的ReadResponse消息就来自主内存。

    可见,在Processor0读取内存 的时候,即便Processor I对相应的内存数据进行了更新且这种更新还停留在Processor I 的高速缓存中而造成高速缓存与主内存中的数据不一致,在MESI消息的协调下这种不一 致也并不会导致Processor0读取到一个过时的旧值。

    讨论Processor 0往地址A写数据的实现

    任何一个处理器执行内存写操作时必须拥有相应数据的所有权。在执行内存写操作时,Processor0会先根据内存地址A找到相应的缓存条目。Processor0所找到的缓存条目的状态若为E或者M, 则说明该处理器已经拥有相应数据的所有权,此时该处理器可以直接将数据写入相应的缓存行并将相应缓存条目的状态更新为M 。Processor0所找到的缓存条目的状态如果不为E、M, 则该处理器需要往总线发送Invalidate消息以获得数据的所有权。其他处理器接收到Invalidate消息后会 将其高速缓存中相应的缓存条目状态更新为I (相当于删除相应的副本数据)并回复 Invalidate Acknowledge消息。发送Invalidate消息的处理器(即内存写操作的执行处理器),必须在接收到其他所有处理器所回复的所有I nvalidate Acknowledge消息之后再将数据更 新到相应的缓存行之中.
    在这里插入图片描述
    Processor 0所找到的缓存条目的状态若为s. 则说明Processor l上的高速缓存可能也保留了地址A对应的数据副本(场景I). 此时Processor 0需要往总线发送Invalidate消息。Processor 0在接收到其他所有处理器所回复的InvalidateAcknowledge消息之后会将相应的缓存条目的状态更新为 E, 此时 Processor 0 获得了地址 A 上数据的所有权。 接着,Processor 0 便可以将数据写入相应的缓存行, 并将相应缓存条目的状态更新为 M 。Processor 0 所找到的缓存条目的状态若为 I, 则表示该处理器不包含地址 A 对应的有效副本数据(场景 2), 此时 Processor 0 需要往总线发送 Read Invalidate 消息。Processor 0 在接收到 Read Response 消息以及其他所有处理器所回复的 Invalidate Acknowledge 消息之后, 会将相应缓存条目的状态更新为E, 这表示该处理器已经获得相应数据的所有权。接 着, Processor 0 便可以往相应的缓存行中写入数据了并将相应缓存条目的状态更新为 M 。 其他处理器在接收到 Invalidate 消息或者 Read Invalidate 消息之后, 必须根据消息中包含的内存地址在该处理器的高速缓存中查找相应的高速缓存条目。若 Processor I 所找到的高速缓存条目的状态不为 I (场景 2), 那么 Processor I 必须将相应缓存条目的状态更新为I, 以删除相应的副本数据并给总线回复 Invalidate Acknowledge 消息。可见. Invalidate 消息和 Invalidate Acknowledge 消息使得针对同一个内存地址的写操作在任意一个时刻只能由一个处理器执行, 从而避免了多个处理器同时更新同一数据可能导致的数据不一致问题。

    从上述例子来看. 在多个线程共享变抵的情况下, MESI 协议已经能够保障一个线程 对共享变量的更新对其他处理器上运行的线程来说是可见的;既然如此,可见性又何以存在呢?这就要从写缓冲器和无效化队列的角度来解释了。

    整理不易,喜欢请点个赞。

    展开全文
  • 事务解决的也是数据一致性的问题(业务层与数据库层面的一致性),看来这个也跟数据库的事务没有关系。 4、我们可以采用队列来实现,read的时候判断当前队列中是否存在删除操作,如果存在直接等待,如果没有直接...
  • MESI 协议解决了缓存一致性问题, 但是其自身也存在一个性能弱点——处理器执行写内存操作时,必须等待其他所有处理器将其高速缓存中的相应副本数据删除并接收到这些处理器所回复的 Invalidate Acknowledge/Read ...
  • Java并发——缓存一致性

    千次阅读 2018-11-24 10:57:17
    CPU多级缓存 CPU的时钟频率非常的快,跑起来的速度远远超过了内存、硬盘。《码农翻身》形象的比喻CPU为阿甘,跑的速度是内存的100倍,硬盘的1000多万倍。如果直接靠CPU直接和内存打交道,那么CPU要等待太久,浪费...
  •  在前面内存系统重排序提到,*“写缓存没有及时刷新到内存,导致不同处理器缓存的值不一样”*,出现这种情况是糟糕的,所幸处理器遵循**缓存一致性协议**能够保证足够的可见性又不过多的损失性能。  缓存一致性...
  • 多处理器环境下的存储模型与缓存一致性协议的分析。
  • CPU多级缓存与缓存一致性

    千次阅读 2018-06-20 16:20:23
    https://blog.csdn.net/muxiqingyang/article/details/6615199
  • 高速缓存是一种存取速率远比主内存大而容量远比主内存小的存储部件,每个处理器都有其高速缓存。引入高速缓存之后, 处理器在执行内存读、 写操作的时候并不直接与主内存打交道, 而是通过高速缓存进行的。变量名...
  • MESI 协议解决了缓存一致性问题, 但是其自身也存在一个性能弱点——处理器执行写内存操作时,必须等待其他所有处理器将其高速缓存中的相应副本数据删除并接收到这些处理器所回复的 Invalidate Acknowledge/Read ...
  • 数据库和缓存一致性的问题

    千次阅读 2020-04-01 16:58:36
    经常看到有人问怎么解决数据库和缓存一致性的问题,这个问题我觉得是不要去解决。 如果你不信你先看我列的几种情况 假设 数据库一开始和缓存都是1元。 用户更新数据库的同时双写缓存。 1.双写不删 写库充值...
  • 缓存一致性协议

    千次阅读 2018-03-28 22:55:13
    缓存一致性协议 简介 缓存一致性协议是为了解决多核以及多处理器的多个缓存之间的数据不一致提出来的,缓存一致性协议分为两种,第一种是基于窥探的协议(snoop-based),第二种是基于目录的协议(directory-based...
  • 笔者在学习过程中发现了一个不错的网站,模拟了MESI协议流程,现分享下: ... 运行效果图如下所示: 上图是CPU0、CPU1两个核心分别执行a0++后的效果图,执行顺序是CPU1执行a0++操作,然后CPU0执行a0++操作, ...
  • MESI缓存一致性

    2019-05-05 14:44:25
    CPU访问存储设备时,无论是存取数据抑或存取指令,都趋于聚集在一片连续的区域中,这就被称为局部原理。 时间局部(Temporal Locality):如果一个信息项正在被访问,那么在近期它很可能还会被再次访问。 比如...
  • SMP缓存一致性

    2019-06-23 19:06:48
    要想理解这些原语的作用,有必要理解SMP缓存一致性原理。 在SMP系统中,处理器的每个核都有独立的一级缓存,因此同一内存位置的数据,可能在多个核一级缓存中存在多个副本,所以存在数据一致性的问题。目前主流的...
  • Redis缓存一致性

    2019-04-11 17:49:08
    用过Redis的应该都清楚,redis作为内存缓存,只是他查询快的一大优势,关系型数据库只能用作存储重要数据,或者备份缓存的数据,这个时候,不可避免,我们会遇到缓存中的数据与关系型数据库中的数据不一致的情况。...
  • 缓存一致性问题

    2018-06-01 17:59:33
    缓存更新策略被动更新: 设置key过期的时间,让其自动失效。 主动更新: 更新DB的时候,同时更新缓存 一般业务都是主动更新和被动更新结合使用。 主动更新 问题存在一个问题:你是先更新缓存,后更新DB;还是反过来? ...

空空如也

1 2 3 4 5 ... 20
收藏数 7,191
精华内容 2,876
热门标签
关键字:

缓存一致性