在我们的日常工作中,无论是编程、数据库操作还是服务器运维,都离不开对数据的存取。那么,你有没有想过,为什么我们的电脑可以在瞬间完成大量数据的读取和写入呢?这就涉及到了我们今天要讲的主题——存储的局部性原理。
局部性原理的意义
首先,让我们来看看为什么需要局部性原理。在计算机的世界里,存储的性能和数量是成反比的,存取速度越快价格越高,存储数量越少。就好比我们去买水果,口感越好的价格往往越贵,但是无奈囊中羞涩,买不了几颗。我们希望能够既享受到存储的高速度体验,又能有大容量和低成本,这就好比我们希望一颗苹果既大又甜,又便宜。可是,现实是残酷的,我们不能同时得到这三者。那么,怎么办呢?这时候,就需要我们的局部性原理登场了。
局部性原理,简单来说,就是利用数据访问的特性,将频繁或尽快访问的数据加载到高性能的存储设备上,比如内存,而将不常用的数据放在低成本的存储设备上,比如硬盘。这就好比我们把经常需要用到的工具放在手边,而把不常用的工具放在远一点的地方。
局部性分类
那么,这个数据访问的特性是什么呢?通常,我们会发现,对于数据的访问总是存在一定的局部性,即时间局部性和空间局部性。
时间局部性,就是在短时间内,某些数据会被多次访问。比如,我们在编程的时候,可能会多次调用同一个函数,这个函数的代码就是被多次访问的数据。
空间局部性,是指相邻的数据会被接连访问。比如,我们在读取一个数组的时候,通常会按照数组的顺序进行读取,这时候就体现出了空间局部性。
用在哪里
那么,这个原理在哪些地方可以用到呢?
首先,我们可以用它来估算数据访问的需求和服务器的负载。比如,我们可以通过分析用户的访问模式,预测哪些数据会被频繁访问,然后设计将这些数据加载到高性能的存储设备上。
其次,我们可以通过这个原理,来判断缓存策略是否满足需求。比如,我们可以通过分析数据的访问模式,来确定使用哪种缓存策略,或者是否需要更换缓存策略。比如缓存过期是使用LRU算法还是固定时间淘汰。
最后,我们还可以通过这个原理,来规划硬件或资源的种类和容量。比如,我们可以根据数据的访问模式,来确定使用机械硬盘、固态硬盘、Redis还是内存,需要多少内存,或者需要多大的硬盘。
具体怎么做
举几个例子:
我们可以将热点数据从数据库、磁盘等加载到内存,并使用某种算法进行维护。此类代码我们大家可能都写过,比如我们将用户每次访问都需要验证的权限数据加载到Redis或者本地内存,加速此类数据的访问,提高用户的使用体验。
这个原理还用在了CPU中,CPU访问本地寄存器的速度比访问内存的速度快若干数量级,所以设计者们在CPU中规划了一块区域用于缓存计算所需的代码和数据,但是CPU寄存器的成本很高,所以这块区域相对内存要小很多,只在这个区域加载计算马上或者需要频繁用到的代码和数据。一般开发者不需要关心CPU缓存的管理,但是在高性能编程时可能也会涉及,比如log4j2这个日志库中使用的 Disruptor 组件就充分利用了CPU缓存的高速访问能力,让log4j2 的日志处理能力大大提升。
再来看一个写数据的问题。大家都知道机械硬盘的存取速度要远小于固态硬盘,这是因为随机读写时,机械硬盘内部的机械运动没有规律,有时候移动的比较远,就需要较长的时间,如果写数据的时候是在硬盘上顺序操作的,那么速度就会快很多。基于这个特性,我们需要提高写数据的效率时,就可以采用顺序写入的方式。比如kafka为了提升数据的处理效率,就利用了操作系统提供的硬盘连续物理数据块写入优化。
总的来说,存储的局部性原理是一种非常实用的原理,它可以帮助我们在享受高速度的同时,也能得到大容量和低成本。希望大家在日常的工作中,能够善用这个原理,提高我们的程序运行效率。
关注微/信/公/众/号:萤火架构,提升技术不迷路。