CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Redis 缓存入门/课时/Redis 是什么
RawBlame
课时目录12 节

Redis 缓存入门

  1. 01Redis 是什么
  2. 02CLI 与键命名
  3. 03String 与计数
  4. 04Hash / List / Set / ZSet
  5. 05过期与淘汰
  6. 06缓存模式
  7. 07Spring Data Redis
  8. 08会话与 Sa-Token
  9. 09Docker 运行 Redis
  10. 10Pub/Sub 入门
  11. 11测试与监控
  12. 12综合练习

Redis 是什么

内存 KV、缓存 vs 数据库、在本站架构中的角色。

25 分钟

Redis 是什么

这一课你将能做到

  1. 用自己的话说清 Redis 的定位:内存键值数据结构存储,常用于缓存、会话、计数、限流,并指出它和 MySQL 在本站架构里各管什么
  2. 用 Docker 在本机起一个 Redis,用 redis-cli 完成 PING、SET、GET,第一次亲手摸到数据
  3. 打开本站 backend 的 application.yml 和 RedisConfig.java,说出 codeforge.redis.enabled 开关打开后会启用哪些能力(Sa-Token 会话、Redis 限流、StringRedisTemplate)

为什么要学

想象一个真实场景:你的 GET /api/tracks 接口,每个访客打开首页都会触发一次 MySQL 全表查询。100 个人同时访问,就是 100 次几乎一模一样的 SQL。数据没变,结果却每次都重新算——这就是典型的热点读问题。

Redis 把「按 key 立刻拿到值」这件事做到了微秒级:数据放内存、结构简单、没有 SQL 解析开销。同样的请求,第一次查 MySQL 并把结果写进 Redis,之后 5 分钟内的请求全部由 Redis 直接返回,数据库压力骤降。

除了缓存,Redis 还解决另外几个 MySQL 不擅长的问题:

  • 会话共享:本站生产环境跑多个 Spring Boot 实例,登录态必须存在所有实例都能读到的地方——Redis 是本站的选择(Sa-Token + sa-token-redis-jackson)
  • 计数与限流:INCR 原子自增,天然适合「每分钟最多 90 次请求」这种配额判断,本站 RedisRequestRateLimiter 就是这么实现的
  • 排行榜、去重:ZSet、Set 等结构后面会学

本站的实际分工非常明确:MySQL 是权威数据源(课程、用户、进度都必须落库),Redis 是加速与共享层(缓存只读视图、存会话、做限流)。这门课的全部内容都围绕这个边界展开。

面试里 Redis 也是 Java 后端必考题:为什么快、缓存三兄弟(穿透/击穿/雪崩)、怎么保证一致性,几乎每场面试都会遇到。学完这 12 课,这些问题你都能结合亲手做过的项目回答。

先建立图像

先看本站的整体架构,Redis 的位置一目了然:

浏览器
  → platform(Next.js 前端)
  → backend(Spring Boot :8080)
        ├─ MySQL(:3306):cf_track 等权威表
        │     课程内容、用户、进度、订单类数据 → 必须落这里
        └─ Redis(:6379,可选,codeforge.redis.enabled=true)
              ├─ Sa-Token 会话(sa-token-redis-jackson)→ 多实例共享登录态
              ├─ 公开接口限流(rl:* + INCR)→ 防爬虫/防刷
              └─ 业务缓存(coderoadmap:*)→ 综合练习课你会亲手加

再看 Redis 内部,它本质上是一个大 Map:

Redis
 ├─ key: "coderoadmap:tracks:list"   → value: '[{"slug":"redis-essentials",...}]'(String)
 ├─ key: "rl:203.0.113.7"            → value: '42'(String 计数,TTL 60s)
 ├─ key: "satoken:login:token:..."   → value: 会话信息(Sa-Token 管理)
 └─ key: "user:1001:bookmarks"       → value: Set{...}

和 MySQL 对比,差异一目了然:

RedisMySQL(本站主库)
定位
加速、临时、共享状态
权威、持久、事务、关联查询
存储介质内存为主(RAM)磁盘为主(InnoDB)
访问方式按 key 取,常见 O(1)SQL 解析、索引、可复杂查询
典型延迟亚毫秒几毫秒到几十毫秒
数据丢了缓存可从 MySQL 重建;会话用户需重登不可接受,需要备份和事务
事务简单(MULTI/EXEC,无回滚)完整 ACID
本站开关codeforge.redis.enabled始终需要

人话:MySQL 是公司账本,必须准、可审计、永不丢;Redis 是柜台上的一摞便签,谁问得勤就先看便签,便签丢了可以从账本再抄一份。

跟着做

步骤 1:用 Docker 起一个本地 Redis

确保 Docker Desktop 已启动,然后:

docker run -d --name redis-dev -p 6379:6379 redis:7-alpine

参数拆解:-d 后台运行;--name redis-dev 给容器起名;-p 6379:6379 把容器的 6379 端口映射到宿主机;redis:7-alpine 是官方 7.x 精简镜像。

验证容器在跑:

docker ps --filter name=redis-dev

应看到 STATUS 为 Up ...。

步骤 2:第一次 PING 和 SET/GET

进入容器自带的 redis-cli:

docker exec -it redis-dev redis-cli

进入交互界面后依次执行:

PING
SET hello "redis-works"
GET hello
TTL hello

应看到:PONG、OK、"redis-works"、-1。

-1 表示这个 key 存在但没有设过期时间。现在删掉它并退出:

DEL hello
exit

如果你在 Windows 上没有本地 redis-cli,用 docker exec -it redis-dev redis-cli 即可,功能完全一样。第 9 课会专门讲 Docker 运行 Redis 的各种姿势,这里先能连上就行。

步骤 3:读本站的 Redis 开关

打开 backend/src/main/resources/application.yml,注意这一段:

codeforge:
  redis:
    enabled: false

默认值是 false——本机开发不启动 Redis 也能把 backend 跑起来,登录走单机内存实现,限流走内存实现(见 RateLimitConfig 的 matchIfMissing = true 分支)。这是有意设计的:本地开发少一个外部依赖,新人克隆仓库就能启动。

步骤 4:读 RedisConfig,看开关背后是什么

打开 backend/src/main/java/com/codeforge/config/RedisConfig.java:

@Configuration
@ConditionalOnProperty(name = "codeforge.redis.enabled", havingValue = "true")
public class RedisConfig {

    @Bean
    public LettuceConnectionFactory redisConnectionFactory(...) { ... }  // 1. 连接 Redis 的"水管"

    @Bean
    public StringRedisTemplate stringRedisTemplate(LettuceConnectionFactory factory) { ... }  // 2. 字符串读写工具

    @Bean
    public RequestRateLimiter redisRequestRateLimiter(StringRedisTemplate stringRedisTemplate) { ... }  // 3. Redis 限流

    @Bean
    public SaTokenDao saTokenDao(LettuceConnectionFactory factory) { ... }  // 4. Sa-Token 会话转存 Redis
}

类上的 @ConditionalOnProperty 是关键:只有 codeforge.redis.enabled=true 时,这 4 个 Bean 才会被创建。开关一开,会话和限流就一起切换到 Redis 实现——不是「多了一个模板」,而是整组能力换轨。

步骤 5:对照生产配置

打开 backend/src/main/resources/application-prod.yml:

spring:
  data:
    redis:
      host: ${REDIS_HOST:127.0.0.1}
      port: ${REDIS_PORT:6379}
      password: ${REDIS_PASSWORD:}

codeforge:
  redis:
    enabled: true

结论写进笔记:「本机默认关,生产 profile 默认开」。host、密码全部走环境变量注入,代码里不出现明文配置。

步骤 6:给数据分类(练习)

拿一张纸或笔记,把下面这些数据分两列——「必须 MySQL」和「适合 Redis」:

课程标题、用户密码哈希、登录 token、 tracks 列表接口的返回值、学习进度、每 IP 每分钟请求次数、订单金额。

参考答案:课程标题(MySQL,可加缓存副本);密码哈希(只 MySQL,绝不放 Redis);登录 token(Redis);列表返回值(Redis 缓存,MySQL 权威);学习进度(MySQL);限流计数(Redis);订单金额(MySQL)。

判断标准只有两条:丢了能不能接受?需不需要复杂查询/事务? 两个都「不需要」的,才有资格进 Redis。

讲清楚要点

  1. Redis 是内存数据结构存储,不只是「字符串 KV」:String、Hash、List、Set、ZSet 各有场景,第 4 课展开。
  2. 因为数据在内存,所以快;因为内存贵,所以不能当主存——只放热点、可重建、临时的数据。
  3. 因为命令在服务端基本由单线程执行,所以慢命令会拖住所有人——这个特性决定了后面 KEYS 禁用、SCAN 代替等一系列纪律。
  4. 因为本站用条件装配,所以 enabled=false 时连连接工厂都不创建——本机无 Redis 也能启动;开了却连不上,会在启动或首次访问时报错。
  5. 因为多实例共享登录态需要中心存储,所以生产把 Sa-Token 会话放进 Redis——任意节点都能校验同一个 token。
  6. 因为公开接口要防刷,所以限流用 rl: 前缀 + INCR 共享配额——多实例下内存计数会各算各的,Redis 计数是全局的。
  7. 因为缓存是副本,所以写路径永远先保证 MySQL 成功——「先写库再删缓存」是第 6 课的核心。
  8. Redis 可选持久化(RDB/AOF),不是「内存存储 = 断电必丢」,第 9 课细讲。

你可能会懵的地方

  • Redis 和 Memcached 有什么区别? 入门记住三点就够:Redis 数据结构更丰富(Memcached 基本只有字符串)、支持持久化、支持发布订阅。Memcached 更纯粹的多线程缓存。本站选 Redis 是因为会话、限流、缓存能用同一个实例解决。

  • 「内存存储」是不是断电就全没了? 未开持久化时,进程一停数据就丢。可以开 RDB(定时快照)或 AOF(命令日志)来降低丢失窗口。但要分数据看后果:缓存丢了回源重建即可;会话丢了用户要重新登录——所以第 9 课会讲「会话实例更需要 AOF」。

  • Redis 为什么快?是不是用了多线程? 快的根源:① 数据在内存,没有磁盘 IO;② 命令执行是单线程,没有锁竞争和上下文切换;③ IO 多路复用(epoll)让单线程能同时监听大量连接;④ 数据结构针对场景优化(如跳表、ziplist/listpack)。核心命令执行确实是单线程,Redis 6+ 的多线程只用于网络读写和部分异步任务。

  • Redis 能替代 MySQL 吗? 本课和整个 track 都不会教你这么做。Redis 没有完整 SQL、没有外键、事务不回滚,做不了复杂关联查询。正确姿势是 MySQL 存权威数据 + Redis 放加速副本。

  • 为什么 enabled: false 时加了 spring-boot-starter-data-redis 依赖也没连接产生? 依赖只是把类放进 classpath,Spring Boot 会在 classpath 有 Redis 类时自动配置连接工厂——但本站用 @ConditionalOnProperty 主动拦住了自动装配,开关不开、Bean 不建、连接不发生。这解释了为什么「引入依赖」不等于「已连接」。

错法对照

错法问题正解
把 Redis 当唯一用户数据仓库丢数据、难查询、难事务MySQL 权威,Redis 加速
开发环境强制 enabled: true 但没起 Redis启动失败或登录异常本机保持 false,或先起 Docker Redis
以为加了 starter 依赖就在用 Redis忽略条件装配看 codeforge.redis.enabled 与 RedisConfig
会话 key 和业务缓存 key 混用前缀清理时误删登录态satoken: / rl: / coderoadmap: 三类前缀分立
一上来就学集群、哨兵、分布式锁全家桶没有单机模型做地基先完成本 track 12 课单机内容

卡点急救

  1. docker run 报 port is already allocated:6379 被占(可能已有本地 Redis 或旧容器)。docker ps 查旧容器 docker rm -f 掉,或换端口 -p 6380:6379(后端配置也要同步改 port)。
  2. PING 报 NOAUTH Authentication required:你连的 Redis 设了密码。交互模式里先 AUTH 你的密码,或用 redis-cli -a 密码 连接。
  3. Connection refused:容器没起来或端口映射错了。docker ps 确认 0.0.0.0:6379->6379/tcp 在列;不在就 docker logs redis-dev 看报错。
  4. Windows 找不到 redis-cli 命令:不必装,直接 docker exec -it redis-dev redis-cli 用容器内的客户端。
  5. backend 开了 enabled: true 却启动报错:八成是 Redis 没起或 host/port 不对。先 PING 通再开开关;本地开发顺手保持 false 最省心。

面试常问

  • Redis 为什么快? 内存操作 + 单线程命令执行(无锁、无上下文切换)+ epoll IO 多路复用 + 为场景优化的高效数据结构。注意别说「因为它多线程」——恰恰相反,核心是单线程 + 多路复用。

  • Redis 和 MySQL 怎么分工? MySQL 是持久化的权威数据源,负责事务、复杂查询;Redis 是内存加速层,负责缓存热点读、共享会话、计数限流。写路径先落 MySQL,读路径先走 Redis、miss 回源 MySQL。

  • Redis 是单线程的,为什么还能扛高并发? 单线程避免了锁和线程切换开销,而它的瓶颈从来不是 CPU 而是内存和网络;epoll 让一个线程管理成千上万连接,每个命令又是内存级的微秒操作,所以吞吐量依然极高。

  • 你们项目里 Redis 具体用在哪儿? 按本站真实情况答:① Sa-Token 分布式会话(sa-token-redis-jackson),多实例共享登录态;② 公开接口限流(INCR + EXPIRE 固定窗口);③ 业务只读接口的 Cache-Aside 缓存(tracks 列表)。同时说明本机开发通过配置开关可整体关闭,生产 profile 开启——体现「依赖可降级」的工程意识。

自测三问

  1. 用一句话说明:本站什么数据必须进 MySQL,什么数据适合进 Redis?判断标准是什么?
  2. codeforge.redis.enabled=true 之后,RedisConfig 会注册哪 4 个 Bean?分别服务什么能力?
  3. 为什么说「缓存丢了可以重建,会话丢了用户会被踢下线」?

小结一句话

Redis 是内存键值数据结构存储,本站把它当缓存、会话与限流的共享层,MySQL 永远是权威数据源。

延伸

  • What is Redis?(官方介绍)
  • Redis 数据类型总览(第 4 课预习)
  • 下一课:CLI 与键命名——学会用 redis-cli 看 key、管 key,以及为什么生产环境禁用 KEYS *。
加载本节练习…
下一课 →CLI 与键命名