文章目录

  • 简介
  • 常规缓存
  • 缓存操作
  • 读缓存
  • 写缓存
  • 缓存回收策略
  • LRU实现
  • 在哪里放置缓存?
  • 何时实现缓存?
  • Python中的缓存
  • 参考文献


简介

缓存,是软件从硬件中获取灵感的概念。

缓存是一个临时存储区域,用于存储使用过的东西以便于访问。


常规缓存

在计算机科学中,缓存是存储计算结果以快速访问的硬件组件。影响速度的主要因素是它的内存大小和位置。缓存的内存大小比RAM小得多。减少了检索数据的扫描次数。缓存位于更靠近CPU的位置,因此延迟更少。


缓存操作

缓存,如浏览器缓存,服务器缓存,代理缓存,硬件缓存。无论哪种缓存,操作有两种主要类型:readwrite

当处理缓存时,会使用一个巨大内存块,取代从数据库,硬盘等耗时的读写,使工作更快。

读缓存

读缓存是存储被访问项的存储器。每次客户端从存储器请求数据时,请求都会命中与存储器相关联的缓存。

  1. 如果请求的数据在缓存上可用,那么缓存命中 Cache Hit
  2. 如果没有,则是缓存丢失 Cache Miss
  3. 当从缓存访问数据时,其他一些进程在此时更改数据,需要用新更改的数据替换缓存,这是缓存失效 Cache Invalidation

写缓存

写缓存指快速写入。写数据库代价很高,想象一个写量很大的系统,使用缓存可以处理数据库写负载,然后批量更新到数据库。需要注意的是,DB和缓存之间的数据应该始终是同步的。有三种方法可以实现写缓存:

  1. 直写 Write Through
    对数据库的写入是通过缓存进行的。每次在缓存中写入新数据时,都会在数据库中进行更新。
    优点:缓存和存储之间不会有数据不匹配
    缺点:缓存和存储都需要更新,会增加开销,而不是提高性能
  2. 回写 Write Back
    回写是指缓存以设定的时间间隔将值异步更新到数据库,这种方法与 Write Through 的优缺点正好相反。
    优点:缓存和存储不需要都更新
    缺点:缓存和存储之间会有数据不匹配
  3. 绕写 Write Around
    将数据直接写入存储,并仅在读取数据时加载缓存。
    优点:①缓存不会因写入后没有立即读取而超负荷。 ②减少 Write Through 的延迟
    缺点:读取最近写入的数据会导致缓存丢失

python 缓存环 python 缓存模块_python 缓存环


缓存回收策略

缓存使读写速度更快,只有从缓存中读取和写入数据而不是从数据库中才有意义。但是,请记住,速度的提高只是因为缓存很小。缓存越大,搜索所需的时间就越长。

所以空间优化是很重要的。一旦缓存满了,我们只能通过删除缓存中已经存在的数据来为新数据腾出空间。

缓存回收策略用于决定哪些数据需要从缓存中丢弃:

  1. LRU - 最久未使用
    当缓存耗尽空间时,删除最久未使用的元素。简单,易于实现,相对公平的缓存频率。
  2. LFU - 最近最少使用
    同时考虑了数据的年龄和频率。但问题是,经常使用的数据会在缓存中停留很长时间。
  3. MRU - 最频繁使用
    什么情况用到?例如,看图片时往回看的概率比较小。
  4. FIFO - 先进先出
    缓存像队列一样工作,先进先出。非常适合按顺序读取和处理数据管道的情况。


LRU实现

缓存基本上是一个哈希表。每个进入它的数据都被散列和存储,使它可以以O(1)访问。

可以使用双重链接的链表实现。每次访问时向链表中添加一个项目,并维护它是哈希表中的一个引用,使能够O(1)访问。当元素已经存在时,将其从当前位置删除,并将其添加到链表的末尾。

python 缓存环 python 缓存模块_python 缓存环_02


在哪里放置缓存?

缓存离消费者越近,速度就越快。这意味着在Web应用程序的情况下将缓存与Web服务器放在一起。但有几个问题:

  1. 当服务器宕机时,会丢失与服务器缓存相关的所有数据。
  2. 当需要增加缓存的大小时,会入侵分配给服务器的内存。
  3. python 缓存环 python 缓存模块_缓存_03


最可行的解决方案是在服务器外部维护缓存。尽管它包含了额外的延迟,但对于缓存的可靠性来说还是值得的。

分布式缓存的概念是在服务器外部托管缓存并独立地扩展它。


何时实现缓存?

寻找技术实现缓存是所有步骤中最简单的。缓存保证了高速API,不使用缓存可能很笨,但如果出于错误的原因这样做,只会给系统增加额外的开销。所以实现前确保:

  1. 数据存储的点击率很高
  2. 已经尽了一切可能来提高DB级别的速度
  3. 已经学习和研究了各种缓存方法和系统,并找到了项目适合的方法和系统











推荐阅读:

  1. 缓存使用过程中的五种策略总结及优缺点组合分析


Python中的缓存

使用 functools 模块中的 lru_cache()

from functools import lru_cache


@lru_cache(maxsize=None)
def fib(n):
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)


def fib1(n):
    if n < 2:
        return n
    return fib1(n - 1) + fib1(n - 2)


result = [fib(i) for i in range(16)]
print(result)
print(fib.cache_info())  # 查看命中和未命中次数
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]
# CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)


参考文献
  1. Caching in Python
  2. 缓存使用过程中的五种策略总结及优缺点组合分析
  3. Caching Strategies and How to Choose the Right One