存储器结构

存储器的层次结构
1,CPU中的寄存器与其说是存储器,其实更像CPU本身的一部分,只能存放极其有限的信息,但是速度非常快,和CPU同步。
2,CPU Cache(CPU高速缓存)用的是SRAM(Static Random- Access Memory,静态随机存取存储器)的芯片。
1)只要处在通电状态,里面的数据就可以保持存在,一旦断电,数据就会丢失。
2)在SRAM里,一个bit数据需要6~8个晶体管,所以存储密度不高,同样的物理空间下,能够存储的数据有限,不过因为电路简单,所以访问速度快。
3,在CPU中通常会有L1,L2,L3这样三层高速缓存。
1)每个CPU核心都有一块属于自己的L1高速缓存,通常分为指令缓存和数据缓存,分别存放CPU使用的指令和数据。
2)每个CPU核心也都有L2的Cache,但不在CPU核心内部,L2的访问速度会比L1稍慢。
3)L3的Cache则通常是多个CPU核心共用,尺寸更大,访问速度也更慢一些。
4,CPU的L1 Cache可理解为短期记忆,L2/L3 Cache理解成长期记忆,数据从内存中加载到CPU的寄存器和Cache中,然后通过CPU进行处理和运算。
5,内存使用DRAM(Dynamic Random Access Memory,动态随机存取存储器)的芯片,比起SRAM密度更高,容量更大,也便宜。需要不断刷新,才能保持数据被存储。
1)DRAM称为动态存储器,一个bit只需要一个晶体管和一个电容就能存储,所以在同样的物理空间下能够存储的数据更多,存储密度更大。
2)数据存储在电容里,电容会不断漏电,所以需要定时刷新充电,才能保持数据不丢失。
3)DRAM的数据访问电路和刷新电路都比SRAM更复杂,访问延时也更长。
6,CPU中的L1 Cache不仅受成本限制,更受物理层面限制,访问速度和它到CPU的距离有关。
7,SSD(Solid-state drive或Solid-state disk固态硬盘)、HHD(Hard Disk Drive,硬盘)外部存储设备有更多的空间。
8,从Cache、内存到SSD和HDD硬盘,一台现代计算机用上了所有存储器设备,容量越小的设备速度越快,CPU不直接与每一种存储设备打交道,每一种存储设备只和它相邻的存储设备打交道,数据先从硬盘加载到内存,CPU Cache从内存中加载数据,写回到内存,再写回到硬盘。
9,各个存储器只与相邻一层存储器打交道,且随着一层层向下,存储器的容量逐层增大,访问速度变慢,单位存储成本也逐层下降,这些构成了存储器的层次结构。

局部性原理
1,服务端软件开发时,通常把数据存储在数据库里,而在数据库前提供一层缓存的数据,可缓解数据库面临的压力,提升服务端的性能。通过使用Redis/Memcache的开源缓存,在数据库前提供一层缓存的数据,缓解数据库压力,提升服务端的性能。
2,利用存储器中数据的局部性原理,制定管理和访问数据的策略。
1)时间局部性,如果一个数据被访问了,短时间内还会再次访问,将存储在硬盘的数据库读取到内存的缓存中。
2)空间局部性,如果一个数据被访问了,和它相邻的数据也很快会被访问,将相邻的数据一并加载到缓存中。
3,在实际应用程序中,查看一个数据可能不止一次随机内存或随机磁盘的访问,数据存储需要考虑数据结构、维护数据结构的空间、缓存的命中率,访问请求则需要考虑均值和峰值的问题。
1)考虑硬件的成本、访问的数据量以及访问的数据分布,根据这些数据的估算,组合不同的存储器,以较低的成本支撑服务器压力。
2)根据数据访问的局部性原理,基于存储器的层次结构,进行硬件规划。

高速缓存
1,内存与硬盘之间存在巨大的性能差异,但在CPU眼里,内存也很慢,所以CPU中嵌入了CPU Cache。
1)CPU读取数据时,先访问Cache,当CPU在Cache中找不到数据时,才会访问内存,将内存中的指令、数据加载到L1-L3 Cache中,L1/L3 Cache是由SARM组成的物理芯片。
2)时间局部性原理,刚刚访问的数据很快会再次访问,Cache的访问速度远快于内存,CPU等待内存访问时间大大缩短。
2,CPU从内存读取数据到CPU Cache中,是一小块一小块的读取,将Block(内存块)的数据读取到Cache Line(缓存块)。
3,内存块地址对缓存块进行映射,多个内存块映射到同一个缓存块时,在缓存块存储一个组标记(Tag),记录当前缓存块内数据对应的内存块。
1)将缓存块数量设置成2的N次方,内存块的低N位代表映射的缓存块,缓存块中Tag记录内存块的其他位的信息。
2)缓存还存储有效位,标记缓存块中的数据是否有效,有效位为0时,CPU需要访问内存重新加载数据,确保不是启动时的空数据。
3)CPU读取数据时,并不读取一整个Block,而是读取一个Word(字)的整数,即Block的偏移量。
4)总结就是,内存地址,高位代表组标记、低位代表缓存索引,加上一个字的偏移量。而缓存块的数据结构,则多了有效位和对应的数据,由索引+有效位+组标记+数据组成。
4,如果内存中的数据已经在CPU Cache中,内存地址的访问,要经历以下步骤:
1)根据内存地址的低位,计算在Cache中的索引;
2)判断有效位,确认Cache中的数据是有效的;
3)对比内存地址的高位,和Cache中的组标记,确认Cache中的数据即为访问的内存数据,从Cache Line读取到对应的Data Block(数据块);
4)根据内存地址的Offset,从Data Block读取需要读取的字。
5)如果2,3步骤中,Cache中数据不是要访问的内存地址数据,CPU访问内存将对应Block Data加载到Cache Line中,并更新有效位和组标记。

CPU高速缓存的写入
1,CPU通常是多核的,每个CPU核里都有独立的L1、L2 的Cache,多核共用L3的Cache和主内存,L1、L2的Cache速度快于L3的Cache,CPU通常是从CPU Cache中读取数据。
2,写入数据是写入到内存还是Cache呢,写入L1、L2 Cache不同CPU核内数据是否同步,写入内存Cache数据是否会失效。
3,一种策略是写直达(Write-Through),每一次数据都写入到主内存中,写入前判断数据是否在Cache里,数据在先写入到Cache再写入到内存,数据不在直接写入到内存。但这个策略速度较慢。
4,一种策略是写回(Write-Back),不是每次都将数据写回主内存,只写入CPU Cache,当CPU Cache里的数据要被替换时,才将数据写回主内存。
1)如果要写入的数据就在Cache里,更新Cache里的数据,并标记Cache里的Block是脏(Dirty)的,代表CPU Cache里这个Block的数据和主内存不一致。
2)如果写入数据所对应的Block里是其他内存的数据,查看数据是否标记为脏,是脏的话需要将这个数据写回到主内存,再将当前数据写入Cache,同时标记Block为脏,如果Block数据不是脏,当前数据直接写入到Cache,再将Block标记为脏。
3)写回策略在加载内存数据到Cache时也多了一步同步脏Cache动作,加载内存数据到Cache时,如果Cache Block里有脏标记,需要先将Cache Block的数据写回到主内存,才能加载覆盖掉Cache。
4)写回策略里如果大量操作能够命中缓存,就不需要读写内存,性能会比写直达效果好一些。

缓存一致性问题
1,为了性能采取写回策略,但没有解决CPU多核缓存一致的问题,写回策略更新数据到L2 Cache,数据没有同步到L3 Cache内存中,其他CPU获取不到更新后的数据,此时需要引入MESI协议,一个维护缓存一致的协议,需要做到:
1)写传播,当前CPU里Cache数据更新必须传播到其他对应节点的Cache Line中。
2)事务串行化,不同的CPU读写Cache数据在所有CPU看来顺序是一致的。
2,CPU Cache事务串行化需要做到:
1)其中一个CPU核心对数据的操作需要同步给其他CPU;
2)如果两个CPU核心有同一个数据的Cache,对该数据的更新需要有一个锁,拿到Cache Block的锁后才能更新数据。
3,事务的串行化,不仅对缓存一致性是必须的,平时所用到的系统中,数据库也需要保障事务串行化,多个不同的连接访问数据库,必须保障事务的串行化。
4,解决缓存一致问题即多个CPU核心之间数据传播的问题,最常见解决方案为总线嗅探(Bus Snooping),把所有读写请求通过总线广播给所有CPU核心,CPU核心嗅探请求根据本地情况响应。
5,总线广播进行数据传输,嗅探机制可以分成多种不同的缓存一致性协议:
1)常见有MESI协议,是一种写失效(Write Invalidate)协议,一个CPU核心负责写入数据,CPU核心写入Cache后,广播一个失效请求告知其他CPU核心,其他CPU核心判断自己是否有失效版本的Cache Block,然后标记为失效。
2)还有一种写广播(Write Broadcast)协议,一个写入请求广播所有的CPU核心,同时更新各个核心中的Cache,写广播实现上简单,但占用总线带宽更多。
3)写失效只需要告诉其他CPU核心哪一个内存地址的缓存失效,写广播需要将对应数据传输给其他CPU核心,写失效只需要在总线上传输操作信号和地址信号,写广播还需要传输数据内容。
6,MESI协议对Cache Line四种不同标记:
1)M(Modified,已修改),已修改就是Cache Block的脏标记,表示Cache Block里内容已更新但还没写回到主内存中
2)E(Exclusive,独占)
3)S(Shared,共享)
4)I(Invalidated,已失效),已失效就是Cache Block里数据已失效
7,独占和共享状态表示Cache Block与主内存的数据是一致的,非脏的。
1)独占状态下,对应Cache Line只加载到了当前CPU的Cache里,其他CPU Cache未加载相应数据,此时可自由写入数据,不需要告知其他CPU核。
2)独占状态下的数据,如果收到总线读取对应缓存的请求,就会变成共享状态,另外一个CPU核心会将数据从内存加载到缓存中。
3)共享状态下,同样的数据在多个CPU核心的Cache中都有,如果需要更新数据时,不能直接修改,需要向其他CPU广播请求将其他CPU Cache里对应数据标记为失效,再在当前CPU Cache里更新数据。这个广播操作一般称为RFO(Request For Ownership),即获取当前对应Cache Block数据的所有权。
4)共享状态下,CPU都可以并行读取对应数据,写时需要通过锁获取当前写入位置的所有权,类似多线程是的读写锁。

猜你喜欢

转载自blog.csdn.net/mei_true/article/details/127453563