缓存一致性解决方案:MESI
我们知道,缓存如果不保证一致性,可能会导致程序发生预期之外的结果,正确性得不到保障,那如何保证缓存的一致性呢?
MESI协议就是用来解决缓存一致性问题的,下面来一步一步聊聊什么的MESI。
总线窥探
了解MESI之前,先了解一下什么是总线窥探。

一般我们的电脑和服务器都是基于总线的架构(Bus-based)。例如上图有3个cpu核心和一个共享的主存,每一个cpu通过同一个总线向主存读写数据。
总线窥探从通俗的话来讲,就是每一个cpu都可以监测到某一个内存地址的更新操作,因为所有cpu都是共用同一个bus,所以cpu可以关注自己的cache里有那些地址,并且关注这些地址的数据是否有更新。
窥探协议
那么是怎么实现这个窥探的呢?
有两种协议,写失效(Write Invalidate) 和 写更新(Write Update)
无论是Write Invalidate 还是 Write Update 操作,都需要通过总线仲裁来完成,总线仲裁就是同一时刻,只有一个cpu能够使用总线,类似给总线加了一把锁。
到底使用哪种协议呢?
写更新协议看上去最简单,但是存在性能问题,例如多次更新同一条数据,需要占用多次总线进行同步更新,而占用总线的成本是非常高的。
写失效协议虽然使用起来相对复杂,但是是最节省总线资源的方案,因为写失效协议不需要每次更新其他cpu缓存,仅仅是发送缓存失效消息。
如果你再多思考一下, 你会发现写失效不一定总是性能上强于写更新的,例如当一个cpu核心更新了一条数据之后,其他的cpu核心马上需要读取数据, 那总线资源一样会占用的非常大,但是实际情况不会这么极端。从经验上来看,写失效在性能上是好于写更新,但是不是绝对的。
MESI
在了解什么是写失效(Write Invalidate)之后,来看看什么是MESI。
MESI相当于是Write Invalidate的一个拓展,MESI试图让使用Write Invalidate协议的过程中,尽可能的节省总线资源。
MESI协议定义了所有的缓存行都有一个状态,状态分为4种:
从上面的名字可以看出来,MESI其实就是这4种操作的首字母
MESI还对缓存行的操作,进行了抽象,所有的操作都可以抽象成4种:
用一张图来展示这4种操作对应的状态变化:
