Mobile wallpaper 1Mobile wallpaper 2Mobile wallpaper 3Mobile wallpaper 4
2131 字
11 分钟
Redis学习系列 | Redis 不只是缓存——一个数据结构服务器的世界观

我以为 Redis 就是个缓存#

刚接触 Redis 的时候,我对它的理解就一句话:比 MySQL 快的缓存

这其实不怪我。你在网上搜 Redis,十篇文章有八篇的标题都是”用 Redis 做分布式缓存”、“Redis 缓存穿透解决方案”、“Spring Boot 集成 Redis 缓存”。看多了,脑子里自然就形成了等式:Redis = 缓存 = 给数据库挡枪的。

后来有一天,我在看一个项目源码的时候,发现他们把用户的好友关系、实时积分排行、消息队列全塞在同一个 Redis 里。我当时心想:这不是瞎搞吗,缓存不是应该就存点临时数据吗?

查了一圈文档才反应过来——我对 Redis 的认知从一开始就偏了。

Redis 的官方自我介绍是:“An open source, in-memory data structure store”(开源、基于内存的数据结构存储)。注意最后三个词:data structure store,数据结构存储。它从来没说自己只是个缓存。

书架和数据库有什么不一样?#

让我换个方式解释。

想象你家里有几百本书。找一本书有两种方法:

方法一:查目录卡。 你翻到”计算机”那页,找到《深入理解计算机系统》的编号 20231001,然后去对应的书架上按编号找。这个过程很精确,但你要翻目录、记编号、走到书架、核对编号——每一步都要时间。

方法二:把常用书摆在手边。 桌面上有个小书架,放着最近常翻的二三十本。你要哪本,伸手就拿,不用查目录,不用记编号,不用来回走。

方法一就是 SQL 数据库。方法二就是 Redis。

但这个故事最关键的不是”拿书快”,而是——桌面上那二十本书你可以按自己的习惯随便摆放。你可以把技术书摞成一叠(List),可以给书按标签分类(Set),可以按阅读次数排个序(Sorted Set)。而目录卡做不到这些——你只能查编号,然后按编号找书。

这个区别就是 Redis 和缓存的真正界限。缓存只管”把数据塞内存里”,Redis 关心的是”用什么样的结构来组织这些数据”。

同一个需求,SQL 和 Redis 长什么样#

说个具体的。假设你要存一个用户信息:名字、积分、最近登录时间。

SQL 的思路:

CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50),
score INT,
last_login DATETIME
);
INSERT INTO users (name, score, last_login) VALUES ('zhangsan', 1200, NOW());
SELECT * FROM users WHERE id = 1;

这是”先存再想怎么查”:你把数据扔进表里,结构是固定的(二维表),以后想查什么就写什么 SQL。表结构跟你的业务模型是两层皮,中间靠 ORM 翻译。

Redis 的思路:

HMSET user:1 name "zhangsan" score 1200 last_login "2025-05-14"
HGET user:1 score → "1200"
HINCRBY user:1 score 10 → 1210(原子递增)

这是”想好怎么查再存”:你用 Hash 结构直接映射你的业务对象,查一个字段就是一次操作,修改积分就是原子递增——不用 SELECT 出来、+10、再 UPDATE 回去。

这个区别在实际开发里意味着很多:

场景SQL 做法Redis Hash 做法
用户积分 +10SELECT → 加 → UPDATE,两步HINCRBY 一条命令
并发积分更新需要事务或乐观锁原子操作,天然安全
查用户单个字段SELECT name FROM users WHERE id=1HGET user:1 name

当然,Redis 不是替代 SQL 的。后面我会聊到什么时候用 Redis、什么时候用 SQL、什么时候两个一起用。

单线程怎么比多线程还快?#

说到 Redis 的性能,几乎每个面试都会问:为什么 Redis 单线程这么快?

我第一次看到这个问题的时候很困惑——单线程不是应该更慢吗?CPU 那么多核,用满不好吗?

答案是:CPU 从来不是 Redis 的瓶颈。

真正耗时间的地方是网络 I/O。数据从网卡走到内核、从内核走到用户程序,这个过程是毫秒级的。而 Redis 在内存里执行一条命令是微秒甚至纳秒级。换句话说,你点一桌子菜,等菜上来的时间比吃饭的时间长一百倍——你雇十个厨子帮忙吃,没有任何意义。

所以 Redis 选了这么一条路:

  1. 所有命令在一个线程里串行执行——省掉了锁、线程切换、竞态条件这些开销。一个操作要么做了,要么没做,没有”做了一半”的情况。
  2. 用 epoll 同时监听几千个连接——哪个连接有数据来了就处理谁,没数据的连接不浪费 CPU。这叫 I/O 多路复用。

这个模型像什么?像一个人同时跟几百个人下棋。他不是同时走每一步——他扫一眼,谁走了他就回应谁。因为他落子的速度(CPU 计算)远快于对方想棋的时间(网络 I/O),所以一个人处理几百盘棋完全够用。加更多”下棋手”不会让整盘棋变快,反而会把人撞到一起去。

到底什么时候用到了多线程?

Redis 6.0 之后引入了多线程,但只用在了网络数据的读写和协议解析上。命令执行本身还是单线程、串行的。简单说就是:拆信封可以多人拆,但看信的内容还是一个人看。这么做在 4 核机器上实测能把并发吞吐量提高接近一倍,而且不用加锁——因为内存操作仍然是串行的。

五个家伙的速写画像#

Redis 有五种数据结构,名字你可能都见过。在深入之前,先快速扫一遍它们各自长什么样。

String,但不是你以为的 String。它不只是一个字符串——它可以存数字来做计数器(INCR),可以存 JSON 来做缓存,甚至可以按位操作(位图签到)。用心的 Redis 使用者能把 String 玩出花。

Hash,就是字典。键-字段-值三层结构,适合存对象。跟把 JSON 序列化成 String 存起来相比,Hash 可以单独读写某个字段,不用整出整进。

List,像个双向队列。左进右出就是队列,同一端进出就是栈。BLPOP 可以让消费者在没有数据时阻塞等,这就是一个轻量级消息队列。

Set,无序不重复的集合。两个 Set 可以做交集(共同好友)、并集、差集。天然适合做标签、社交关系。

Sorted Set,跟 Set 的区别是每个元素带一个叫 score 的权重值,按 score 自动排序。排行榜、延迟队列、带优先级的任务系统,都是它的主场。

每种结构天然匹配了一类需求。学 Redis 到后面你会发现,背命令不如练直觉——看到一个需求,脑子里自动弹出”这个用 ZSet 就行了”。后面的文章,我一种一种掰开揉碎讲。

下一篇:Redis学习系列 | String 比你想象能打。

一个老生常谈但重要的问题:Redis 到底能替代什么?#

很多人刚上手 Redis 时会有一个危险的倾向——什么数据都往 Redis 里塞,因为快嘛。

简单说:Redis 替代不了 MySQL、PostgreSQL 这类关系型数据库。 它处理不了复杂的关系查询(JOIN、子查询、聚合报表)。内存贵,几 TB 的数据全放 Redis 不现实。

Redis 真正擅长的是:

  • 热点数据快速读取(你不想每次都打数据库)
  • 需要原子操作的场景(计数、排行、队列)
  • 有结构需求的临时数据(Session、验证码、限流计数)
  • 写入速度优先的场景(秒杀扣库存、日志缓冲)

一句话总结:别把 Redis 当万能法宝,把它当一个拥有多种数据结构的、极快的内存工具箱。在合适的场景掏出合适的工具——这个系列的目的就是帮你建立起这种判断力。


这是 Redis 学习系列的第 1 篇。下一篇钻进最基础也最容易被低估的 String 类型——计数器、分布式锁、位图签到,一个都不落下。

Redis学习系列 | Redis 不只是缓存——一个数据结构服务器的世界观
https://qiandaos.top/posts/redis-learning-series/1-data-structure-server/
作者
千岛寒流
发布于
2025-05-03
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

封面
Sample Song
Sample Artist
封面
Sample Song
Sample Artist
0:00 / 0:00