缓存一致性问题

  1. iPhone降价了,要把iPhone最新的价格更新到主内存里,为了性能问题,采用写回策略
    • 先把数据写入到L2 Cache里,然后把Cache Block标记为
    • 此时数据其实没有被同步到L3 Cache主内存
      • 1号核心希望在这个Cache Block要被交换出去的时候,数据才写入到主内存里
  2. 此时2号核心尝试从内存里读取iPhone的价格,就会读取一个错误的价格
    • 缓存一致性问题:1号核心和2号核心的缓存,此时是不一致
  3. 同步机制能够达到的目标
    • 写传播(Write Propagation
      • 在一个CPU核心里面的Cache数据更新,必须能够传播到其他对应节点的Cache Line
    • 事务串行化(Transaction Serialization)
      • 在一个CPU核心里面的读取和写入,在其他节点看起来,顺序是一样

事务串行化

  1. 1号核心先把iPhone的价格改成5000,差不多时间,2号核心把iPhone的价格改成6000,这两个修改会传播到3号核心和4号核心
  2. 3号核心先收到2号核心的写传播,再收到1号核心的写传播;4号核心刚好相反
    • 虽然写传播做到了,但各个Cache里面的数据,是不一致
  3. 事务串行化:从1号到4号核心,都应该看到相同顺序的数据变化
    • 事务串行化的应用场景:缓存一致性数据库
  4. 要在CPU Cache里做到事务串行化,需要做到两点
    • 一个CPU核心对于数据的操作,需要同步通信给其他CPU核心
    • 如果两个核心里有同一个数据的Cache,那么对于这个Cache数据的更新,需要有一个『』的机制

总线嗅探

  1. 要解决缓存一致性问题,首先要解决的是多个CPU核心之间的数据传播问题
  2. 常见的解决方案:总线嗅探(Bus Snooping)
    • 本质:把所有读写请求都通过总线广播给所有的CPU核心,各个CPU核心去嗅探这些请求,再根据本地的情况进行响应
  3. 总线是一种特别适合通过广播来进行数据传输的机制
  4. 总线嗅探是Intel CPU进行缓存一致性处理的解决方案
  5. 基于总线嗅探机制,可以分成很多种不同的缓存一致性协议,最常用的就是MESI协议(在Pentium时代,被引入到Intel CPU)

MESI协议

写失效协议 – Write Invalidate

  1. 只有一个CPU核心负责写入数据,其他核心,只是同步读取到这个写入
  2. 在这个CPU核心写入Cache之后,会去广播一个失效请求告诉所有其他的CPU核心
  3. 其他的CPU核心,只是去判断自己是否也有一个失效版本的Cache Block,然后把这个也标记成失效即可

写广播协议 – Write Broadcast

  1. 把一个写入请求广播到所有的CPU核心,同时更新各个核心里的Cache
  2. 优点:实现简单
  3. 缺点:占用更多的总线带宽
    • 写失效只需要告诉其他的CPU核心,哪一个内存地址的缓存失效了
    • 写广播还需要把对应的数据传输给其他CPU核心

MESI协议

  1. MESI协议,是一种写失效(Write Invalidate)协议
  2. MESI协议,来自于对Cache Line的四个不同的标记
    • M:已修改(Modified) –
      • :Cache Block里面的内容已经更新过,但还没有写回到主内存里面
    • E:独占(Exclusive) – 干净
    • S:共享(Shared) – 干净
    • I:已失效(Invalidated) –
      • Cache Block里面的数据已经失效,不可以相信这个Cache Block里面的数据
  3. 无论是独占状态还是共享状态,缓存里面的数据都是干净
    • 干净:Cache Block里面的数据和主内存里的数据是一致
    • 独占:对应的Cache Line只加载到了当前CPU核所拥有的Cache里
      • 此时,如果要向独占的Cache Block写入数据,可以自由地写入数据,而不需要告知其他CPU核心
    • 共享:在独占状态下,如果收到一个来自于总线读取对应缓存的请求,就会变成共享状态
      • 另一个CPU核心,也把对应的Cache Block,从内存加载到自己的Cache里
      • 共享状态下,同样的数据多个CPU核心的Cache里都有
        • 如果想要更新Cache里面的数据,不能直接修改
        • 需要先向所有的其他CPU核心广播一个请求,要求先把其他CPU核心里面的Cache,都变成无效状态
        • 然后再更新当前Cache里面的数据
      • 这个广播操作,一般叫作RFO(Request For Ownership),即获取当前对应Cache Block数据的所有权
    • 机制有点类似于读写锁
  4. 整个MESI的状态,可以用一个有限状态机表示它的状态流转
    • 对于不同状态触发的事件操作,可能来自于当前CPU核心,也可能来自总线里其他CPU核心广播出来的信号

参考资料

深入浅出计算机组成原理