计算机操作系统学习笔记(3)——CPU缓存一致性

简介: 计算机操作系统学习笔记(3)——CPU缓存一致性

一、CPU Cache写回内存

之前说的CPU Cache缓存块实际分为:头标志Tag和数据块Data Block

前面说的直接映射,取模运算有可能发生冲突,发生了冲突就用Tag去标记。组标记(Tag)。这个组标记会记录当前 CPU Line 中存储的数据对应的内存块,我们可以⽤这个组标记来区分不同的内存块。

Cache里的数据总要写回内存的,那在什么时机才把 Cache 中的数据写回到内存呢?

这里有2种方案:写直达和写回
写直达:写直达法很直观,也很简单,把数据同时写⼊内存和 Cache 中,⽆论数据在不在 Cache ⾥⾯,每次写操作都会写回到内存,这样写操作将会花费⼤量的时间,⽆疑性能会受到很⼤的影响。
写回:在写回机制中,如果当发⽣写操作时,数据所对应的 Cache Block ⾥存放的是「别的内存地址的数据」的话,就要检查这个 Cache Block ⾥的数据有没有被标记为脏的,如果是脏的话,我们就要把这个 
Cache Block ⾥的数据写回到内存,然后再把当前要写⼊的数据,写⼊到这个 Cache Block ⾥,同时也把它标记为脏的;。这样的好处是,如果我们⼤量的操作都能够命中缓存,那么⼤部分时间⾥ CPU 都不需要读写
内存,⾃然性能相⽐写直达会⾼很多。
脏说明这个数据被更新了,说白了写回策略其实就是操作一个变量,直到换成了操作其他变量才更新

二、何为CPU缓存一致性问题?

举个例子:如果一个CPU有2个核心A和B,他们都操作共同的变量 i(初始值为 0 )。

这时如果 A 号核⼼执⾏了 i++ 语句的时候,为了考虑性能,使⽤了我们前⾯所说的写回策略,先把值为 1 的执⾏结果写⼊到 L1/L2 Cache 中,然后把 L1/L2 Cache 中对应的 Block标记为脏的,这个时候数据其实没有被同步到内存中的,因为写回策略,只有在 A 号核⼼中的这个 Cache Block 要被替换的时候,数据才会写⼊到内存⾥。


如果这时 B 号核⼼尝试从内存读取 i 变量的值,则读到的将会是错误的值,因为刚才A 号核⼼更新 i 值还没写⼊到内存中,内存中的值还依然是 0。这个就是所谓的缓存⼀致性问

题,A 号核⼼和 B 号核⼼的缓存,在这个时候是不⼀致,从⽽会导致执⾏结果的错误。

三、怎么解决缓存一致性问题?

要保证缓存一致性问题,要保证2点: 写传播(Wreite Propagation)和 事务的串形化(Transaction Serialization)

事务串形化

解释一下,事务串行化:

假设我们有⼀个含有 4 个核⼼的 CPU,这 4 个核⼼都操作共同的变量 i(初始值为 0 )。A号核⼼先把 i 值变为 100,⽽此时同⼀时间,B 号核⼼先把 i 值变为 200,这⾥两个修改,都
会「传播」到 C 和 D 号核⼼。那么问题就来了,C 号核⼼先收到了 A 号核⼼更新数据的事件,再收到 B 号核⼼更新数据的事件,因此 C 号核⼼看到的变量 i 是先变成 100,后变成 200。
⽽如果 D 号核⼼收到的事件是反过来的,则 D 号核⼼看到的是变量 i 先变成 200,再变成100,虽然是做到了写传播,但是各个 Cache ⾥⾯的数据还是不⼀致的。所以,我们要保证 C 号核⼼和 D 号核⼼都能看到相同顺序的数据变化,⽐如变量 i 都是先变
成 100,再变成 200,这样的过程就是事务的串形化。

写传播

写传播很容易就理解,当某个核⼼在 Cache 更新了数据,就需要同步到其他核⼼的Cache ⾥。


写传播就是写传播最常⻅实现的⽅式是总线嗅探(Bus Snooping)。说白了就类似一个消息队列,其他缓存去监听,数据被修改了,操作那个数据都缓存发条消息,其他缓存就都知道了。


可以发现,总线嗅探⽅法很简单, CPU 需要每时每刻监听总线上的⼀切活动,但是不管别的核⼼的 Cache 是否缓存相同的数据,都需要发出⼀个⼴播事件,这⽆疑会加重总线的负载。


总线嗅探并不能保证事务串形化。


于是,有⼀个协议基于总线嗅探机制实现了事务串形化,也⽤状态机机制降低了总线带宽压⼒,这个协议就是 MESI 协议,这个协议就做到了 CPU 缓存⼀致性。

四、MESI 协议

MESI 协议其实是 4 个状态单词的开头字⺟缩写,这四个状态来标记 Cache Line 四个不同的状态,而这些状态是通过总线广播出去的,所以说是基于总线嗅探的,分别是:

Modified,已修改
Exclusive,独占
Shared,共享
Invalidated,已失效

「已修改」状态就是我们前⾯提到的脏标记,代表该 Cache Block 上的数据已经被更新过,但是还没有写到内存⾥。⽽「已失效」状态,表示的是这个 Cache Block ⾥的数据已经失效
了,不可以读取该状态的数据。
「独占」和「共享」状态都代表 Cache Block ⾥的数据是⼲净的,也就是说,这个时候
Cache Block ⾥的数据和内存⾥⾯的数据是⼀致性的。「独占」和「共享」的差别在于,独占状态的时候,数据只存储在⼀个 CPU 核⼼的 Cache
⾥,⽽其他 CPU 核⼼的 Cache 没有该数据。这个时候,如果要向独占的 Cache 写数据,就可以直接⾃由地写⼊,⽽不需要通知其他 CPU 核⼼,因为只有你这有这个数据,就不存在缓
存⼀致性的问题了,于是就可以随便操作该数据。另外,在「独占」状态下的数据,如果有其他核⼼从内存读取了相同的数据到各⾃的 Cache
,那么这个时候,独占状态下的数据就会变成共享状态。那么,「共享」状态代表着相同的数据在多个 CPU 核⼼的 Cache ⾥都有,所以当我们要更新 Cache ⾥⾯的数据的时候,不能直接修改,⽽是要先向所有的其他 CPU 核⼼⼴播⼀个请
求,要求先把其他核⼼的 Cache 中对应的 Cache Line 标记为「⽆效」状态,然后再更新当前 Cache ⾥⾯的数据。
我们举个具体的例⼦来看看这四个状态的转换:
1. 当 A 号 CPU 核⼼从内存读取变量 i 的值,数据被缓存在 A 号 CPU 核⼼⾃⼰的 Cache ⾥⾯,此时其他 CPU 核⼼的 Cache 没有缓存该数据,于是标记 Cache Line 状态为「独占」,
此时其 Cache 中的数据与内存是⼀致的;
2. 然后 B 号 CPU 核⼼也从内存读取了变量 i 的值,此时会发送消息给其他 CPU 核⼼,由
于 A 号 CPU 核⼼已经缓存了该数据,所以会把数据返回给 B 号 CPU 核⼼。在这个时候, A 和 B 核⼼缓存了相同的数据,Cache Line 的状态就会变成「共享」,并且其Cache 中的数据与内存也是⼀致的;
3. 当 A 号 CPU 核⼼要修改 Cache 中 i 变量的值,发现数据对应的 Cache Line 的状态是共享状态,则要向所有的其他 CPU 核⼼⼴播⼀个请求,要求先把其他核⼼的 Cache 中对应的 Cache Line 标记为「⽆效」状态,然后 A 号 CPU 核⼼才更新 Cache ⾥⾯的数据,
同时标记 Cache Line 为「已修改」状态,此时 Cache 中的数据就与内存不⼀致了。
4. 如果 A 号 CPU 核⼼「继续」修改 Cache 中 i 变量的值,由于此时的 Cache Line 是「已
修改」状态,因此不需要给其他 CPU 核⼼发送消息,直接更新数据即可。
5. 如果 A 号 CPU 核⼼的 Cache ⾥的 i 变量对应的 Cache Line 要被「替换」,发现Cache Line 状态是「已修改」状态,就会在替换前先把数据同步到内存。所以,可以发现当 Cache Line 状态是「已修改」或者「独占」状态时,修改更新其数据不需
要发送⼴播给其他 CPU 核⼼,这在⼀定程度上减少了总线带宽压⼒。

对于在「已修改」或者「独占」状态的 Cache Line,修改更新其数据不需要发送⼴播给其他 CPU 核⼼。

这个MESI,我这里只是简诉,Java中的volatile保证的可见性,底层的原理就是依靠于MESI,建议这个协议还是有必要了解下。

相关实践学习
CentOS 7迁移Anolis OS 7
龙蜥操作系统Anolis OS的体验。Anolis OS 7生态上和依赖管理上保持跟CentOS 7.x兼容,一键式迁移脚本centos2anolis.py。本文为您介绍如何通过AOMS迁移工具实现CentOS 7.x到Anolis OS 7的迁移。
目录
相关文章
|
3月前
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
4月前
|
消息中间件 缓存 监控
如何保证缓存和数据库的一致性?
保证缓存和数据库的一致性的做法
|
1月前
|
缓存 NoSQL 关系型数据库
mysql和缓存一致性问题
本文介绍了五种常见的MySQL与Redis数据同步方法:1. 双写一致性,2. 延迟双删策略,3. 订阅发布模式(使用消息队列),4. 基于事件的缓存更新,5. 缓存预热。每种方法的实现步骤、优缺点均有详细说明。
|
2月前
|
缓存 监控 算法
小米面试题:多级缓存一致性问题怎么解决
【10月更文挑战第23天】在现代分布式系统中,多级缓存架构因其能够显著提高系统性能和响应速度而被广泛应用。
56 3
|
2月前
|
消息中间件 缓存 中间件
缓存一致性问题,这么回答肯定没毛病!
缓存一致性问题,这么回答肯定没毛病!
|
3月前
|
消息中间件 缓存 NoSQL
奇怪的缓存一致性问题
本文记录了缓存一致性问题的排查过程和解决方案,同时带读者朋友们一起回顾下相关的八股文。
|
3月前
|
缓存 NoSQL 关系型数据库
MySQL与Redis缓存一致性的实现与挑战
在现代软件开发中,MySQL作为关系型数据库管理系统,广泛应用于数据存储;而Redis则以其高性能的内存数据结构存储特性,常被用作缓存层来提升数据访问速度。然而,当MySQL与Redis结合使用时,确保两者之间的数据一致性成为了一个重要且复杂的挑战。本文将从技术角度分享MySQL与Redis缓存一致性的实现方法及其面临的挑战。
156 2
|
4月前
|
存储 算法 网络协议
了解操作系统的基本原理和常见操作,提高计算机使用效率
了解操作系统的基本原理和常见操作,提高计算机使用效率
52 4
|
4月前
|
存储 缓存 数据处理
计算机硬件存储器中的缓冲与缓存
【8月更文挑战第2天】
290 5
|
4月前
|
消息中间件 缓存 监控
go-zero微服务实战系列(六、缓存一致性保证)
go-zero微服务实战系列(六、缓存一致性保证)

热门文章

最新文章