Redis 从入门到实战:高性能原理、数据结构、事务、Lua 与排行榜

Redis 是后端开发中最常见的基础设施之一。

很多人第一次接触 Redis,会把它简单理解成“一个很快的缓存”。这个理解不能说错,但明显低估了 Redis:它不仅能缓存字符串,还提供 Hash、List、Set、Sorted Set 等丰富的数据结构,并且通过事务、原子命令、Lua 脚本等能力,可以直接解决计数器、秒杀、抢票、排行榜等高并发场景中的核心问题。

本文结合几篇 Redis 学习资料,对其中的知识重新抽取和组织,尝试回答几个真正重要的问题:

  • Redis 为什么快?
  • Redis 的核心数据结构应该怎么选?
  • Redis 的事务与传统关系型数据库事务有什么不同?
  • WATCH + MULTI 为什么能解决并发抢票问题?
  • Lua 脚本解决了什么问题?
  • 为什么排行榜几乎是 Sorted Set 的“标准答案”?
  • Redis 和 MySQL 应该如何配合,而不是互相替代?

1. Redis 是什么?

Redis 全称可以理解为 Remote Dictionary Server,本质上是一种基于 Key-Value 模型的数据存储系统。

最简单的 Redis 数据可以写成:

1
key -> value

例如:

1
2
SET name zhangfei
GET name

但 Redis 与普通 Key-Value 数据库最大的区别之一,是它的 value 并不局限于一个字符串,而是可以使用多种数据结构。

因此,更准确地说,Redis 是一个:

以内存为核心、支持丰富数据结构、提供高性能读写与原子操作能力的数据存储系统。

在实际架构中,Redis 经常和 MySQL 等关系型数据库一起使用:

1
2
3
4
5
6
7
Client
|
Application
|
+------> Redis:高频访问、缓存、计数、排行、并发控制
|
+------> MySQL:核心业务数据、长期持久化、复杂查询

Redis 擅长的是“快”和“实时”,关系型数据库擅长的是“可靠存储”和“复杂关系查询”。

两者并不是替代关系,而是互补关系。


2. Redis 为什么这么快?

资料中把 Redis 的高性能归纳为几个核心因素。

2.1 基于内存读写

传统数据库的大量性能成本来自磁盘 I/O。

而 Redis 的主要数据保存在内存中,大部分命令都直接对内存中的数据结构进行操作,因此绕开了磁盘随机 I/O 的巨大延迟。

粗略理解:

1
2
磁盘访问:慢
内存访问:快

所以 Redis 天生适合:

  • 缓存
  • Session
  • 高频计数
  • 排行榜
  • 热点数据
  • 临时状态
  • 高并发读写

当然,“数据在内存中”也意味着 Redis 的容量和成本受到内存大小约束,它通常不应该被简单当成无限容量的主数据库。

2.2 数据结构针对场景进行了专门设计

Redis 并不是只提供一个简单的 HashMap。

它为不同场景提供不同的数据结构:

1
2
3
4
5
String      -> 简单 KV、缓存、计数器
Hash -> 对象属性
List -> 队列、列表
Set -> 去重、集合运算
Sorted Set -> 排行榜、带权排序

当业务问题与数据结构高度匹配时,很多复杂逻辑可以直接由 Redis 命令完成。

例如排行榜如果放在普通关系型表中,通常需要:

1
ORDER BY score DESC

而 Redis Sorted Set 本身就在维护一个有序结构,因此“排序”不是每次查询时临时计算,而是数据结构本身提供的能力。

2.3 避免大量线程竞争和上下文切换

资料以经典 Redis 模型解释其性能:核心命令执行采用串行化思路,可以避免大量线程之间的:

  • 锁竞争
  • 上下文切换
  • 临界区协调
  • 死锁风险
  • 共享状态同步

这让 Redis 的执行路径非常直接。

需要注意的是,现代 Redis 的网络 I/O、后台任务等实现已经随着版本发展发生变化,因此不要把“Redis 只有一个线程”理解成整个 Redis 进程内部永远只有一个线程。

真正应该抓住的是:

Redis 的核心命令执行模型尽可能保持简单、可预测,并避免让多线程锁竞争成为主要瓶颈。

2.4 I/O 多路复用

Redis 可以同时面对大量客户端连接,但不需要为每个连接都创建一个独立线程。

其关键思想是 I/O 多路复用:

1
2
3
4
5
Client A ----\
Client B -----\
Client C ------> I/O Multiplexing -> Redis Event Loop
Client D -----/
Client E ----/

一个线程可以监听多个 Socket 的事件,只处理真正已经准备好的连接。

因此 Redis 能在减少线程开销的同时处理大量并发网络连接。

2.5 C 语言实现

Redis 使用 C 语言实现,运行时依赖较少,能够直接使用底层系统能力。

不过工程上不能简单得出“C 写的所以一定快”的结论。真正决定 Redis 性能的是:

内存访问 + 高效数据结构 + 简单执行模型 + I/O 多路复用 + 成熟工程实现。


3. Redis 最核心的五种数据类型

Redis 的重点不是背命令,而是建立:

业务问题 -> 数据结构

之间的映射。


4. String:最简单,也最常用

String 是 Redis 最基础的数据类型。

1
2
SET name zhangfei
GET name

除了存字符串,还经常用于数字:

1
2
3
SET stock 100
DECR stock
INCR page_view

Redis 的 INCRDECR 等操作具有原子性,因此对于单纯的计数问题,不一定需要事务。

典型场景:

  • 缓存 JSON
  • Token
  • 验证码
  • Session ID
  • 页面访问量
  • 库存计数
  • 分布式序列的一部分

例如:

1
2
SET product:1001:stock 500
DECR product:1001:stock

5. Hash:适合表示对象

Hash 的结构可以理解为:

1
key -> field -> value

例如用户:

1
2
HSET user:1 username zhangfei
HSET user:1 age 28

读取:

1
2
HGET user:1 username
HMGET user:1 username age

逻辑结构:

1
2
3
user:1
├── username -> zhangfei
└── age -> 28

Hash 比较适合:

  • 用户信息
  • 商品属性
  • 配置项
  • 状态对象

它比把整个对象序列化成 JSON 字符串更灵活,因为可以单独修改某个字段。


6. List:天然的双端队列

List 可以从左右两侧插入数据。

1
2
LPUSH heroList zhangfei guanyu liubei
RPUSH heroList dianwei lvbu

读取范围:

1
LRANGE heroList 0 4

从抽象上可以理解为:

1
LEFT <-> A <-> B <-> C <-> D <-> RIGHT

所以它适合:

  • 简单消息队列
  • 时间线
  • 最新记录
  • 双端队列

不过在现代大型消息系统中,如果真正需要消息确认、消费者组、消息重放等能力,更应该考虑 Redis Stream 或专门的 MQ,而不是只靠 List 硬凑。


7. Set:去重和集合运算

Set 是无序且元素唯一的集合。

1
SADD heroSet zhangfei guanyu liubei dianwei lvbu

删除:

1
SREM heroSet liubei

判断元素是否存在:

1
SISMEMBER heroSet zhangfei

获取所有元素:

1
SMEMBERS heroSet

Set 最重要的不是“存一堆不重复的数据”,而是集合语义。

它非常适合:

  • 标签
  • 用户关注关系
  • 去重
  • 黑名单
  • 共同好友
  • 权限集合
  • 已处理 ID 集合

典型思路:

1
2
3
4
5
6
用户 A 的关注集合
用户 B 的关注集合
|
求交集
|
共同关注

8. Sorted Set:Redis 排行榜核心

Sorted Set,也叫 ZSet,可以理解成:

1
member + score

例如:

1
2
3
ZADD heroScore 8341 zhangfei
ZADD heroScore 7107 guanyu
ZADD heroScore 6900 liubei

Redis 会按照 score 维护排序。

查看分数:

1
ZSCORE heroScore guanyu

倒序取前三名:

1
ZREVRANGE heroScore 0 2 WITHSCORES

它特别适合:

  • 游戏排行榜
  • 热度榜
  • 销量榜
  • 文章排行
  • 积分榜
  • 延迟队列
  • 按时间或权重排序的数据

从业务角度看,可以把 Sorted Set 理解成:

1
2
3
4
5
member                score
--------------------------------
user:10001 95
user:10002 88
user:10003 120

Redis 自动维护:

1
2
3
user:10003  120
user:10001 95
user:10002 88

这就是它构建实时排行榜的根本原因。


9. 其他 Redis 数据能力

除了五种经典类型,Redis 还提供过或持续扩展了更多能力,例如:

  • Bitmap
  • HyperLogLog
  • Geospatial
  • Stream

它们分别适合:

1
2
3
4
Bitmap       -> 签到、布尔状态、大量 0/1 标记
HyperLogLog -> 大规模基数估算、UV
Geospatial -> 地理位置与距离查询
Stream -> 消息流、消费者组

这也是 Redis 和单纯 Memcached 类缓存系统相比的重要优势之一:

Redis 不只是缓存值,而是在服务端直接提供数据结构能力。


10. 为什么应用访问 Redis 要使用连接池?

资料中给出了 Python 直接连接 Redis 的方式:

1
2
3
4
5
6
import redis

r = redis.Redis(
host="localhost",
port=6379
)

也给出了连接池:

1
2
3
4
5
6
7
8
pool = redis.ConnectionPool(
host="localhost",
port=6379
)

r = redis.Redis(
connection_pool=pool
)

连接池解决的问题并不只属于 Redis。

如果每一次请求都:

1
2
3
4
5
创建 TCP 连接

发送请求

关闭连接

高并发下会产生大量额外开销。

连接池的思路是:

1
2
3
4
5
6
7
 +-------------------+
| Connection Pool |
+-------------------+
/ | \
conn1 conn2 conn3
\ | /
Application

连接使用完成后不是关闭,而是归还连接池。

核心收益:

  • 减少连接创建开销
  • 减少 TCP 建连成本
  • 控制最大连接数
  • 提升连接复用率
  • 提高高并发下的稳定性

11. Redis 事务和 MySQL 事务不是一回事

关系型数据库中,我们经常强调 ACID:

1
2
3
4
A - Atomicity    原子性
C - Consistency 一致性
I - Isolation 隔离性
D - Durability 持久性

Redis 也有事务,但不要直接套用 MySQL 事务的全部语义。

Redis 的事务更接近:

把一组命令先进入队列,然后一次性按顺序执行。

核心命令:

1
2
3
4
5
MULTI     开始事务
EXEC 执行事务
DISCARD 放弃事务
WATCH 监视 Key
UNWATCH 取消监视

例如:

1
2
3
4
5
6
7
MULTI

HSET user:001 hero zhangfei
HSET user:002 hero guanyu
HSET user:003 hero liubei

EXEC

MULTI 之后,命令不会立即执行,而是进入队列:

1
2
3
4
5
6
7
8
9
MULTI
|
+-- COMMAND 1 -> QUEUED
+-- COMMAND 2 -> QUEUED
+-- COMMAND 3 -> QUEUED
|
EXEC
|
一次执行

12. Redis 事务为什么不提供传统 Rollback?

资料特别强调:

Redis 事务并不提供与关系型数据库相同的回滚机制。

这里要区分两类错误。

12.1 入队阶段就能发现的错误

例如命令本身语法错误。

这种问题可能导致整个事务无法正常执行。

12.2 真正执行时才出现的错误

例如对错误类型的 Key 使用了不匹配的命令。

这种情况下,Redis 不会像 MySQL 那样把前面已经执行成功的命令全部回滚,而是继续执行后续命令。

所以 Redis 事务的设计哲学更偏向:

1
2
3
4
简单
快速
明确
把很多错误交给开发阶段发现

而不是实现复杂的数据库级回滚系统。


13. Redis 持久化:RDB 与 AOF

虽然 Redis 以内存为中心,但仍然提供持久化能力。

13.1 RDB

RDB 可以理解为:

对某一时刻 Redis 中的数据生成快照。

大致过程:

1
2
3
4
5
Memory
|
Snapshot
|
RDB File

优点:

  • 文件紧凑
  • 适合备份
  • 恢复速度通常较快

问题:

  • 快照之间存在时间窗口
  • 宕机时可能丢失最近一段数据

13.2 AOF

AOF 的核心思想是记录写操作:

1
2
3
4
SET a 1
INCR counter
HSET user:1 age 28
...

恢复时可以重放这些写命令。

资料中提到常见同步策略:

1
2
3
always
everysec
no

其中 everysec 是性能和数据安全之间常见的折中方式。

所以 Redis 的持久化不是一个简单的“有或没有”,而是:

性能、恢复速度和可接受数据丢失窗口之间的权衡。


14. 为什么 Redis 单线程执行命令,还需要并发控制?

这是 Redis 初学者非常容易困惑的问题。

假设 Redis 一次只执行一个命令:

1
2
3
4
Client A: GET ticket
Client B: GET ticket
Client A: SET ticket 0
Client B: SET ticket 0

每条命令确实没有同时执行。

但是:

一个业务操作通常包含多条命令。

例如抢票:

1
2
3
4
1. 查询票数
2. 判断票数 > 0
3. 票数减 1
4. 保存

多个客户端的这些命令可以交叉:

1
2
3
4
Client A: GET ticket -> 1
Client B: GET ticket -> 1
Client A: SET ticket -> 0
Client B: SET ticket -> 0

于是两个人都以为自己抢到了最后一张票。

所以:

单条 Redis 命令原子,不代表由多条命令组成的业务逻辑天然原子。

这就是 Redis 仍然需要事务、原子命令和 Lua 的原因。


15. WATCH + MULTI:Redis 的乐观锁

Redis 可以通过:

1
WATCH + MULTI + EXEC

实现一种乐观锁语义。

流程:

1
2
3
4
5
6
7
8
9
10
11
WATCH ticket
|
读取 ticket
|
判断库存
|
MULTI
|
修改 ticket
|
EXEC

如果 WATCH 之后、EXEC 之前,别的客户端修改了这个 Key,那么当前事务执行失败。

可以把它抽象成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Client A
WATCH ticket
|
| ticket version = v1
|
|-------------------------\
\
Client B |
SET ticket 0 |
ticket version = v2 |
|
Client A |
EXEC ---------------------------/
|
发现已变化
|
事务取消

它本质上是一种:

先假设不会冲突,真正提交时再检查冲突。

这就是乐观锁。


16. 抢票场景的核心逻辑

假设库存只有 1:

1
SET ticket 1

两个客户端都开始:

1
WATCH ticket

客户端 2 先执行:

1
2
3
MULTI
SET ticket 0
EXEC

客户端 2 成功。

这时候客户端 1 再执行 EXEC,因为 ticket 已经发生修改,所以事务失败。

最终只会有一个客户端成功。

需要特别注意:

1
WATCH 必须发生在 MULTI 之前

不能:

1
2
MULTI
WATCH ticket

因为 WATCH 的目的就是监控事务正式提交之前 Key 是否被修改。


17. 抢票不一定必须使用事务

如果业务只是:

1
库存 -1

Redis 本身提供原子命令:

1
DECR ticket

因此很多场景可以直接利用原子操作。

例如:

1
DECR ticket

返回:

1
2
>= 0   抢票成功
< 0 库存不足,需要补偿或恢复

但真实业务通常还有:

1
2
3
4
5
6
库存
用户资格
限购
订单号
去重
活动状态

这时一个 DECR 就不够了。

于是 Lua 开始变得非常重要。


18. Lua:把多条 Redis 命令变成一个整体

Redis 支持执行 Lua 脚本。

基本命令:

1
EVAL script numkeys key [key ...] arg [arg ...]

其中:

1
2
3
KEYS[1]
KEYS[2]
...

用于访问 Key。

1
2
3
ARGV[1]
ARGV[2]
...

用于访问脚本参数。

例如:

1
EVAL "return {ARGV[1], ARGV[2]}" 0 hello redis

Lua 最大的价值并不是“Redis 里还能写一种语言”。

真正重要的是:

可以把一组 Redis 操作封装成一个在服务端执行的整体。

这样有两个核心收益。

18.1 减少网络往返

原本:

1
2
3
4
5
6
7
8
Client -> Redis: GET
Client <- Redis

Client -> Redis: GET
Client <- Redis

Client -> Redis: SET
Client <- Redis

Lua:

1
2
3
Client -> Redis: EVAL script
Redis 本地执行多个操作
Client <- Redis: result

多次网络 RTT 变成一次。

18.2 多步操作不被其他命令插入

Lua 脚本执行时可以把多条 Redis 操作组合在一起完成。

这特别适合:

  • 秒杀
  • 库存扣减
  • 限流
  • 分布式锁释放
  • 多 Key 状态检查
  • 原子计数
  • 排行榜批量操作

例如伪代码:

1
2
3
4
5
6
7
8
9
10
local stock = tonumber(redis.call('GET', KEYS[1]))

if stock <= 0 then
return 0
end

redis.call('DECR', KEYS[1])
redis.call('SADD', KEYS[2], ARGV[1])

return 1

比客户端写:

1
GET -> 判断 -> DECR -> SADD

更加适合要求原子语义的高并发场景。


19. 为什么排行榜特别适合 Redis?

假设现在有 10 万玩家:

1
2
3
user_id
score
create_time

需求包括:

  • 查询 Top N
  • 查询我的排名
  • 查询我的分数
  • 修改积分
  • 更新排名
  • 查询我前后几名
  • 玩家加入排行榜
  • 玩家退出排行榜

如果全部使用 MySQL,最直观的查询是:

1
2
3
SELECT user_id, score
FROM user_score
ORDER BY score DESC;

MySQL 当然可以完成。

但是问题在于:

排行榜是一个高频动态排序问题,而关系型数据库的强项主要是持久化、关系和查询,不是把一个不断变化的大集合一直维护成实时排名。

而 Sorted Set 本身就为这个问题而生。


20. 使用 Sorted Set 构建排行榜

创建:

1
2
3
ZADD user_score 100 user:10001
ZADD user_score 90 user:10002
ZADD user_score 150 user:10003

结果逻辑上为:

1
2
3
4
5
Rank    Member       Score
--------------------------
1 user:10003 150
2 user:10001 100
3 user:10002 90

查询全部排行榜

1
ZREVRANGE user_score 0 -1 WITHSCORES

查询 Top 10

1
ZREVRANGE user_score 0 9 WITHSCORES

查询某玩家分数

1
ZSCORE user_score user:10001

查询某玩家排名

1
ZREVRANK user_score user:10001

注意排名从 0 开始。

如果业务显示排名从 1 开始:

1
业务排名 = Redis Rank + 1

增加积分

1
ZINCRBY user_score 10 user:10001

分数变化之后,Redis 会同步维护其有序位置。

查询某玩家前后 5 名

先查询排名:

1
ZREVRANK user_score user:10001

假设结果是:

1
100

则:

1
ZREVRANGE user_score 95 105 WITHSCORES

删除玩家

1
ZREM user_score user:10001

新增玩家

1
ZADD user_score 80 user:10004

这套 API 几乎完整覆盖了实时排行榜。


21. 并列排行榜与严格排行榜

排行榜还有一个容易被忽略的问题:

两个人分数相同怎么办?

21.1 并列排行榜

例如:

1
2
3
4
5
Rank  User   Score
1 A 100
2 B 90
2 C 90
4 D 80

相同分数拥有相同业务排名。

这种业务规则通常需要应用层根据相同 score 进一步处理展示排名。

21.2 严格排行榜

严格排行榜要求:

1
任何两个人最终都必须有先后顺序

例如:

1
2
score DESC
create_time ASC

即:

分数相同,注册更早的用户排名靠前。

MySQL 中非常直观:

1
ORDER BY score DESC, create_time ASC

Redis Sorted Set 只有一个 score,因此资料采用了将多个排序维度编码进一个分数的办法:

1
最终 score = 业务得分 + 时间信息

思路本质上是:

1
2
3
4
5
主排序字段 + 次排序字段

映射为一个可比较数值

ZSet Score

不过生产环境中需要非常谨慎地设计这种编码,尤其要考虑:

  • 浮点数精度
  • 时间范围
  • 主排序权重
  • score 的安全整数范围
  • 是否可能发生碰撞

不要仅仅为了“省一个字段”而把一个难以维护的浮点编码方案直接搬到生产环境。


22. Redis 排行榜与 MySQL 排行榜怎么选?

简单来说:

MySQL 更适合

1
2
3
4
5
6
完整玩家资料
比赛记录
历史战绩
订单数据
长期存档
复杂关联查询

Redis 更适合

1
2
3
4
5
6
实时积分
Top N
我的排名
热榜
在线状态
实时变化的排序

一个常见组合:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
                     +----------------+
| MySQL |
| 玩家完整数据 |
| 历史战绩 |
+----------------+
^
|
Application ----------------+
|
v
+----------------+
| Redis |
| 实时排行榜 |
| 热点玩家信息 |
+----------------+

例如排行榜页面只需要:

1
2
3
4
5
userId
nickname
avatar
score
rank

这些高频字段可以直接在 Redis 中准备好。

用户点击某个玩家进入详情页之后,再查询 MySQL 中更完整的数据。


23. Redis 中几种并发方案如何选择?

结合事务、原子命令和 Lua,可以形成一个很实用的判断方式。

场景一:一个 Key 的简单加减

优先:

1
2
3
4
INCR
DECR
INCRBY
DECRBY

例如:

1
DECR stock

场景二:读 -> 判断 -> 写

可以考虑:

1
WATCH + MULTI + EXEC

它属于乐观并发控制。

适合冲突概率不是特别高、逻辑比较简单的场景。

场景三:多个 Redis 操作必须作为整体

优先考虑:

1
Lua Script

尤其是高并发核心路径。

场景四:业务一致性跨 Redis 与 MySQL

这时已经不是 Redis 单机原子性能够完整解决的问题,需要从系统层面考虑:

  • 消息队列
  • Outbox
  • 最终一致性
  • 幂等
  • 状态机
  • 补偿机制

不要试图用一个 Redis 事务解决整个分布式系统的一致性。


24. 从抢票案例真正应该学到什么?

抢票案例表面上是在学:

1
2
3
WATCH
MULTI
EXEC

真正应该学到的是:

并发问题通常发生在“读 -> 判断 -> 写”之间。

只要代码里出现:

1
2
3
if (stock > 0) {
stock--;
}

就应该立即警觉:

1
2
3
“stock > 0” 这个判断成立以后,
真正执行 stock-- 之前,
其他请求有没有可能修改 stock?

这也是 CAS、乐观锁、版本号、数据库 UPDATE ... WHERE version = ?、Redis WATCH 等机制背后共同的思想。


25. 从排行榜案例真正应该学到什么?

排行榜案例最重要的不是记住:

1
ZREVRANK

而是理解:

数据结构选对之后,很多业务问题会从“算法问题”变成“命令调用”。

如果使用普通数据库表思考排行榜,首先想到的是:

1
2
3
4
5
查询
排序
计算排名
分页
更新后重新排名

如果用 Sorted Set 思考:

1
2
3
4
ZADD
ZINCRBY
ZREVRANK
ZREVRANGE

问题一下子简单很多。

所以使用 Redis 的核心能力之一,就是:

用数据结构直接表达业务语义。


26. Redis 的工程使用原则

最后把前面的内容浓缩成几条工程经验。

26.1 Redis 不只是缓存

Redis 更准确的定位应该是:

1
高性能内存数据结构服务

缓存只是它最常见的用途之一。

26.2 不要把所有数据都塞进 Redis

Redis 内存昂贵。

应该优先存:

  • 热数据
  • 高频数据
  • 临时数据
  • 实时状态
  • 可以重建的数据

26.3 多条命令之间存在竞态条件

即使单条命令原子,也不能自动保证:

1
2
3
GET
判断
SET

整体原子。

26.4 优先使用 Redis 原子命令

如果一个命令能解决:

1
2
3
4
INCR
DECR
SET NX
ZINCRBY

就不要先上复杂事务。

26.5 多步原子逻辑优先考虑 Lua

客户端多次请求不仅有并发窗口,还有网络 RTT。

Lua 往往能够同时解决:

1
2
3
原子性
+
网络往返

26.6 Redis 与 MySQL 各自做擅长的事情

不要纠结:

1
Redis 还是 MySQL?

更好的问题是:

1
这部分数据的访问模式是什么?

如果核心需求是:

1
实时排行、高频计数、缓存、临时状态

Redis 很合适。

如果核心需求是:

1
复杂关系、长期持久化、事务、历史记录

MySQL 更合适。


27. 总结

把 Redis 从入门到实战串起来,可以得到这样一条知识主线:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Redis
|
+-- 为什么快
| |
| +-- 内存
| +-- 高效数据结构
| +-- 简单执行模型
| +-- I/O 多路复用
|
+-- 数据结构
| |
| +-- String
| +-- Hash
| +-- List
| +-- Set
| +-- Sorted Set
|
+-- 并发
| |
| +-- 原子命令
| +-- WATCH
| +-- MULTI / EXEC
| +-- 乐观锁
|
+-- Lua
| |
| +-- 多命令原子执行
| +-- 减少网络 RTT
|
+-- 典型场景
|
+-- 抢票 / 秒杀
+-- 计数器
+-- 排行榜
+-- 实时状态

真正掌握 Redis,不应该停留在:

1
2
SET
GET

而应该逐渐建立三个层次的理解:

第一层是命令

1
这个命令怎么用?

第二层是数据结构

1
这个业务应该选什么结构?

第三层是并发和系统设计

1
2
多客户端同时操作时,正确性还能不能保证?
Redis 和数据库之间的数据应该如何协作?

当你开始从第三层思考 Redis,它就不再只是一个“缓存工具”,而会真正成为系统架构中的高性能数据组件。


Redis 从入门到实战:高性能原理、数据结构、事务、Lua 与排行榜
https://allendericdalexander.github.io/2026/08/11/db/53sql/07redis-from-basics-to-practice/
作者
AtLuoFu
发布于
2026年8月11日
许可协议