我记得第一次认认真真把 Redis 用起来,跟 Redis 本身没什么关系,是被一个接口慢查询逼的。表里就几万条数据,MySQL 查询也走了索引,但接口平均响应时间还是到了 800 多毫秒。后来查了半天,发现是每次请求都在重复查同一份几乎不变的配置数据。把这段数据丢进 Redis,接口响应直接掉到 20 毫秒以内。那一刻我才意识到,很多人面试题里背得滚瓜烂熟的"缓存数据库",真正解决的是性能场景下的数据访问效率问题。
这篇内容写给刚接触 Redis、或者已经敲过 set/get 但还没形成体系的人。我会从"它到底解决了什么问题"讲起,把安装、五种核心数据类型、持久化、缓存问题、主从哨兵、分布式锁这些高频接触点全部串一遍,最后给一条适合自学的路径。既然是初识,我不会堆特别偏的源码细节,但会把真正影响你后续使用和理解的概念讲透。
1. Redis 到底是什么:先搞清楚它凭什么是"快"
1.1 一个内存和一个磁盘的差距有多大
Redis 最核心的标签就是"基于内存"。内存的随机读取延迟大概是 100 纳秒级,而 SSD 磁盘的随机读取延迟是 100 微秒级,传统机械硬盘更慢,能做到 10 毫秒就算不错。纳秒、微秒、毫秒,每一级都差了 1000 倍。也就是说,同样的数据放在内存里读,比放在磁盘上快几个数量级。这个差距不是靠优化 SQL、加索引能抹平的,这是存储介质的物理特性决定的。
打个比方,磁盘就像一个档案室,数据都归档在文件柜里,每次要资料都得跑一趟档案室去翻;内存就像你的办公桌,经常用的文件直接摊在桌面上,抬手就能拿到。Redis 做的事情,就是把一批高频使用的数据,从档案室搬到办公桌上。
但快只是结果,不是设计目标。Redis 的设计目标,是提供一套高效的数据结构操作接口,让开发者可以用极简的命令去操作内存中的数据。
1.2 Redis 和 MySQL 从来不是二选一
初学的时候最容易产生一个误解:有了 Redis 是不是可以不用 MySQL 了?完全不是。Redis 是数据结构的服务器,MySQL 这类关系型数据库是持久化存储和复杂查询的底座。它们的分工是:
| 维度 | Redis | MySQL 等关系型数据库 |
|---|---|---|
| 存储位置 | 主要内存,磁盘仅做持久化 | 磁盘为主 |
| 数据模型 | key-value 加多种数据结构 | 二维表、SQL、事务 |
| 响应速度 | 亚毫秒级 | 毫秒级起步 |
| 数据容量 | 受内存限制,单机一般几十 GB 量级 | 可扩展到 TB 级甚至更大 |
| 典型定位 | 缓存、计数器、队列、排行榜 | 业务数据的最终存储和复杂查询 |
所以更准确的理解是:MySQL 负责"数据的家",Redis 负责"数据的快车道",两个配合使用。比如用户信息落库在 MySQL,读接口先把 Redis 查一遍,没有再从 MySQL 加载并回填到 Redis,这就是最常见的旁路缓存策略。
1.3 哪些场景天然适合用 Redis
我自己的经验是,判断一个场景适不适合上 Redis,就问一句:这数据是不是被高频读、写简单、对一致性要求不那么苛刻?满足的话基本都可以考虑。
常见的典型应用有:
- 热点数据缓存:配置、商品详情、用户会话,读了以后短时间内变化不大。
- 计数器:点赞数、播放量、库存扣减,用 INCR/DECR 一条命令完成原子操作。
- 排行榜:ZSet 天然按分数排序,游戏排行榜、热销榜直接用一个 key 就能维护。
- 分布式场景协调:分布式锁、幂等控制、限流计数器,后面单独展开。
- 消息通信:List 的阻塞弹出可以实现轻量级队列,不需要立刻上 Kafka 这类重量级 MQ。
- 临时时效数据:验证码、限时优惠,设置过期时间即可自动清理。
理解了"Redis 是因为什么被需要"以后,再去装环境、敲命令,整个学习过程会顺畅很多。很多人学 Redis 学得痛苦,就是因为一上来死记命令,却不知道每一条命令在真实系统里解决什么问题。
2. 把 Redis 跑起来:安装、启动图形客户端、连接验证
我见过太多人卡在第一步。其实现在安装 Redis 的路径很成熟,我分别说三种常见方式,你自己按环境选。强调一句:学习阶段不要纠结安装最新版,6.x 已经非常稳定,很多生产系统还在用 6.2,拿来入门完全够用。
2.1 最省事的开发环境方案:Docker 一条命令
如果你的电脑上有 Docker,这是我认为最干净的启动方式,不会在系统里留下各种编译依赖。
docker run -d \ --name redis-dev \ -p 6379:6379 \ -v redis-data:/data \ redis:7.2 \ redis-server --appendonly yes拆开解释一下:
-p 6379:6379把容器里的 6379 端口映射到宿主机,这样本地客户端可以直接连。-v redis-data:/data是挂载数据卷。Redis 做持久化时会把 RDB/AOF 文件写到容器内的/data目录,挂载出来可以防止容器删除后数据全丢。redis-server --appendonly yes覆盖容器默认启动命令,开启 AOF 追加持久化。开发环境这么做,能避免你重启容器之后发现 key 全没了而一脸懵。
启动后用docker ps看容器状态,再用docker logs redis-dev看启动日志,出现Ready to accept connections tcp就说明起来了。
如果你要用 Docker Compose 管理,对应配置大概是这样的:
services: redis: image: redis:7.2 container_name: redis-dev ports: - "6379:6379" volumes: - redis-data:/data command: ["redis-server", "--appendonly", "yes"] volumes: redis-data:开发学习阶段没必要指定特别复杂的配置,等理解主从、哨兵之后,再对照生产环境去补齐密码、持久化策略和内存上限,那部分我会在第 5 节专门讲。
2.2 Windows 本机安装:注意官方支持和移植版的区别
Redis 官方网站其实从来没有提供过 Windows 原生安装包,这一点很多人不知道。Windows 上跑的 Redis 基本都是微软存档的移植版或者第三方的二次封装版本。所以在搜索"redis windows 下载"的时候,你会看到各种版本,质量参差不齐。
我的建议是优先考虑两种方式:
- WSL 或者 Docker Desktop:在 Windows 里起一个 Linux 环境跑官方版 Redis,行为最接近生产环境,学习过程中遇到问题和网上资料对得上。
- Memurai:一个兼容 Redis 协议的 Windows 原生实现,日常学习和轻量使用可以接受,但版本演进和 Redis 官方有差距。
如果你只是想在 Windows 图形界面里点点点,很多"Redis 安装包"其实还会捆绑 Redis Desktop Manager 这类可视化工具,下载时注意看来源,尽量选知名度高的站点,避免装到带广告的打包版。Windows 本机装的本质是练习环境,不是生产目标,所以不用花太多时间纠结"装得对不对",能启动、能连接就够了。
顺带推荐一下我的习惯:学习阶段我更喜欢直接用命令行redis-cli操作,图形工具用来看数据和排查问题。命令行会让你对命令本身更敏感,否则很容易陷入"只会点点点,不知道底层发了什么命令"的状态。
2.3 源码编译安装:Linux 服务器上的标准姿势
如果你有一台 Linux 服务器,或者云主机,源码编译安装是最接近官方推荐的方式。整个过程很直白:
wget https://download.redis.io/releases/redis-6.2.14.tar.gz tar xzf redis-6.2.14.tar.gz cd redis-6.2.14 make make install编译完成后,redis-server和redis-cli会安装到/usr/local/bin。然后可以直接启动:
redis-server --daemonize yes --protected-mode yes --requirepass yourpassword这里提醒两个入门阶段特别容易踩的坑。
第一,不要裸奔。Redis 默认绑定所有网卡并且没有密码,如果你在云服务器上这么跑,外网扫描工具扫到 6379 端口,几分钟就能被入侵,这就是网上一直在说的 Redis 未授权访问漏洞。生产环境必须设置requirepass,并且把bind改成内网 IP 或 127.0.0.1,同时保持protected-mode yes。
第二,编译前先确认系统里有gcc。缺少编译器的时候,执行make会报错,而不是给你什么友好的提示。CentOS 上用yum install -y gcc,Ubuntu/Debian 上用apt install -y build-essential,装完再 make 一般就通过了。
2.4 可视化客户端怎么选:RDM 和 Another Redis Desktop Manager
命令行跑通之后,你大概率会想找个图形工具看数据。Redis Desktop Manager 是老牌工具,最初是免费开源的,后来变成了商业软件,现在是官方推出的 Redis Insight 接过了"官方可视化客户端"的位置。另一个选择是开源的 Another Redis Desktop Manager,界面更现代,社区活跃,Windows/macOS/Linux 都能跑。
| 客户端 | 适用场景 | 说明 |
|---|---|---|
| redis-cli | 日常命令学习、生产排查 | 最可靠,任何环境都有 |
| Redis Insight | 官方推荐的可视化工具 | 支持数据浏览、命令行、性能分析 |
| Another Redis Desktop Manager | 轻量开源客户端 | 连接管理方便,适合多实例场景 |
可视化工具连接的时候,最常遇到的问题就是连不上。顺序排查:第一,Redis 是不是只绑定了 127.0.0.1,如果是,外部工具肯定连不上,需要改 bind;第二,密码是否填写正确,Redis 的密码在客户端里一般填在"Password"或"Auth"字段;第三,云服务器安全组和防火墙有没有放行 6379 端口,这个进云控制台看。
2.5 启动后的第一个自检流程
我建议装完不要急着背命令,先做三个验证,确认你的 Redis 真的处于健康可用的状态:
# 1. 检查服务是否存活 redis-cli -a yourpassword ping # 应该得到 PONG # 2. 写入和读取 redis-cli -a yourpassword set hello redis redis-cli -a yourpassword get hello # 3. 看当前有多少 key redis-cli -a yourpassword dbsize命令里的-a是密码参数,如果你没设密码就去掉。顺便提醒,-a在命令行里会把密码暴露在终端历史和进程列表里,生产环境排查时不建议用,一般用REDISCLI_AUTH环境变量或者登录后交互输密码,学习环境就无所谓了。
3. 五种基本数据类型:每个命令背后都是一个真实场景
Redis 的"五种数据类型"几乎是所有面试题和项目里都会出现的基础,但单纯背命令列表没什么意义。我按"场景 -> 命令 -> 为什么用这个类型"来讲,这样你合上文章之后,才能真的在项目里判断该用哪种。
3.1 String:缓存、计数器和一切简单的值
String 是最基础、使用率最高的类型,value 可以是字符串、数字、甚至是序列化后的对象。它适用的场景通常一句话能说完:一个 key 对应一个简单值。
缓存场景最典型:
SET user:profile:10086 '{"name":"张三","level":5}' GET user:profile:10086注意这里我是手动写了一个 JSON 字符串。真正在业务代码里,这个 JSON 一般是对象序列化后的结果,后面第 4 节讲序列化时再展开。
String 还有个容易忽略的杀手级能力:自增自减是原子的。
INCR article:read_count:99 INCRBY article:read_count:99 100 DECR stock:sku_123所谓原子,就是多个客户端同时执行 INCR 也不会互相覆盖。你在高并发场景下做计数器、库存扣减、生成自增序号,直接用 INCR 就行,这比"先 GET 出来、程序里加一、再 SET 回去"安全得多,后者在并发下一定会丢更新。
3.2 Hash:存"一个对象的多个字段"比 String 更合理
用户信息如果用 String 存整个 JSON,改一个字段就得把整个对象取出来、反序列化、改完再序列化、再写回,非常浪费。Hash 类型天然适合这种"对象"结构,每个 key 下面可以挂多个 field-value 对。
HSET user:10086 name "张三" level 5 HGET user:10086 name HGETALL user:10086 HINCRBY user:10086 level 1你看,HINCRBY可以直接对对象里的某一个字段做原子自增,这在 String 场景里要写一堆代码才能做对。购物车也特别适合 Hash:user:cart:10086 这个 key 下,field 是商品 ID,value 是加入数量,加购、改数量、删商品都只需要操作一个字段。
我的判断原则是:如果一个 key 下面的数据是"多个子字段",而且你会单独读写其中某些子字段,优先考虑 Hash,而不是无脑 JSON 塞进 String。
3.3 List:队列和时间线
List 底层是链表结构,两头操作的效率都很高。最常用的两个场景:消息队列和时间线列表。
生产者把消息推到左边,消费者从右边阻塞弹出:
# 生产者 LPUSH task_queue task:1 task:2 # 消费者 BRPOP task_queue 0BRPOP的 B 是 blocking,如果没有数据,会阻塞等待而不是立刻返回,0 表示永不超时。这个模式可以搭一个最简单的可靠队列:任务被消费后就从列表里移除,不会重复消费。当然它没有 RabbitMQ 那套 ack、重投机制,理解成"轻量队列"就好。
时间线场景更适合用LPUSH往头部插,再用LRANGE分页取:
LPUSH user:timeline:10086 "发布了一篇文章" LRANGE user:timeline:10086 0 9List 还经常用来做最新公告、操作日志这类"只关心最近 N 条"的数据,LTRIM key 0 99可以把列表裁剪到最近 100 条,避免无限增长。
3.4 Set:去重、交并集与标签系统
Set 是"不重复且无序"的集合。它最值钱的能力是集合运算。
最简单的场景是抽奖:把所有参与用户 ID 放进一个 Set,SRANDMEMBER随机抽一个,SPOP随机抽完并从集合移除。
SADD lottery:20240601 user_1 user_2 user_3 SRANDMEMBER lottery:20240601 1更实用的是交友/推荐系统的交集场景。用户 A 关注了 {a,b,c},用户 B 关注了 {b,c,d},两个人的共同关注用一条命令:
SINTER user:follow:A user:follow:B结果就是 {b,c}。类似地,SUNION做并集(比如给两个人推荐他们关注过的所有大 V),SDIFF做差集(比如我关注了你但你没关注我)。这种多集合运算要在 MySQL 里实现往往需要 join,在 Redis 里就是一个命令的事。
3.5 ZSet:排行榜和时间序最优雅的解法
ZSet 是 Set 的有序版本,每个成员关联一个 score,Redis 按 score 自动排序。排行榜就是为它量身定做的场景。
ZADD rank:game:100 100 user_a ZADD rank:game:100 200 user_b ZINCRBY rank:game:100 50 user_a ZREVRANGE rank:game:100 0 9 WITHSCORESZINCRBY可以实时加分,ZREVRANGE取出分数最高的前 10 名。要取某个人的排名,ZREVRANK;要按分数区间筛查,ZRANGEBYSCORE。
ZSet 还有一个很多人没想到的用法:延迟队列。把任务的执行时间戳作为 score,用ZRANGEBYSCORE key 0 当前时间戳拉取到期的任务,配合定时轮询,就能实现"N 秒后执行"这种轻量定时能力。这里的核心思想是:把时间纬度编码成 score,数据结构就拥有了排序和范围查询能力。
3.6 选择数据类型的通用判断方法
我经常跟朋友说,不要拿着类型列表去套场景,要反过来:先画一个数据存取流程,然后看它对"单个字段""顺序""去重""排序"分别是什么要求。
- 只有一个 value:String
- 一个对象,字段会被单独改:Hash
- 有顺序、只关心头尾:List
- 要去重、要做交并差:Set
- 要按某个分数排序、实时更新排名:ZSet
这套判断方法比背命令可靠得多。等你真的用熟悉了,再看 Redis 的位图、流等高级结构,都会轻松很多。
4. 初学阶段必须搞懂的四个机制:持久化、过期、淘汰、序列化
很多人学 Redis 学到一半会卡住,原因很统一:前面 set/get 玩得很爽,但一旦涉及重启、内存爆掉、Java 代码里存取数据出乱码,就开始一脸懵。这四个机制是初学阶段的拦路虎,也是面试问得最多的点。
4.1 为什么一重启数据就没了:RDB 和 AOF
Redis 默认对持久化是有配置的,但很多人并不清楚"数据存在内存里"和"数据会写进磁盘"是两回事。如果关闭了持久化,Redis 一旦重启,内存清空,所有 key 全部消失。
Redis 提供了两种持久化方案:
- RDB:按时间间隔生成内存数据快照,优点是恢复快、文件紧凑,缺点是如果刚好在两次快照之间宕机,会丢失最后一次快照之后写入的数据。
- AOF:把每一条写命令追加到日志文件,恢复时重放命令。AOF 比 RDB 丢数据少,但文件更大、恢复更慢。
生产环境的常见做法是两者同时开启,或者至少开启 AOF,并配合appendfsync everysec(每秒刷盘一次,最多丢一秒数据)。开发环境我用 Docker 启动时加--appendonly yes,也就是这个原因。
我这个建议非常直接:学习阶段也从一开始就开启 AOF 持久化。否则你某天敲了一堆数据,重启容器,发现全没了,很容易误以为 Redis 坏了,实际上只是持久化没开。
4.2 过期清理和内存淘汰:Redis 是怎么"处理放不下"的数据
给 key 设置过期时间,是缓存场景的基本操作:
SET verify:code:18800001111 '123456' EX 300EX 300表示 300 秒后过期。过期后的 key 是什么时候被删除的?Redis 用的是"惰性删除"加"定期删除"的组合。惰性删除是指访问到这个 key 时才发现它过期了,顺手删掉;定期删除是指后台周期性地抽查一批 key 并清理过期的。听起来有点绕,但结论很简单:过期的 key 不一定会立刻消失,但你 GET 它的时候不会拿到过期数据。
更关键的是内存淘汰策略。如果你设置了maxmemory,当内存达到上限,Redis 需要决定"踢掉哪些 key"。常见的策略有:
| 策略 | 行为 |
|---|---|
| noeviction | 不淘汰,写入报错(默认) |
| allkeys-lru | 从所有 key 中按最近最少使用淘汰 |
| volatile-lru | 从设置了过期时间的 key 中按 LRU 淘汰 |
| allkeys-lfu | 按访问频率淘汰 |
| volatile-ttl | 优先淘汰剩余时间最短的 key |
如果没有特殊要求,我一般建议线上配置maxmemory-policy allkeys-lru,意思就是内存快满时优先淘汰最久没用的 key,这对缓存类业务最友好。需要明确的是:LRU 是"近似 LRU",Redis 不会为每个 key 都维护精确的最近访问时间,而是采样后估算,但这在生产中已经足够有效。
4.3 序列化:为什么存进去的是对象,取出来是一堆乱码
这是使用 Redis 客户端时最典型的困惑。你往 Redis 里存一个 Java 对象,打开可视化工具一看,value 是一串以\xAC\xED开头的乱码,key 也可能变成\xAC\xED\x00\x05t\x00...这种。
原因是默认的RedisTemplate用的是 JDK 序列化,会把 Java 对象序列化成二进制。Redis 本身不管你存的是字符串、JSON 还是二进制,它都当成字节数组存下来。所以"乱码"其实不是 Redis 的故障,是序列化方式的选择问题。
解决思路分两种:
- 自己手动序列化:把对象转成 JSON 字符串再存,业界主流用 Jackson、Gson、Fastjson,取出来再反序列化。
- 配置统一的 RedisTemplate 序列化器:把 key 的序列化器改成 StringRedisSerializer,value 的序列化器改成 GenericJackson2JsonRedisSerializer。
用 Spring Boot 时,StringRedisTemplate默认就是字符串存取,适合纯字符串场景;如果你用RedisTemplate操作对象,一定要理解序列化器配置。否则你写的缓存,Java 服务自己能读,但跨语言、跨系统、可视化排查时全是二进制,调试成本极高。
4.4 缓存穿透、击穿、雪崩:三个名字像、原因不同的问题
Redis 做缓存后,第一个要学会的治理思路就是区分这三个词,因为它们经常同时出现在网上,但病因和治疗方案完全不同。
- 缓存穿透:查一个不存在的 key,缓存里没有,数据库里也没有,每次请求都打到数据库,相当于缓存失效。解决思路:空值也能缓存一段时间,或者用布隆过滤器先把不存在的 key 挡在外面。
- 缓存击穿:某个热点 key 突然过期,大量并发请求同时打到数据库。解决思路:热点数据尽量不过期,或者用互斥锁只让一个请求去回源数据库。
- 缓存雪崩:大量 key 在同一时刻过期,或者 Redis 整体不可用,导致数据库被压垮。解决思路:给过期时间加一个随机范围,避免集中过期;做高可用,避免单点。
我见过不少简历上写"解决了缓存雪崩",但问具体场景和代码,对方很难说清。我的理解是,这三个问题对初识 Redis 的人不是要求你现在就设计多复杂的方案,但你至少要知道:缓存并不是"加一层就万事大吉",这层的稳定性和数据一致性都会引入新的问题。缓存治理是一个持续的事情,后面我会单独写更深的案例。
5. 从单机到生产架构:主从、哨兵、分布式锁和部署注意
一个 Redis 实例学完,你会发现它是单线程的、有内存上限的、可能会有单点宕机风险的。生产环境里,Redis 很少是"一台裸实例"跑到底。所以初识阶段也要对主从、哨兵、分布式锁这些进阶概念有个整体印象,以后真正部署时才不会慌。
5.1 主从复制:读写分离和数据备份
主从复制是 Redis 高可用和扩展读性能的基础。简单说,一个主节点负责写,多个从节点复制主节点的数据,读请求可以分散到从节点上。配置从节点的方式:
# 在从节点的 redis.conf 里 replicaof 192.168.1.10 6379 # 如果主节点有密码 masterauth yourpassword配置完后,从节点会同步主节点数据。同步分两个阶段:第一次是全量同步,主节点生成 RDB 快照发给从节点;之后是增量同步,主节点把后续写命令传播给从节点。
主从复制解决的核心问题有两个:一是读写分离,把读压力分散;二是数据备份,主节点挂了,从节点上还有一份数据。但它不解决故障自动切换的问题,主节点真挂了,从节点不会自己上位,这就需要哨兵。
5.2 哨兵模式:故障自动切换
哨兵(Sentinel)是一个独立进程,专门盯着主从节点。当主节点不可达,哨兵会发起故障转移,把一个从节点提升为新主节点,并通知其他从节点和客户端。
网上常见的"哨兵模式启动未生成 known-sentinel 文件"这类问题,大概率和哨兵配置、日志路径相关。我自己的经验是,排查顺序应该是:先确认哨兵配置文件里的sentinel monitor mymaster <主节点IP> <主节点端口> <quorum>这一段 IP 是否填写正确,再确认哨兵进程对配置目录有没有写权限。很多时候不是逻辑问题,是配置里的 IP 写成了 127.0.0.1,导致哨兵之间没法互相发现。
学习阶段搭建哨兵,建议至少启动 3 个哨兵实例,quorum 设为 2,这样更贴近生产,也能看到"少数服从多数"是怎么工作的。但说实话,手动搭一遍只是为了理解原理,真正的生产环境,现在越来越多团队直接交给云厂商的托管 Redis 或者 Kubernetes 里的 Operator 去管理,人工搭哨兵的机会并不多了。理解了原理,再去看托管方案会非常快。
5.3 分布式锁:SETNX 只是起点
Redis 做分布式锁,最朴素的思路是用SETNX,意思是"如果 key 不存在才设置成功"。多个服务抢锁,谁 SETNX 成功谁拿到锁,用完删 key 释放。
SET lock:order:10086 unique_token EX 30 NX这条命令同时做了三件事:设置锁、设置过期时间、只在不存在时设置。EX 30是锁的超时时间,NX是 not exists。为什么一定要放在一条命令里?因为假设你分两步:
SETNX lock:order:10086 token # 第一步 EXPIRE lock:order:10086 30 # 第二步如果第一步成功、第二步之前服务宕机或网络抖动,锁没有过期时间,就会变成死锁,所有拿锁的请求全部卡死。所以一定要在一个原子操作里完成"加锁 + 过期时间",这也是面试里特别喜欢埋的坑。
还有两个细节,初学阶段最好就养成正确习惯。第一,value 要放一个唯一标识(比如 UUID),释放锁的时候先比对是不是自己的锁再删除,避免把别人后来拿到的锁删了。第二,过期时间到了但业务还没执行完,就需要看门狗机制自动续期,这个在 Redisson 里已经有成熟实现。分布式锁的坑很多很细,但理解SETNX + 过期时间是理解一切的基础。
5.4 生产环境部署 Redis 的几个底线配置
很多跟着教程学完的同学,第一次自己用 Docker Compose 部署 Redis 时,只写了端口映射就完事。这里我给一份我常用的最小生产配置模板,你可以在理解每个配置的含义之后再调整:
services: redis: image: redis:7.2 container_name: redis-prod restart: always ports: - "127.0.0.1:6379:6379" volumes: - ./redis-data:/data - ./redis.conf:/usr/local/etc/redis/redis.conf command: ["redis-server", "/usr/local/etc/redis/redis.conf"]对应的redis.conf里至少要包含:
requirepass your-strong-password bind 127.0.0.1 protected-mode yes appendonly yes maxmemory 2gb maxmemory-policy allkeys-lru几个配置的考虑:
- 端口映射写成
127.0.0.1:6379:6379,意味着只允许本机访问,应用服务器和 Redis 在同一台机器时这么干最安全。如果 Redis 和应用不在同一台机器,就把 bind 和端口暴露策略结合实际情况设置,同时用云安全组限制来源 IP。 protected-mode yes加requirepass,杜绝未授权访问。maxmemory必须设置,否则内存被写爆,操作系统 OOM 把 Redis 进程杀掉,比淘汰旧数据更难看。
这一节的内容对于"初识"来说可能有点密。我的想法是,你不需要立刻全消化,但至少要建立这个意识:单实例能跑通只是第一步,Redis 在真实系统里一定是配合高可用、安全、容量规划一起出现的。
6. 一条靠谱的 Redis 学习路径与面试知识点梳理
6.1 从命令到框架,再到一个完整项目
如果你完全从零开始,我建议的学习顺序是这样,每个阶段都配了明确的出口:
- 环境阶段:用 Docker 起一个 Redis,装载到 Redis 官方以 docs 为主的资料,学会
redis-cli的基本操作。这个阶段结束时,你应该能自己配置密码、开启持久化、用 RDM 或 Another Redis Desktop Manager 看到数据。 - 数据结构阶段:把 5 种基本类型全都实际敲一遍,重点是给每种类型找一个"你曾经在项目里真实遇到过的场景"。
- 代码集成阶段:用你熟悉的语言写一个最简单的缓存工具类。Java 方向就是理解
StringRedisTemplate和RedisTemplate的区别,以及序列化器怎么配。 - 进阶机制阶段:搞懂 RDB/AOF、过期淘汰、事务、管道 Pipeline、发布订阅。
- 生产架构阶段:搭建一主两从三哨兵,模拟主节点宕机,观察哨兵怎么完成故障切换。
- 实战项目阶段:把缓存穿透/击穿/雪崩的治理手段、分布式锁,用到你自己的项目里。网上比较经典的实战演示项目里,黑马点评这类带完整前后端和 Redis 应用的课程,对初学者很友好;还有些朋友会跟着视频课手写一个秒杀项目,把库存预减、限流、分布式锁全部练一遍,效果也非常好。
我个人不建议一上来就去读源码。先做到"能用、知道为什么这么用",再考虑源码细节。否则你看着源码里的跳跃表、字典结构,大概率是劝退而不是提升。
6.2 面试高频点:初识阶段就要有个思维框架
Redis 是后端面试的常客,但面试官其实不是要你背八股,而是看你能不能把一个概念说清楚、能不能对比选型。我把常见的考察点整理成一份自查表:
| 考察方向 | 核心问题 | 初学至少要能说出 |
|---|---|---|
| 数据结构 | String/Hash/List/Set/ZSet 区别 | 每个类型对应什么场景,为什么要用它 |
| 持久化 | RDB 和 AOF 优缺点 | 什么时候会丢数据,恢复速度差异 |
| 过期与淘汰 | 过期 key 怎么删除,内存不够怎么办 | 惰性删除+定期删除,常用淘汰策略 |
| 缓存问题 | 穿透、击穿、雪崩分别是什么 | 能说出区别和一个简单解决方案 |
| 分布式锁 | SETNX 为什么不能拆成两步 | 原子操作、过期时间、唯一标识 |
| 高可用 | 主从、哨兵、集群的关系 | 主从解决复制、哨兵解决自动切换 |
| 性能 | 为什么快,单线程为什么快 | 内存、IO 多路复用、避免上下文切换 |
把这些能用自己的话讲清楚,Redis 面试这一块基本就稳了,更重要的是,你对 Redis 的真实使用场景会有一个成体系的认知。
6.3 学会自我排查:监控命令和调试工具
初学者最容易忽略的,是学习阶段就养成用 Redis 自带的运维命令看问题的习惯。这几个命令我认为很值得记:
ping:确认连接正常。info:看内存、连接数、持久化状态、复制信息,重点看memory和replication段落。MONITOR:实时打印 Redis 收到的每一条命令,调试代码里到底发了什么请求特别好用。注意生产环境不要随便开着,有性能开销。slowlog get:查看慢查询日志,命令执行超过slowlog-log-slower-than阈值就会被记录。redis-cli --bigkeys:扫描大 key,找到占用空间不正常的对象,生产排查经常用到。
有一次我定位线上缓存问题,发现某个 key 的 value 有几十 MB,就是靠--bigkeys扫出来的。这种工具类命令不需要背得很全,但你要知道自己能通过哪些路径获取 Redis 的运行状态。
写到这里,Redis 的初识地图基本就画完了。从我自己的体会来说,Redis 是一门"实践反馈极其直接"的技术——你装好、敲命令、写代码,立刻能看到性能变化和数据结构带来的便利。但它也是一门"越深入越复杂"的技术,从单机到高可用,从缓存到分布式协调,每一个方向都能延伸出大量实战细节。
如果你现在刚起步,我的建议很简单:先把今天这篇里的命令亲手敲一遍,再找一个你项目里的真实场景,把代码改成用 Redis 实现。不要贪多,不要急着把集群、分片、源码全部看完,先把"用起来"这件事做扎实。后面你会发现,那些曾经觉得深奥的概念,当你真的遇到了一次缓存穿透、一次主从切换、一次分布式锁的并发事故之后,也就自然而然理解了。