Skip to content

Redis 入门最直接的方式就是:装好 → 命令行玩一遍 → 再上代码。下面按这个顺序走。

1. 安装 & 启动(macOS)

bash
brew install redis          # 安装
redis-server                # 前台启动(会占用当前终端)
# 或后台启动:
brew services start redis   # 开机自启的常驻方式

再开一个终端连上去:

bash
redis-cli                   # 进入交互式命令行
redis-cli ping              # 应返回 PONG

2. 先把最核心的概念玩通: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. 五种数据类型(逐个敲一遍)

类型命令典型用途
StringSET/GET/INCR缓存、计数器
HashHSET/HGET/HGETALL存一个对象(用户信息)
ListLPUSH/RPUSH/LRANGE队列、消息列表
SetSADD/SMEMBERS/SINTER去重、共同好友
Sorted SetZADD/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 redis
python
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 件事

  1. Key 命名习惯:用 : 做层级,如 user:1:nameorder:2024:list,方便管理和批量操作。
  2. 内存有限:Redis 数据在内存里,别存大文件/大对象,适合存「热数据」。
  3. 缓存套路(最经典用法):
    查缓存 → 命中就返回 → 没命中就查数据库 → 写入缓存(带TTL) → 返回
    这就是常说的 Cache Aside 模式。

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 10
  • NX: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
end

8.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 三个必踩的坑

  1. 必须加过期时间——否则持锁进程挂了就永久死锁
  2. 释放必须校验 token——防止误删别人的锁
  3. 过期时间要 > 业务执行时间——否则锁提前释放,别人插进来

8.5 进阶

  • 锁过期了业务还没做完:用「看门狗(watch dog)」后台线程定期续期(Java 的 Redisson 内置,Python 需自己实现)
  • 多节点:RedLock 在 N 个独立 Redis 实例分别拿锁,过半成功才算拿到;一般业务「单机 + 主从 + 看门狗」就够