配置 Redis 作为高效的多层缓存

配置 Redis 缓存内存限制、逐出策略、TTL 和持久化选项,构建可靠的多层缓存。

配置 Redis 作为高效的多层缓存

Redis 之所以快,是因为它将工作数据保存在内存中,但不受管理的缓存仍可能填满主机并导致写入失败。当您将 Redis 用作应用程序与较慢数据库之间的多层缓存时,关键决策包括内存限制、逐出策略、TTL 规范以及是否持久化缓存数据。

本指南重点介绍 Redis 在缓存工作负载中的配置,而非主数据存储。

理解 Redis 缓存层

在许多应用设计中,Redis 是位于较小进程内缓存之后的共享缓存。您的应用程序可能将少量热点值在本地保留几毫秒,而 Redis 则存储更大规模的可重用对象,持续数秒或数分钟。这使得 Redis 成为在流量高峰时保护数据库的缓存层。

高效配置取决于两个核心领域:

  1. 内存管理:设置 Redis 可消耗内存的硬性限制。
  2. 逐出策略:确定当达到内存限制时,Redis 如何决定删除哪些键。

1. 设置内存限制以确保稳定性

防止 Redis 消耗所有可用系统内存对于主机稳定性至关重要。maxmemory 指令为数据集分配的内存(不包括开销)设置了绝对上限。如果达到此限制,Redis 将根据配置的策略开始逐出键。

配置指令:maxmemory

此设置在生产环境中至关重要。常见的最佳实践是留出一些余量给操作系统任务和 Redis 开销(例如内部数据结构、复制缓冲区)。

示例配置(redis.conf):

# 设置最大内存使用量为 4 GB
maxmemory 4gb

提示: 始终使用人类可读的后缀(例如 100mb2gb)以便于配置管理。

内存策略执行

如果设置了 maxmemorymaxmemory-policy 保持为 noeviction,则一旦达到限制,需要更多内存的命令将失败。对于缓存,请选择一种逐出策略,让 Redis 丢弃旧的缓存条目,而不是拒绝正常的缓存写入。

2. 选择合适的逐出策略(maxmemory-policy

此指令定义了当内存限制被突破时,Redis 用于选择要删除哪些键的算法。选择正确的策略在很大程度上取决于应用程序数据的访问模式。

易失性与非易失性策略

策略通常根据是否考虑键上设置的生存时间(TTL)过期来分类:

  • 易失性:仅考虑设置了过期时间(EXPIRESETEX)的键。
  • 所有键:考虑所有键,无论是否设置 TTL。

对于大多数项目都有明确过期时间的纯缓存层,易失性策略非常出色。如果您依赖外部应用程序逻辑来管理数据陈旧性,则可能更喜欢非易失性策略。

关键逐出算法详解

A. 最近最少使用(LRU)

这是最常见且通常是通用缓存的默认策略。它会删除最长时间未被访问的键。当访问模式遵循时间局部性原则(最近访问的数据很可能很快再次被访问)时,此策略效果最佳。

配置:

maxmemory-policy allkeys-lru

B. 最不经常使用(LFU)

LFU 跟踪键被访问的频率。它会逐出估计访问频率较低的键。当您的工作负载具有一组稳定的热门键,这些键应在偶尔的扫描或一次性读取中幸存时,此策略效果良好。

配置:

maxmemory-policy allkeys-lfu

C. 基于 TTL 的逐出

当键具有有意义的过期时间且最接近过期的键是最安全的删除对象时,基于 TTL 的逐出非常有用。

配置:

maxmemory-policy volatile-ttl

此策略仅考虑设置了过期时间的键。如果许多键没有 TTL,Redis 可能仍然耗尽可逐出的键并拒绝写入。

D. 随机逐出

随机逐出很简单,有时对于一次性缓存数据可以接受,但当您的缓存具有清晰的访问模式时,它很少是首选。

maxmemory-policy allkeys-random

3. 一致地设置 TTL

逐出策略是一个压力释放阀,而不是您唯一的缓存失效策略。大多数缓存键应具有与数据业务价值相匹配的过期时间。

例如,产品详情页面可能会将渲染的片段缓存五分钟:

redis-cli SET product:123:html "$HTML" EX 300

用户权限查找可能需要更短的 TTL,因为陈旧数据风险更高:

redis-cli SET user:42:permissions "$JSON" EX 30

避免将永久键与一次性缓存键混合到同一个 Redis 数据库中,除非您使用 allkeys-* 策略并且可以接受任何键被逐出。如果某些数据绝不能逐出,请将其保存在具有不同策略的单独 Redis 实例或数据库中。

4. 决定缓存持久化是否有帮助

对于纯缓存,Redis 持久化是可选的。禁用 RDB 和 AOF 可减少磁盘 I/O 和重启复杂性,但 Redis 重启时会丢失所有缓存键。

save ""
appendonly no

当您的应用程序可以从数据库重建缓存时,这是可以接受的。如果缓存预热成本高昂或冷缓存会使数据库过载,请保持 RDB 快照或 AOF 启用,并在负载下测试重启行为。

5. 监控缓存健康

使用 Redis 指标确认缓存正在发挥作用:

redis-cli INFO memory
redis-cli INFO stats
redis-cli INFO keyspace

特别关注以下字段:

指标 说明
used_memory_human Redis 当前消耗的内存。
maxmemory_human 配置的内存上限。
evicted_keys Redis 是否在压力下逐出键。
keyspace_hitskeyspace_misses 缓存是否提供有用的读取。
expired_keys TTL 清理是否活跃。

如果 evicted_keys 快速上升且命中率下降,请增加内存、缩短低价值键的 TTL,或将嘈杂的工作负载拆分到单独的缓存中。

示例缓存配置

以下是专用于一次性缓存条目的 Redis 实例的合理起点:

maxmemory 4gb
maxmemory-policy allkeys-lfu
save ""
appendonly no

对于每个键都有精心选择 TTL 的缓存:

maxmemory 4gb
maxmemory-policy volatile-ttl

使用 CONFIG GET maxmemory maxmemory-policy 验证活动设置:

redis-cli CONFIG GET maxmemory maxmemory-policy

要点

将 Redis 缓存配置视为容量控制问题。设置 maxmemory,选择与访问模式匹配的逐出策略,为缓存键设置明确的 TTL,并决定持久化是否值得磁盘 I/O。然后监控命中率、逐出和内存增长,以便缓存保护您的数据库,而不是成为下一个瓶颈。