Skip to content

Redis 入门:从安装到第一个缓存

本文是 Redis 系统学习系列的 L1 入门篇。前置:无。 学完可以配合面试题食用:05-cache-penetration-breakdown-avalanche

Redis 是什么

Redis 是一个内存键值存储,常被当作缓存、计数器、队列用。它快的原因一句话就能说清:数据在内存,读写走 epoll 事件循环,单线程避免锁竞争。详细原理在面试题 0831 展开。

装一个用 Docker 最快:

bash
docker run -d --name redis -p 6379:6379 redis:7-alpine
redis-cli ping
# PONG

redis-cli 是自带的命令行客户端,后面所有实验都靠它。

基础和库:别拿 SELECT 当 namespace

Redis 默认有 16 个库(0-15),用 SELECT n 切换。但生产上别用库做隔离——每个库共用同一条持久化策略,一个库内操作阻塞会影响其他库。不同业务用独立实例,或者用 key 前缀区分(user:1000:profile)。

key 命名规范社区约定是 : 分隔,如 user:1000:profile。没有层级结构,纯字符串,冒号只是给人看的。

五大类型速览

Redis 不是简单的 key-value。同样一个 key,value 可以是五种类型之一,每种有对应的业务场景:

类型一句话场景命令
String计数、缓存一段 JSONSET key value / INCR key
Hash对象字段增删不改整体HSET user:1000:profile name "Alice" age 30
List最新 N 条动态、消息队列雏形LPUSH timeline:1 {msg} + LTRIM timeline:1 0 99
Set标签、去重、共同关注、抽奖SADD article:1:tags java / SINTER
ZSet排行榜、带权重的队列ZADD leaderboard 1000 "user:1" / ZREVRANGE

每类型的内部编码(SDS、Dict、Listpack、Skiplist)在 L2 篇细讲,入门阶段先记住 "什么场景用什么类型" 就行。

第一个缓存:Cache Aside 模式

缓存最常用的模式是 Cache Aside(旁路缓存)。读流程:先查缓存,没命中则查数据库,回写缓存。写流程:更新数据库后删除缓存,而不是更新缓存。

为什么删不是改?因为并发写场景下,更新缓存会遇到"先更新缓存还是先更新数据库"的时序问题,删缓存让下一次读触发重建,天然避免脏数据。

下面是一个 Spring Boot + StringRedisTemplate 的完整示例:

java
@Service
public class UserService {
    private final StringRedisTemplate redis;
    private final JdbcTemplate db;

    public UserService(StringRedisTemplate redis, JdbcTemplate db) {
        this.redis = redis;
        this.db = db;
    }

    // 读:先查缓存,没命中查 DB 回写
    public Map<String, Object> getUser(Long id) {
        String key = "user:" + id;
        String cached = redis.opsForValue().get(key);
        if (cached != null) {
            return JSON.parseObject(cached);  // 缓存命中
        }
        // 缓存未命中 -> 查 DB
        Map<String, Object> user = db.queryForMap("SELECT * FROM user WHERE id = ?", id);
        // 回写缓存,过期时间 1 小时,防止缓存雪崩
        redis.opsForValue().set(key, JSON.toJSONString(user), 1, TimeUnit.HOURS);
        return user;
    }

    // 写:更新 DB -> 删除缓存
    public void updateUser(Long id, Map<String, Object> data) {
        db.update("UPDATE user SET name = ? WHERE id = ?", data.get("name"), id);
        // 一定删缓存,而不是 SET 新值
        redis.delete("user:" + id);
    }
}

注意三点:

  • 缓存 TTL 必须设置,否则数据改完永远不更新
  • 删缓存之前先确认 DB 写入成功,如果 DB 失败则不能删(保持缓存不变)
  • 并发场景下,读未命中查 DB 和回写缓存之间可能被另一个写覆盖,带上 SET NX 加锁可进一步稳,入门阶段上面代码够用

过期与内存:别让 Redis 说爆就爆

Redis 会给每个 key 设置 TTL(秒级),到期自动删除。常用命令:

bash
SET key value EX 3600        # 设置 1 小时过期
TTL key                      # 看剩余秒数,-1 表示没设过期,-2 表示已过期
PERSIST key                  # 去掉过期
EXPIRE key 300               # 修改过期时间

不设 TTL 的 key 会一直占内存。生产上 maxmemory 设实例内存上限(比如 4GB),超限后 Redis 按淘汰策略(LRU/LFU/TTL)逐出。不做配置的话,Redis 会一直涨到 OOM 被系统杀掉。

常见误区与小结

  • 误区 1:用 SELECT 库做隔离。不同库共享 fork 和持久化,一个库的大 key 倒腾会影响全实例。每个业务该单独实例或集群。
  • 误区 2:缓存更新用 SET 而不是 DELETE。并发写 + 读时容易读到旧值("先更新缓存再写 DB"或"先写 DB 再更新缓存"都有时序问题),DELETE 让下一次读重新拉取最安全。
  • 误区 3:所有 key 不设 TTL。Redis 不是关系型数据库,不设 TTL 的缓存就是内存泄漏的源头。
  • 误区 4:一个 key 塞超大数据。String 塞几 MB 大 JSON 或百万成员 Hash,读写都阻塞事件循环,用 MEMORY USAGE key 可以看实际占用量。

小结:这一篇跑通了 Redis 安装、五大类型的基本认知、Cache Aside 的 Java 写法、和 TTL 的必要性。接下来去 28. 五种数据类型的典型业务用法,每个类型会展开具体业务场景代码。

参考

参考:Redis 官方文档 Data Types / Redis Documentation

手撕 → 框架 → 生产化,一步步把 AI Agent 工程化搞透。
粤ICP备2026104257号-1