一级二级缓存设计

为什么需要多级缓存

在互联网系统中,随着业务规模不断增长,数据库往往会成为系统的性能瓶颈。大量请求如果直接访问数据库,不仅会带来高延迟,还会导致数据库压力过大,甚至出现连接耗尽、查询变慢等问题。因此,几乎所有高并发系统都会引入 缓存(Cache) 来提升系统性能。

最常见的缓存方式是使用 Redis 作为统一缓存层。客户端请求首先访问 Redis,如果缓存命中,就直接返回数据;如果缓存未命中,再访问数据库并将结果写入缓存。这种方式已经能够显著降低数据库压力。

但随着系统规模继续扩大,仅仅依赖 Redis 仍然可能出现新的问题。例如在高 QPS 场景下,大量请求同时访问 Redis,会产生网络开销和 Redis CPU 压力。同时,某些热点数据可能会被频繁读取,每次都经过网络访问 Redis,也会带来额外延迟。

为了解决这些问题,很多大型系统会引入 多级缓存架构(Multi-Level Cache),其中最常见的一种模式就是 一级缓存 + 二级缓存设计

一级二级缓存的基本架构

一级二级缓存本质上是一种 缓存分层架构

通常系统会设计两层缓存:

一级缓存(L1 Cache)

一级缓存通常位于 应用进程内部,也称为 本地缓存(Local Cache)。例如使用:

  • Go:bigcache / ristretto
  • Java:Caffeine / Guava Cache
  • Node:LRU Cache

一级缓存的特点是:

  • 访问速度极快(内存访问)
  • 不需要网络通信
  • 每个服务实例都有自己的缓存

二级缓存(L2 Cache)

二级缓存通常是 分布式缓存系统,最常见的是 Redis 或 Memcached。所有服务实例共享同一个缓存系统。

二级缓存的特点是:

  • 多节点共享
  • 数据一致性更好
  • 容量更大
  • 支持分布式部署

整个系统的访问流程通常是:

客户端请求
→ 服务进程
→ 查询一级缓存
→ 未命中则查询二级缓存
→ 再未命中则查询数据库

一级二级缓存访问流程

在实际系统中,一次请求的典型访问流程如下:

首先,请求进入应用服务。系统会优先查询 一级缓存。如果数据存在,直接返回结果,这种情况延迟最低,通常只需要微秒级时间。

如果一级缓存未命中,则继续查询 二级缓存(Redis)。如果 Redis 中存在数据,则返回结果,并将该数据写入一级缓存,以便后续请求可以直接命中本地缓存。

如果 Redis 中也没有数据,则说明缓存未命中,此时系统需要访问数据库。数据库返回结果后,系统会同时写入 Redis 和一级缓存,从而建立新的缓存数据。

整个流程可以理解为:

L1 Cache → L2 Cache → Database

通过这种方式,大部分请求都可以在缓存层被拦截,从而避免频繁访问数据库。

为什么要设计两级缓存

一级缓存和二级缓存各自解决不同的问题,两者结合可以大幅提升系统性能。

降低 Redis 压力

在高并发系统中,如果所有请求都访问 Redis,Redis 可能成为新的瓶颈。通过一级缓存,大量热点数据可以直接在应用内存中返回,从而减少 Redis 请求数量。

减少网络开销

访问 Redis 需要网络通信,即使延迟只有 1ms,在高 QPS 场景下也会产生明显开销。而一级缓存是进程内访问,速度远远快于网络调用。

提升系统吞吐量

通过一级缓存,系统可以处理更多请求,而不会增加 Redis 或数据库负载。

提升热点数据访问效率

在很多业务场景中,少量热点数据会被频繁访问,例如:

  • 热门商品
  • 用户信息
  • 配置数据
  • 推荐结果

一级缓存可以让这些热点数据直接在本地命中。

一级缓存设计需要注意的问题

虽然一级缓存性能很好,但它也会带来一些新的问题。

首先是 数据一致性问题。由于一级缓存存在于每个服务实例中,不同实例的缓存数据可能不同步。当数据更新时,如果没有正确的缓存失效机制,可能会导致读取到旧数据。

为了解决这个问题,通常会采用 缓存失效策略。例如在数据更新时,通过消息队列或发布订阅机制通知所有服务实例清除本地缓存。

第二个问题是 缓存容量控制。一级缓存存在于应用内存中,如果缓存数据过多,可能会占用大量内存,影响系统稳定性。因此通常会使用 LRU 或 LFU 等策略限制缓存大小。

第三个问题是 缓存穿透和缓存击穿。当大量请求同时访问不存在的数据,可能会直接冲击数据库。通常可以通过布隆过滤器或互斥锁机制进行防护。

缓存更新策略设计

在多级缓存系统中,缓存更新策略非常关键。

常见策略包括:

Cache Aside(旁路缓存)

应用程序先查询缓存,如果未命中再查询数据库,然后写入缓存。这是最常见的一种模式。

Write Through(写穿透)

应用在写入数据库的同时也更新缓存,保证缓存和数据库数据同步。

Write Back(写回缓存)

应用只写缓存,由缓存系统异步写入数据库。这种方式性能更高,但实现复杂。

在互联网系统中,大多数业务都会采用 Cache Aside 模式,因为它实现简单且稳定。

一级二级缓存架构适用场景

多级缓存架构通常适用于以下场景:

高并发读取系统

例如商品详情页、用户信息查询、配置读取等。

热点数据访问频繁

例如排行榜、推荐列表等。

数据库压力较大

通过缓存层可以显著减少数据库查询次数。

对于一些实时一致性要求非常高的系统,例如金融交易系统,通常不会使用多级缓存,而是直接访问数据库。

文章目录

随心笔记

技术无止境 创新不停驻