系列文章目录
这是本周期内系列打卡文章的所有文章的目录
- 《Go 并发数据结构和算法实践》学习笔记 Day 1
- 《Go 并发数据结构和算法实践》学习笔记 Day 2
- 《说透芯片》学习笔记 Day 3
文章目录
- 系列文章目录
- 前言
- 一、多核缓存一致性从何而来(What)
- 二、怎么解决(How、Why):总线嗅探机制 + MESI 协议
- 总结
前言
提示:这里可以添加本文要记录的大概内容:
学习内容:https://time.geekbang.org/column/article/109874
主客体之间的联系:
这次了解了工作中遇到的多核缓存一致性问题,在GEM5 RISC-V多核仿真环境中,多核共享内存的体系结构。在内存池分配算法时会遇到多核竞争和缓存一致性的问题。
提示:以下是本篇文章正文内容,下面案例可供参考
一、多核缓存一致性从何而来(What)
这点文章解释得很清楚,我用文中的图和自己的文字来简要串一下。
结构上,多核 CPU 里的每一个 CPU 核,都有独立的属于自己的 L1 Cache 和 L2 Cache。多个 CPU 之间,只是共用 L3 Cache 和主内存。
当多个核上,去更新各自的缓存时,其实跟缓存的策略有关:写更新、写穿透。写更新策略,就好遇到多核缓存一致性的问题。
顺便提一下基础问题,为啥CPU有几级缓存:CPU Cache 解决的是内存访问速度和 CPU 的速度差距太大的问题。
Step1:
Step2:
当一个核更新缓存时,另一个核的cacheline也更新了,如果这些更新在第三个核可见,那它的观测会以哪个为准?这其中有时序问题、有可见性。
二、怎么解决(How、Why):总线嗅探机制 + MESI 协议
- 引入机制:写传播与事务串行化
为了解决这个缓存不一致的问题,我们就需要有一种机制,来同步两个不同核心里面的缓存数据。那这样的机制需要满足什么条件呢?我觉得能够做到下面两点就是合理的。
第一点叫写传播(Write Propagation)。写传播是说,在一个 CPU 核心里,我们的 Cache 数据更新,必须能够传播到其他的对应节点的 Cache Line 里。
第二点叫事务的串行化(Transaction Serialization),事务串行化是说,我们在一个 CPU 核心里面的读取和写入,在其他的节点看起来,顺序是一样的。
如果有数据库了解的,是不是“事务化”那个味道了,其实ACID是比较强的事务化约束。当然也是一个解决方案标杆了。
来了,这个机制的重点:解决多个 CPU 核心之间的数据传播问题、保证时序性(锁)。
在 CPU Cache 里做到事务串行化,需要做到两点,第一点是一个 CPU 核心对于数据的操作,需要同步通信给到其他 CPU 核心。第二点是,如果两个 CPU 核心里有同一个数据的 Cache,那么对于这个 Cache 数据的更新,需要有一个“锁”的概念。
- 第一个问题:总线嗅探机制
由谁来传播多个 CPU 核心之间的数据:总线。如果是软件设计,可能就来个观察者模式了,总线这是实体。
最常见的一种解决方案呢,叫作总线嗅探(Bus Snooping)。本质上就是把所有的读写请求都通过总线(Bus)广播给所有的 CPU 核心,然后让各个核心去“嗅探”这些请求,再根据本地的情况进行响应。
- 第二个问题:MESI 协议
基于总线嗅探机制,其实还可以分成很多种不同的缓存一致性协议。不过其中最常用的,就是今天我们要讲的 MESI 协议。和很多现代的 CPU 技术一样,MESI 协议也是在 Pentium 时代,被引入到 Intel CPU 中的。
Cacheline的操作方式是:标记。
MESI 协议的由来呢,来自于我们对 Cache Line 的四个不同的标记,分别是:
- M:代表已修改(Modified)
- E:代表独占(Exclusive)
- S:代表共享(Shared)
- I:代表已失效(Invalidated)
MESI 协议,是一种叫作写失效(Write Invalidate)的协议。在写失效协议里,只有一个 CPU 核心负责写入数据,其他的核心,只是同步读取到这个写入。在这个 CPU 核心写入 Cache 之后,它会去广播一个“失效”请求告诉所有其他的 CPU 核心。其他的 CPU 核心,只是去判断自己是否也有一个“失效”版本的 Cache Block,然后把这个也标记成失效的就好了。
相对于写失效协议,还有一种叫作写广播(Write Broadcast)的协议。在那个协议里,一个写入请求广播到所有的 CPU 核心,同时更新各个核心里的 Cache。
4. 进一步:状态图
整个 MESI 的状态,可以用一个有限状态机来表示它的状态流转。需要注意的是,对于不同状态触发的事件操作,可能来自于当前 CPU 核心,也可能来自总线里其他 CPU 核心广播出来的信号。状态机流转图如下:
总结
提示:这里对文章进行总结:
想要实现缓存一致性,关键是要满足两点。第一个是写传播,也就是在一个 CPU 核心写入的内容,需要传播到其他 CPU 核心里。更重要的是第二点,保障事务的串行化,才能保障我们的数据是真正一致的,我们的程序在各个不同的核心上运行的结果也是一致的。这个特性不仅在 CPU 的缓存层面很重要,在数据库层面更加重要。
内容来源:
极客时间:39 | MESI协议:如何让多核CPU的高速缓存保持一致?