上期说到,X姐虽然在努力之下晋升了P9,进入了高P序列,但由于和自己老板V姐都看上了白马女子私密会所的6666号技师,有时还会发生冲突,因此,X姐面临着绩效325甚至被从大厂毕业的危机。
在危机的压力下,X姐想到,能不能赋予6666号技师分身的能力,让白马会所有多个6666号技师,同时满足多个P9的需求呢?
在CPU设计中,这叫做缓存一致性。
所谓的缓存一致性包括内存和Cache的一致性,以及多处理器中各处理器Cache的一致性。
在处理器写入Cache的时候,有两种不同的方式,第一种称为写透(Write Through),也就是将数据同时写入内存和Cache中,其流程如下图所示:
显然,写透的方式实现简单,逻辑直观,但问题也很明显:
无论数据是否在cache里面,每次写操作都必须在DRAM完成写入后,CPU才能把流水线中的内存访问部件释放出来执行下一条指令的写操作。这会严重影响内存写入的性能。
另一种方式叫写回(Write Back)。写回的实现有点像操作系统的虚拟内存换页机制,先把数据写入Cache的Cache Line,在Cache Line需要被替换掉(也就是映射到其他内存地址)的时候,才把Cache Line内容写到其映射的内存里面。显然,这种方式大大减少了向DRAM写入的次数,也就是提升了系统的性能。
但是,对于写回方式,在多核系统中就会造成缓存一致性的问题。
比较早期的CPU,对于缓存一致性的问题,解决方案非常简单粗暴:如果核心A对内存地址(物理地址)0xHHHHHHHH写入了内容,那么,CPU的Cache控制器会把其他核心缓存中指向0xHHHHHHHH所在的Cache Line均标为Dirty。如果其他核心需要对内存地址0xHHHHHHHH所在的缓存行大小的任何地址(如0x800055AA这个地址,所在的64Byte对齐范围在0x80005580-0x800055BF)进行读写,需要重新将这块内存地址加载到缓存,或写入时直接写入内存,这就造成了严重的排队现象:
不仅是6666号技师需要顾客们排队使用,与6666号技师连号的小伙伴们,从6660-6669号技师,都需要绑定在一块,只有6666号技师结束接待以后,其他技师才可以开始接待。
因此,工程师们对CPU缓存控制器进行了改进,实现了两点:
- 写传播 (Write Propagation)。写传播指的是在一个CPU核心里,对Cache的更新可以传播到其他节点Cache里面,实现Cache内容的一致性;
- 事务串行化 (Transcation Serialization)。事务串行化指的是,对Cache读取和写入,在所有CPU核心看来,其次序是完全一样的。
第1点非常容易理解,重点是第2点,在这里有必要解释一下什么叫“事务”。
事务(Transcation),指的是具有确定性的,对数据进行的存取操作。
事务具备ACID四大特性。
A指的是原子性(Atomic),也就是不可分割性,如X姐点了一份6666号技师的8888元-188分钟巴厘岛武则天套餐,就必须一次性消费完毕,而不能拆分为2次消费;
C指的是一致性(Consistency),也就是X姐消费前钱在自己账户,消费后钱在白马会所账户,这件事情与巴厘岛武则天套餐服务应当同步发生,不会出现扣款而得不到服务的情况,也不会出现享受了服务而付款失败的情况;
I指的是隔离性(Isolation),也就是X姐如果和V姐同时光临白马会所,两个人的消费是独立的,彼此不应当知道对方的存在,即使两个人都想点6666号技师,也不会在同一个时刻接受6666号技师的服务,而需要进行串行化(Serialization);
D指的是持久性(Durability),也就是X姐对白马会所6666号技师的消费记录是持久性的,即使在系统故障下也不会丢失;
一些有数据库基础的同学可能会发现,ACID是数据库事务操作的基本原则。实际上,计算机对内存的存取,也符合事务的以上特征,即对内存的存取必须是原子性,确定性,一致性的。
那么,如果对内存的存取没有实现串行化,也就是隔离性实现有缺陷,会发生这样的情况:
有CPU A对内存地址0x800055A0写入了0x00000100,而CPU B对内存地址0x800055A0写入了0x00000200。如果系统中不同CPU看来,这两个内存事务次序不一致,那么,会导致不同CPU认为内存中这个地址的值是不一致的!
因此,必须实现事务串行化,才可以实现缓存的一致性。
想在CPU中实现事务串行化,就需要实现对Cache Line增加一把“锁”。如果两个或多个CPU中有指向同一个内存地址的Cache Line,无论哪个CPU在写入这个Cache Line的时候,都需要拿到这把锁,只有拿到对应Cache Line的锁以后,才可以更新Cache Line的内容。
在CPU中,实现写传播和事务串行化的机制,叫做MESI和写广播(Write Broadcast)。
请看下回分解。