Redis 入门最直接的方式就是:装好 → 命令行玩一遍 → 再上代码。下面按这个顺序走。
1. 安装 & 启动(macOS)
bash
brew install redis # 安装
redis-server # 前台启动(会占用当前终端)
# 或后台启动:
brew services start redis # 开机自启的常驻方式再开一个终端连上去:
bash
redis-cli # 进入交互式命令行
redis-cli ping # 应返回 PONG2. 先把最核心的概念玩通:String + 过期时间
Redis 本质是「内存 key-value 存储」,最小可用单位就是 SET / GET:
bash
SET name "tom" # 存
GET name # 取 → "tom"
EXISTS name # 是否存在 → 1
DEL name # 删过期时间(TTL) 是 Redis 的杀手锏,也是入门必须会的一个:
bash
SET code 123456 EX 60 # 存一个验证码,60 秒后自动删除
TTL code # 查看剩余秒数很多缓存场景(验证码、会话、接口缓存)全靠这一句。
3. 五种数据类型(逐个敲一遍)
| 类型 | 命令 | 典型用途 |
|---|---|---|
| String | SET/GET/INCR | 缓存、计数器 |
| Hash | HSET/HGET/HGETALL | 存一个对象(用户信息) |
| List | LPUSH/RPUSH/LRANGE | 队列、消息列表 |
| Set | SADD/SMEMBERS/SINTER | 去重、共同好友 |
| Sorted Set | ZADD/ZRANGE | 排行榜 |
bash
# Hash —— 存对象
HSET user:1 name tom age 20
HGET user:1 name # → "tom"
HGETALL user:1
# List —— 队列(左进右出)
LPUSH queue a b c
RPOP queue # → "a"
# Set —— 去重 / 交集
SADD tags:1 redis db
SADD tags:2 redis cache
SINTER tags:1 tags:2 # → "redis"
# Sorted Set —— 排行榜(按分数排序)
ZADD rank 100 tom 200 jerry
ZREVRANGE rank 0 -1 WITHSCORES # 从高到低4. 上代码(以 Python 为例,你的 notes 仓库就是 Python 环境)
bash
pip install redispython
import redis
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
# 写缓存 + 加过期
r.set("user:1:name", "tom", ex=60)
print(r.get("user:1:name")) # → tom
# 计数器
r.incr("page:views")
print(r.get("page:views")) # → 1
# Hash
r.hset("user:1", mapping={"name": "tom", "age": 20})
print(r.hgetall("user:1"))5. 入门必须理解的 3 件事
- Key 命名习惯:用
:做层级,如user:1:name、order:2024:list,方便管理和批量操作。 - 内存有限:Redis 数据在内存里,别存大文件/大对象,适合存「热数据」。
- 缓存套路(最经典用法):这就是常说的 Cache Aside 模式。
查缓存 → 命中就返回 → 没命中就查数据库 → 写入缓存(带TTL) → 返回
6. 建议的下一步
- 装个图形界面看数据更直观:
brew install --cask another-redis-desktop-manager - 了解「缓存三大问题」(穿透 / 击穿 / 雪崩)——面试高频
- 了解「发布订阅」(
PUBLISH/SUBSCRIBE)——做实时消息
7. 持久化(RDB / AOF / 混合)
Redis 数据在内存里,进程一重启就没了。持久化就是把数据落到磁盘,解决「重启丢数据」。
7.1 RDB(快照)—— 定期全量备份
某个时刻把整个内存快照存成二进制文件 dump.rdb。
bash
SAVE # 手动触发,阻塞主线程(线上别用)
BGSAVE # fork 子进程后台做,推荐配置文件里可自动触发:save 900 1(900 秒内有 1 次写入就快照一次)。
- 优点:文件小、恢复快(直接加载一份快照)
- 缺点:两次快照之间改动的数据会丢
7.2 AOF(追加日志)—— 记录每条写命令
每执行一条写命令,就把它追加到 appendonly.aof。重启时把命令「重放」一遍。
刷盘策略(appendfsync):
| 策略 | 行为 | 丢数据 |
|---|---|---|
always | 每条都同步写盘 | 几乎不丢,最慢 |
everysec(默认) | 每秒写一次 | 最多丢 1 秒 |
no | 交给操作系统 | 可能丢更多 |
- 优点:丢得少、文件是可读的命令文本
- 缺点:文件比 RDB 大、恢复慢(要重放所有命令)
7.3 混合持久化(Redis 4.0+,推荐)
AOF 重写时先写一份 RDB 快照,再追加之后的增量 AOF。兼顾「RDB 恢复快 + AOF 丢得少」。
7.4 实际怎么选
conf
# redis.conf
save 900 1 # RDB 快照
appendonly yes # 开 AOF
appendfsync everysec # 每秒刷盘
aof-use-rdb-preamble yes # 混合持久化一句话:开发/测试随便,生产开 AOF(everysec)或混合模式,对数据极度敏感再考虑
always。
8. 分布式锁
场景:多个服务同时「下单减库存」「防重复提交」,要保证同一时刻只有一个拿到锁。
8.1 核心就一条命令
bash
SET lock:order:123 <唯一token> NX EX 10NX:key 不存在才设置成功(= 拿到锁);已存在返回 nil(= 没拿到)EX 10:10 秒自动过期(防持锁进程挂了导致死锁)<唯一token>:每个拿锁者生成自己的 UUID,释放锁时校验用
8.2 释放锁:必须「校验 + 原子删」
不能直接 DEL——否则 A 的锁过期了、B 拿到锁、A 回来 DEL 会把 B 的锁删掉。
要用 Lua 脚本让「判断是不是自己的 → 删除」两步原子执行:
lua
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end8.3 Python 完整示例
python
import redis, uuid, time
r = redis.Redis(decode_responses=True)
def acquire_lock(key, expire=10):
token = uuid.uuid4().hex
return token if r.set(key, token, nx=True, ex=expire) else None
def release_lock(key, token):
lua = """
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
"""
r.eval(lua, 1, key, token)
token = acquire_lock("lock:order:123")
if token:
try:
time.sleep(1) # 业务逻辑
finally:
release_lock("lock:order:123", token)
else:
print("没拿到锁")8.4 三个必踩的坑
- 必须加过期时间——否则持锁进程挂了就永久死锁
- 释放必须校验 token——防止误删别人的锁
- 过期时间要 > 业务执行时间——否则锁提前释放,别人插进来
8.5 进阶
- 锁过期了业务还没做完:用「看门狗(watch dog)」后台线程定期续期(Java 的 Redisson 内置,Python 需自己实现)
- 多节点:RedLock 在 N 个独立 Redis 实例分别拿锁,过半成功才算拿到;一般业务「单机 + 主从 + 看门狗」就够