缓存

从微观角度:寄存器、内存层面来看

关键词: 分级策略、指令预读、指令区、数据区、时钟周期、LRU、LFU

存储结构的分级策略,从快到慢的排序为: 寄存器, L1-cache, L2-cache, L3-cache, 内存。

制造出存储的物件,要考虑成本、散热、性能等等情况。CPU内的速度非常快,但是内存在离CPU在物理上看还是有一定的距离的,速度很明显得受到影响。

时钟周期的概念:
CPU 是用 石英晶体产生的脉冲 转化为 时钟信号 来驱动的,每次 高低电平 的转换的就是一个 时钟周期
CPU 的主频, 说的就是 时钟信号的频率。 一条指令,通常需要 2、4、6个时钟周期。

用数据来感受下:

1GHz的CPU,1G就是10个亿,所以一个时钟周期就是 1 / 10 亿秒;

而光速是 3*10的8次方米每秒,就是每秒可以走3亿米。

所以,在一个时钟周期内,连光速都只能走30厘米。而现实中还达不到这么快的速度,还有各种阻塞损耗。

所以,存储的分级策略就很有必要了。 如果把内存放到CPU里,这样散热性能就会收影响,而且我们不能个性化组装内存了,因为在CPU出厂时内存就定制好了。

都是些线性存储结构。

寄存器: 有几十个到几百个之间,速度非常快,一般要求在半个时钟周期内完成读写任务。

L1-cache: 在几十kb到几百kb不等,速写速度在2到4个CPU时钟周期。

L2-cache:大小具体看CPU的型号,读写速度在10到20个CPU时钟周期。

L3-cache:读写速度在20到60个CPU时钟周期。

内存:材料主要是半导体硅,用总线和CPU进行交流。读写速度大概在200到300个CPU时钟周期。

有了分级策略之后,再来看看,CPU执行一条指令的时候,需要2、4、6个CPU时钟周期,而读写内存需要200到300个CPU时钟周期。所以,我们不能每次从内存中只读取一条指令,这样等待的时间太久了!

所以,每次读的时候,都预读 几十条或者上百条的指令 到L1-cache中,这里是可以跟得上CPU的速度的。对于此,在L1-cache里,指令缓存和数据缓存是分开放的,如果数据覆盖了指令,是很糟糕的。

但是在L2-cache、L3-cache里是不需要区分缓存和指令的,因为根本就没有指令存在,不需要协助预读问题。

查询某个数据时,我们先去寄存器找,没有在去L1-cache找,再去L2-cache找,再去L3-cache找,再去内存中找。

怎么查找一个数据是否在缓存中?或者说缓存里的数据结构是怎样的?

可以就存储一个key-value结构的数据, key是内存地址,value是该地址上的值,也就是缓存的值;比较key的值看有没有在缓存中。这样需要遍历整个缓存空间进行查找,显然是不好的。

或者,我们可以通过类似 HashMap 的结构来存储,来查找,不用遍历整个数据。

缓存中满了,进来新的数据,怎么淘汰旧的数据呢?

一般有算法来进行解决: 先进先出FIFO、LRU、LFU

从宏观角度: 应用层面来看

可以缓存的地方

浏览器

当HTTP响应允许缓存的时候,会缓存一些静态资源,比如图片、css、html、js文件

网络服务提供商ISP : 访问网络的第一跳,加快访问速度。

反向代理:

在服务器之前,用户请求时,可以直接返回 反向代理 里的缓存。

本地缓存、分布式缓存

数据库的缓存:

MySQL 里可以查询缓存,但是之后好像取消这个设计了,因为每次增删改都会改变缓存,很频繁。

Java里的缓存

字符串常类池里的缓存、 Byte、Short、Character、Integer、Long、Boolean 包装类型的缓存

CPU的分级缓存

就是上面微观的层面。 通过 MESI 等缓存一致性协议 来解决 多核CPU缓存数据一致性的问题。

内容分发网络,CDN,content distribution network。

利用更靠近用户的服务器,将静态资源分发给用户。比如音乐、图片、视频、html、css、js等。

多台服务器可以看成是一种冗余机制,具备高可用性。

缓存带来的一些问题

  • 缓存穿透

    请求一定不存在的数据,会直接穿透缓存到达数据库。

    解决:

    对这类请求进行过滤; 对不存在的数据缓存一个空数据。

  • 缓存雪崩

    大量请求到达数据库,造成数据库崩溃。

    原因及解决方法:

    对数据来没来得及加载到缓存中情况: 进行缓存预热,提前加好缓存。

    对缓存数据大面积同一时间失效情况: 设置合理的缓存过期时间。

    对缓存服务器宕机情况: 用分布式缓存,保证其他节点的缓存可用,每个节点只缓存部分数据。

分布式缓存的 数据分布

顺序分布

哈希分布

根据哈希值,分配到对应的节点上。 但是当节点数增加,哈希的计算就有变化,会导致大量的数据迁移。

解决: 一致性哈希算法,DHT,distributed hash table

看 2 张图,

是一个环状结构,哈希计算之后,分布到顺时针看最近的哪个节点。

当增删节点时,也只会影响到前面的哪个节点。

但是对于节点少的时候,就会用数据分布不均匀的情况。解决方法是增加 虚拟节点,映射到真实的节点上,虚拟节点有很多。