image.png多核CPU里的每一个CPU核、都有独立属于自己的L1 Cache 和 L2 Cache、多个CPU之间、只是共用L3 Cache 和 主内存、CPU的每个核之间都有各自的缓存、相互之间的操作又是独立的、就会带来
缓存一致性
问题
示例: 如上图有两个CPU核心、CPU1、CPU2
假设1号核心要将降价信息写入到内存、但使用的是写回策略、先写入到L2 Cache
但并未同步到L3 Cache或者主内存、只有在这个Cache Block被交换出去的时候、才会写到主内存
此时L2 Cache得到的依然是原始价格、CPU1 和 CPU2 Cache里的数据都是读的自身Cache、是不一致的
这就是缓存不一致性
思考:
缓存要保证一致性、需要满足什么条件呢 ?
1. 写传播(Write Propagation). 在一个CPU核心里、Cache数据更新、必须能传播到其它节点对应的Cache Line里
2. 事务的串行化(Transaction Serialization): 在一个CPU核心里的读取和写入、在其它的节点看起来、顺序是一样的
(eg. L1 核心先操作了降价为6000、L2核心又操作了降价为5000、若不能保证事务的串行化, 可能L3核心
得到的顺序是L1 -> L2 最终为5000, 而L4得到的顺序为 L2 -> L1 最终为6000、j出现不一致)
总线嗅探机制和MESI协议
要解决缓存一致性问题、首先要解决的是多个CPU核心之间的数据传播问题、最常见的解决方案叫 `总线嗅探`
其实是把所有的读写请求都通过总线Bus广播给所有的CPU核心、然后让各个核心去嗅探这些请求、再根据本地情况进行响应
由于总线本身就是一个特别适合广播进行数据传输的机制、所以、也是日常使用的Intel CPU采用的方案
基于总线嗅探机制、可以分成很多种不同的缓存一致性协议、最常用的就是`MESI`协议
MESI
协议(写失效协议)
`MESI`协议、是一种叫`写失效`(`Write Invalidate`)的协议、在写失效协议里、只有一个CPU核心负责写入数据、
其它的核心、只是同步读取到这个写入、在这个CPU核心写入Cache之后、它会广播一个`失效`请求告诉其它核心
其它核心只是判断自己是否也有一个`失效`版本的Cache Block、然后相应标记为`失效`
MESI 协议由来是对应于 Cache Line的四个不同的标记
M: 已修改 Modified
E: 代表独占 Exclusive
S: 代表共享 Shard
I: 代表已失效 Invalidated
独占和共享的差别在哪里呢 ?
独占状态下的数据、对应的CPULine只加载到了当前CPU所拥有的Cache里、其它的CPU核、
并没有加载对应的数据到自己的Cache里、此时若向独占的Cache Block写入数据、可自由操作、无需通知其它CPU
独占状态下的数据、若收到来自总线的读取缓存的请求、就变成共享状态、因为另一个CPU也把对应的Cache Block加载到了自己的Cache
共享状态下、同样的数据多个CPU核心的Cache里都有、更新Cache时不可直接修改、
而是要先向其它的CPU广播一个请求、要求先把其它CPU Cache变成无效状态、再更新当前Cache里的数据
这个广播操作叫`RFO`(Request For Ownership)获取当前对应Cache Block 数据的所有权
MESI状态流转.png
写广播协议
写广播协议会将一个写入请求广播到所有的CPU核心、同时更新各个核心里的Cache
在实现上比较简单、但要占用更多的总线带宽、写失效只是告诉其它CPU核心、哪个地址的缓存失效了、
但是写广播协议把对应的数据传播给其它的CPU核心
网友评论