Redis 入门第一课:全局命令、内部编码与单线程模型

文章目录

  • [Redis 预备知识:全局命令、内部编码与单线程架构详解](#Redis 预备知识:全局命令、内部编码与单线程架构详解)

Redis 预备知识:全局命令、内部编码与单线程架构详解

引言

假设你刚刚安装好 Redis,打开 redis-cli,面对黑底白字的命令行界面,你可能会感到有些茫然------Redis 有上百条命令,五大数据结构,该从哪里开始学起?

如果一上来就硬记每种数据结构的专用命令,很快就会感到混乱和挫败。因为你会发现:不同数据结构的命令之间似乎毫无关联,背了后面忘了前面。

但其实,Redis 的设计非常精巧,所有命令背后都遵循着共同的规律。 一旦你先掌握了这些规律,再学具体命令时就会有一种"原来如此"的顿悟感。

这就是本章 2.1 节「预备知识」的价值所在。它不会教你操作具体的数据类型,而是帮你搭建一个理解 Redis 的底层思维框架。这个框架由三块基石构成:

  1. 全局命令------操作"键"的通用指令,不管你存的是什么类型的数据,这些命令都能用
  2. 数据结构与内部编码------Redis 对外展示"五种数据类型",但内部却有"多种编码实现",理解这种双重身份是成为 Redis 高手的必经之路
  3. 单线程架构------Redis 为什么用单线程?单线程为什么还能这么快?理解这一点,你写出的 Redis 代码才能高效且安全

读完本章,你将不再畏惧 Redis 那上百条命令------因为你已经掌握了它们共同的设计哲学。


一、基本全局命令:打开 Redis 的万能钥匙

💡 核心概念

Redis 的数据是键值对(key-value)形式存储的。五种数据结构定义的是 "值" 的类型,而全局命令操作的是 "键" 本身------无论值是什么类型,这些命令都有效。

在正式学习五种数据结构各自的专属命令之前,我们需要先认识六个操作"键"的通用命令。它们就像一把万能钥匙,无论 Redis 里存的是什么类型的数据,你都可以用它们来查找、检查、删除和管理。

1.1 KEYS ------ 按模式查找键

概念

KEYS 命令用于在 Redis 中搜索匹配指定模式的键名 。你可以把它想象成文件系统中的 ls *.txt 或数据库中的 SELECT ... WHERE name LIKE '%pattern%'

通配符详解

Redis 的 KEYS 命令支持以下通配符模式,这些模式与 Linux Shell 中的 glob 风格非常相似:

通配符 含义 匹配示例
? 匹配任意一个字符 h?llo 匹配 hellohallohxllo
* 匹配任意多个字符(包括零个) h*llo 匹配 hlloheeeello
[abc] 匹配括号内的任一个字符 h[ae]llo 匹配 hellohallo,不匹配 hillo
[^abc] 匹配不在括号内的任一个字符 h[^e]llo 匹配 hallohbllo,不匹配 hello
[a-b] 匹配字符范围内的任一个字符 h[a-b]llo 匹配 hallohbllo
命令详解
bash 复制代码
KEYS pattern
  • 命令版本:1.0.0 起可用
  • 时间复杂度:O(N),N 是数据库中键的总数
  • 返回值:匹配 pattern 的所有键的列表
动手示例

我们先往 Redis 中存入几条数据,然后用 KEYS 来查找:

bash 复制代码
# 第一步:存入三条数据
redis> MSET firstname Jack lastname Stuntman age 35
"OK"

# 第二步:查找名字中包含 "name" 的键
redis> KEYS *name*
1) "firstname"
2) "lastname"

# 第三步:查找恰好三个字符的键(两个 ? 加已知字符)
redis> KEYS a??
1) "age"

# 第四步:查看当前数据库中所有的键
redis> KEYS *
1) "age"
2) "firstname"
3) "lastname"

⚠️ 重要警告:KEYS 命令的生产环境风险

KEYS 命令会一次性遍历整个数据库中的所有键 。当数据库中只有几十上百个键时,它瞬间完成,毫无问题。但当生产环境中存有数百万甚至更多键时,执行 KEYS * 会让 Redis 阻塞很长时间------在这个期间,所有其他客户端的请求都会被卡住,就像银行里只有一个窗口,前面的客户办了一小时业务,后面所有人都得干等。

在生产环境中,应该使用 SCAN 命令 替代 KEYSSCAN 采用渐进式遍历 的方式,每次只返回一小批键,不会阻塞 Redis 的正常服务。我们会在后续的键管理章节详细讲解 SCAN


1.2 EXISTS ------ 判断键是否存在

概念

EXISTS 命令用于检查一个或多个键是否存在于数据库中 。可以一次性传入多个键名,返回值是实际存在的键的个数

命令详解
bash 复制代码
EXISTS key [key ...]
  • 命令版本:1.0.0 起可用
  • 时间复杂度:O(1)(检查单个键),O(N)(N 是传入的键个数)
  • 返回值:存在的键的数量(整数)
动手示例
bash 复制代码
# 准备数据:存入两个键
redis> SET key1 "Hello"
"OK"

redis> SET key2 "World"
"OK"

# 检查单个键是否存在
redis> EXISTS key1
(integer) 1        # key1 存在,返回 1

redis> EXISTS nosuchkey
(integer) 0        # nosuchkey 不存在,返回 0

# 一次性检查多个键:key1 和 key2 存在,nosuchkey 不存在
redis> EXISTS key1 key2 nosuchkey
(integer) 2        # 只有 2 个存在

💡 使用技巧

EXISTS 非常适合在设置缓存前进行判断:先检查缓存是否命中,如果不存在再去数据库查询。它能一次性检查多个键,比分别执行多次 EXISTS 单键查询更高效。


1.3 DEL ------ 删除键

概念

DEL 命令用于删除指定的一个或多个键 。与 EXISTS 一样,它支持批量操作,返回值是实际被删除的键的个数

命令详解
bash 复制代码
DEL key [key ...]
  • 命令版本:1.0.0 起可用
  • 时间复杂度:O(1)(删除单个键),O(N)(N 是删除的键个数)
  • 返回值:被成功删除的键的数量
动手示例
bash 复制代码
# 准备数据
redis> SET key1 "Hello"
"OK"

redis> SET key2 "World"
"OK"

# 删除三个键,但 key3 实际上不存在
redis> DEL key1 key2 key3
(integer) 2        # 实际只删除了 key1 和 key2

# 验证删除结果
redis> EXISTS key1
(integer) 0        # key1 已经被删除了

📌 关键提示

DEL 命令在删除大键(如包含数百万元素的列表)时可能会阻塞 Redis。从 Redis 4.0 开始,推荐使用 UNLINK 命令来异步删除大键------UNLINK 会先在键空间中取消链接,然后将实际的内存回收工作交给后台线程处理,不会阻塞主线程。


1.4 EXPIRE ------ 给键设置"保质期"

概念

EXPIRE 命令用于给指定的键设置一个过期时间 (TTL,Time To Live),单位是。时间一到,Redis 会自动删除这个键。

你可以把它理解为给食物贴上"保质期标签"------在保质期内可以随时取用,过期后自动丢弃。

命令详解
bash 复制代码
EXPIRE key seconds
  • 命令版本:1.0.0 起可用
  • 时间复杂度:O(1)
  • 返回值1 表示设置成功,0 表示设置失败(通常是因为键不存在)
动手示例
bash 复制代码
# 存入一个键
redis> SET mykey "Hello"
"OK"

# 设置 10 秒后过期
redis> EXPIRE mykey 10
(integer) 1        # 设置成功

# 立即查看剩余时间
redis> TTL mykey
(integer) 10       # 还剩 10 秒

# 等待几秒后再查看
redis> TTL mykey
(integer) 7        # 还剩 7 秒
键的过期机制全景图

让我们用一个时间轴来完整理解键的生命周期:

复制代码
时间轴上的键生命周期:

  SET key value          EXPIRE key n             n 秒后
      │                       │                      │
      ▼                       ▼                      ▼
  ┌────────┐            ┌────────────┐        ┌────────────┐
  │ key 被  │  ──────▶  │ key 处于    │ ────▶ │ key 被     │
  │ 创建    │           │ "保鲜期"    │        │ Redis 淘汰 │
  └────────┘            └────────────┘        └────────────┘
                               │
                               │ GET key
                               ▼
                         ┌──────────┐
                         │ 返回 value │  ← 期内可以正常访问
                         └──────────┘

� 毫秒级过期控制

Redis 还提供了毫秒精度的过期命令:

  • PEXPIRE key milliseconds ------ 以毫秒为单位设置过期时间
  • PTTL key ------ 以毫秒为单位查看剩余过期时间

当你需要更精细的过期控制时(比如设置 500 毫秒后过期),可以使用这些命令。


1.5 TTL ------ 查看键还剩多少"寿命"

概念

TTL 命令用于查看指定键的剩余过期时间 ,单位是

命令详解
bash 复制代码
TTL key
  • 命令版本:1.0.0 起可用
  • 时间复杂度:O(1)
  • 返回值
    • 正整数:剩余的过期秒数
    • -1 :键存在,但没有设置过期时间(永不过期)
    • -2 :键不存在(可能已被删除或已过期被淘汰)
动手示例
bash 复制代码
# 场景一:键存在且有过期时间
redis> SET mykey "Hello"
"OK"
redis> EXPIRE mykey 10
(integer) 1
redis> TTL mykey
(integer) 10       # 还剩 10 秒

# 场景二:键存在但没有设置过期时间
redis> SET permanent "forever"
"OK"
redis> TTL permanent
(integer) -1       # -1 表示永不过期

# 场景三:键不存在
redis> TTL nonexist
(integer) -2       # -2 表示键不存在

TTL 的三种返回值是初学者最容易混淆的地方,建议牢记:

  • 正数 = 还有多少秒过期
  • -1 = 永久有效
  • -2 = 键已经没了

1.6 TYPE ------ 查看键里存的是什么类型

概念

TYPE 命令用于返回指定键的值所对应的数据类型。这是你在不确定某个键中存了什么数据时最常用的诊断命令。

命令详解
bash 复制代码
TYPE key
  • 命令版本:1.0.0 起可用
  • 时间复杂度:O(1)
  • 返回值nonestringlistsetzsethashstream 之一
动手示例
bash 复制代码
# 分别存入三种不同类型的数据
redis> SET key1 "value"
"OK"
redis> LPUSH key2 "value"
(integer) 1
redis> SADD key3 "value"
(integer) 1

# 查看各自的类型
redis> TYPE key1
"string"           # key1 是字符串类型

redis> TYPE key2
"list"             # key2 是列表类型(因为用了 LPUSH 存入)

redis> TYPE key3
"set"              # key3 是集合类型(因为用了 SADD 存入)

redis> TYPE nokey
"none"             # 不存在的键,返回 none

💡 实用场景

当你接手一个不熟悉的 Redis 实例时,先用 KEYS * 看看有哪些键,再用 TYPE 逐个了解它们的数据类型------这是快速摸清数据结构的最佳实践。


1.7 全局命令小结

命令 作用 时间复杂度 注意事项
KEYS pattern 按模式查找键 O(N) 生产环境慎用,用 SCAN 替代
EXISTS key... 判断键是否存在 O(N) 支持批量检查
DEL key... 删除键 O(N) 大键用 UNLINK 替代
EXPIRE key s 设置秒级过期 O(1) 毫秒级用 PEXPIRE
TTL key 查看剩余时间 O(1) -1=永久,-2=不存在
TYPE key 查看数据类型 O(1) 不存在的键返回 none

这六个命令是所有 Redis 操作的起点。无论你接下来学习哪种数据结构,操作键的增删查改都离不开它们。


二、数据结构与内部编码:Redis 的"双重身份"

💡 核心概念

Redis 对外展示五种数据结构(string、list、hash、set、zset),但每种数据结构背后都有多种底层编码实现。就像一辆汽车对外展示的是"前进、后退、转弯"的操作接口,但发动机内部可能是四缸或六缸------对司机来说操作方式不变,但性能表现不同。

2.1 Redis 的五种对外数据结构

当你使用 TYPE 命令查看一个键时,返回的就是它的对外数据结构类型

复制代码
Redis 的五种数据类型:

  string(字符串)     ──  "Hello World"、"103"、二进制数据
  hash(哈希)         ──  {name: "Jack", age: 19}
  list(列表)         ──  [a, b, c, d]
  set(集合)          ──  {苹果, 香蕉, 葡萄}
  zset(有序集合)     ──  {关羽: 99.0, 张飞: 93.0, 刘备: 87.2}

这五种类型就像五个不同形状的容器,你根据数据的特征选择合适的容器来存放。

2.2 内部编码:隐藏在"类型"背后的秘密

然而,当你用 TYPE 看到 string 时,Redis 内部可能用了 rawintembstr 三种不同的方式来存储它。具体用哪种,取决于数据的内容和大小。

数据结构与内部编码的完整对应关系
对外数据结构 内部编码 适用场景
string raw 长度较长的字符串(> 44 字节)
string int 整数值(可以直接做加减运算)
string embstr 短字符串(≤ 44 字节),内存分配更高效
hash hashtable 字段较多时,标准的哈希表实现
hash ziplist 字段较少时,紧凑的压缩列表,节省内存
list linkedlist 元素较多时,标准的双向链表
list ziplist / quicklist 元素较少时用压缩列表;Redis 3.2 后统一用 quicklist
set hashtable 元素为字符串时
set intset 元素全部为整数且数量较少时
zset skiplist 元素较多时,跳表 + 哈希表组合
zset ziplist 元素较少时,紧凑存储

📌 观察要点

你会发现 ziplist(压缩列表)同时出现在 hash、list、zset 的内部编码中!这说明 Redis 有一个通用的紧凑存储结构,当数据量较小时,多种数据类型都会优先用它来节省内存。

动手查看内部编码

使用 OBJECT ENCODING 命令可以查看一个键当前使用的内部编码:

bash 复制代码
# 存入一个短字符串
127.0.0.1:6379> SET hello world
OK

# 存入一个列表
127.0.0.1:6379> LPUSH mylist a b c
(integer) 3

# 查看各自的内部编码
127.0.0.1:6379> OBJECT ENCODING hello
"embstr"           # 短字符串使用 embstr 编码

127.0.0.1:6379> OBJECT ENCODING mylist
"quicklist"        # 列表使用 quicklist 编码(Redis 5.0+)

你会发现,同样是"字符串类型",内部编码却不同;同样是"列表类型",在你的 Redis 版本下可能显示 quicklist 而不是 ziplistlinkedlist。这就是 Redis 版本演进带来的内部优化。

2.3 这种双重身份设计有什么好处?

很多初学者会问:既然对外只有五种类型,为什么内部要搞这么多种编码?直接每个类型用一套固定实现不好吗?

好处一:内部优化对用户完全透明

这是最重要的设计优势。想象一下:Redis 3.2 版本推出了 quicklist,它结合了 ziplist(省内存)和 linkedlist(操作快)两者的优势。如果内部编码和外部接口是绑定的,那么这次优化就必须修改 LPUSHLRANGE 等命令的行为------所有使用列表的应用都需要改代码。

但因为 Redis 采用了"内外分离"的设计,这个升级对用户来说完全无感知 。你依然用 LPUSH 存数据,用 LRANGE 读数据,只是底层变快、变省内存了。

好处二:不同场景自动适配最优方案

Redis 会根据数据的大小和内容自动选择 最合适的内部编码,并在数据变化时自动切换

复制代码
数据量增长时的自动编码切换:

  少量数据                    大量数据
  ┌──────────┐              ┌──────────┐
  │ ziplist  │  ──阈值──▶  │ hashtable│
  │ (省内存) │              │ (高性能) │
  └──────────┘              └──────────┘

  少量整数元素                大量/含字符串
  ┌──────────┐              ┌──────────┐
  │ intset   │  ──阈值──▶  │ hashtable│
  │ (紧凑)   │              │ (通用)   │
  └──────────┘              └──────────┘

举个例子:当你往一个集合中添加元素时,如果元素全是整数且数量不多,Redis 会用 intset 编码来紧凑存储;一旦你往里面加了一个字符串元素,或者元素数量超过了阈值,Redis 会自动切换到 hashtable 编码。这一切对用户都是透明的。

🔧 最佳实践

虽然内部编码是自动切换的,但了解它的存在能帮助你做出更好的设计决策。例如:

  • 如果你知道某个哈希表只会存很少的字段,可以放心使用,Redis 会用 ziplist 高效存储
  • 如果你要存海量数据,需要关注内存使用,因为 hashtableskiplist 的内存开销比 ziplist 大得多

三、单线程架构:Redis 高性能的核心秘密

💡 核心概念

Redis 使用单线程模型来执行所有命令。这意味着在任何时刻,Redis 只会执行一个命令,不会有两个命令同时运行。这不是 Redis 的设计缺陷------恰恰相反,这是它高性能的关键设计之一。

3.1 什么是单线程模型?------ 一个银行柜台的比喻

我们先来做一个简单实验。假设你同时打开了三个 redis-cli 窗口,分别执行以下命令:

bash 复制代码
# 客户端 1:设置一个字符串键值对
127.0.0.1:6379> SET hello world

# 客户端 2:对 counter 做自增操作
127.0.0.1:6379> INCR counter

# 客户端 3:也对 counter 做自增操作
127.0.0.1:6379> INCR counter
宏观视角:三个客户端"同时"在工作

从你的角度看,三个窗口似乎是同时在向 Redis 发请求------就像三个顾客同时走进了银行。

复制代码
宏观视角:三客户端同时请求 Redis

    客户端 1 ──SET hello world──▶
    客户端 2 ──INCR counter─────▶  Redis 服务端
    客户端 3 ──INCR counter─────▶
微观视角:命令按到达顺序排队执行

但在 Redis 内部,情况却不一样。命令到达 Redis 的时间实际上是有先后次序的(虽然这个间隔非常短,比如毫秒级):

复制代码
微观视角:命令到达时间微微错开

  时间轴 ───────────────────────────────────────────▶
           │              │              │
       客户端 A       客户端 B       客户端 C
       (先到达)       (随后到)       (最后到)

Redis 内部就像只有一个服务窗口的银行柜台:

复制代码
Redis 内部单线程模型:

  ┌─────────────────────────────────────┐
  │            Redis 服务端              │
  │                                     │
  │  排队等候的命令队列:                 │
  │  ┌──────┐ ┌──────┐ ┌──────┐        │
  │  │命令 C│→│命令 B│→│命令 A│        │
  │  └──────┘ └──────┘ └──────┘        │
  │                    ↓                │
  │           ┌──────────────┐          │
  │           │  唯一执行窗口 │          │
  │           │  每次只执行   │          │
  │           │  一个命令     │          │
  │           └──────────────┘          │
  └─────────────────────────────────────┘

所以,两条 INCR counter 命令不会同时执行 。无论它们的到达顺序如何,第一条 INCR 执行完后 counter 变成 1,第二条执行完后变成 2------结果永远是确定的,不会出现并发导致的数据错乱。

📌 这就是单线程模型的核心价值:顺序执行天然保证了原子性。 你不需要加锁、不需要考虑竞态条件,每条命令都是一个不可分割的原子操作。

3.2 单线程为什么还能这么快?------ 三驾马车

你的直觉可能会告诉你:单线程 = 慢。就像用一辆卡车运 10000 公斤货物要跑 50 趟,但用 50 辆卡车一次就能搞定。

那么,Redis 的单线程模型凭什么能达到每秒 10 万次的读写性能?答案来自三个关键因素:

因素一:纯内存访问 ------ 速度的物理基础

Redis 的所有数据都存储在内存中 。内存的访问延迟大约是 100 纳秒 (0.0001 毫秒),而硬盘的寻道时间大约是 10 毫秒

这个差距有多大?让我们直观感受一下:

操作 耗时 类比
L1 缓存访问 0.5 ns 眨一下眼的时间
内存访问 100 ns 约你读完这两个字的时间
SSD 随机读取 0.1 ms 约一次心跳的时间
机械硬盘寻道 10 ms 约蜂鸟扇一次翅膀的时间

内存操作比硬盘快 10 万倍。在这个速度面前,线程切换的开销反而比执行命令本身还要大。所以,Redis 选择了单线程------如果瓶颈在内存访问速度上,加再多线程也无济于事。

因素二:非阻塞 IO 与事件驱动 ------ epoll 的威力

如果 Redis 是单线程,那它怎么同时处理成千上万个客户端连接呢?难道要一个一个排队等?

这正是 IO 多路复用 技术发挥作用的地方。Redis 使用 Linux 的 epoll 机制,将网络连接、数据读写、连接关闭等操作都抽象为"事件":

复制代码
Redis 的事件驱动模型(Event Loop):

┌──────────────────────────────────────────────────┐
│                 Redis Event Loop                  │
│                                                  │
│  ┌────────────────────────────────────────────┐  │
│  │            事件关注列表(epoll)             │  │
│  │                                            │  │
│  │  客户端 1 --- 可读事件 ──▶ ready!            │  │
│  │  客户端 2 --- 等待中...                      │  │
│  │  客户端 3 --- 可写事件 ──▶ ready!            │  │
│  │  ...                                       │  │
│  │  客户端 N --- 可读事件 ──▶ ready!            │  │
│  └────────────────────────────────────────────┘  │
│                      ↓                           │
│  ┌────────────────────────────────────────────┐  │
│  │            单线程事件处理器                  │  │
│  │   依次处理每个 "ready" 事件的对应命令       │  │
│  └────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────┘

💡 通俗理解

epoll 想象成一个高效的"前台接待员"。它同时盯着成百上千个客户端连接,但只把那些"有话要说"(有数据到达)或"愿意听话"(可以发送响应)的连接报告给 Redis 的单线程去处理。绝大多数时间都花在真正需要处理的事件上,而不是盲目地逐个轮询。

这样一来,Redis 不必为每个客户端创建一个线程,也不会在等待网络数据上浪费时间------只在有数据可读或有结果可写时才进行处理。

因素三:避免线程切换和竞态开销

多线程编程的复杂性主要来自两个方面:

  1. 线程切换开销:CPU 在线程之间切换时,需要保存和恢复上下文(寄存器、程序计数器、栈指针等),这个切换本身就需要时间。
  2. 竞态条件处理:多个线程同时访问共享数据时,必须使用锁、信号量等同步机制------加锁、解锁、等待锁,每一步都有开销。

Redis 选择单线程,直接从根源上消除了这两个问题:

  • 没有线程切换:不需要保存和恢复上下文
  • 没有竞态条件:不需要锁,数据结构实现可以极其精简

程序的复杂度大幅降低,代码更短、bug 更少、性能反而更好。


3.3 单线程的"阿喀琉斯之踵":长命令阻塞

单线程模型虽然有很多优点,但它有一个致命的弱点:如果某个命令执行时间过长,它后面的所有命令都会被阻塞,整个 Redis 服务看起来就像"卡死"了一样。

复制代码
长命令导致的阻塞效应:

  ┌─────────────┐
  │ 命令 A (快)  │  0.1ms  ──▶ 瞬间完成
  ├─────────────┤
  │ 命令 B (慢)  │  2000ms ──▶ 耗时 2 秒!!
  ├─────────────┤
  │ 命令 C       │  卡住等待...
  ├─────────────┤
  │ 命令 D       │  卡住等待...
  ├─────────────┤
  │ 命令 E       │  卡住等待...
  └─────────────┘

哪些操作容易成为"慢命令"呢?

  • KEYS * 在键数量巨大时遍历所有键
  • SMEMBERS 在集合有数百万元素时返回所有成员
  • DEL 删除一个包含海量元素的键
  • FLUSHALL / FLUSHDB 清空整个数据库

⚠️ 关键警示

Redis 是为快速执行场景设计的数据库。在设计和使用 Redis 时,始终要问自己:这个操作会不会执行很久?如果有风险,考虑以下替代方案:

  • SCAN 替代 KEYS
  • SSCAN 替代 SMEMBERS
  • UNLINK 替代 DEL(异步删除)
  • 分解大操作为多个小操作

Redis 官方在 6.0 版本引入了多线程 IO ,但这仅限于网络数据的读写和协议解析------命令的执行仍然是单线程的。这个设计在保持单线程命令执行简单性的同时,利用多线程提升了网络 IO 的吞吐能力。

记住一句话:Redis 的核心执行模型永远是单线程的,理解这一点是高效使用 Redis 的前提。


四、常见问题与误区汇总

Q1:KEYS 命令既然有风险,为什么还存在?

KEYS 命令并非"不能用",而是"不能在生产环境的大数据量场景下用"。在以下场景中,KEYS 完全合理:

  • 开发和调试阶段,数据库中只有少量键
  • 确定数据库中键的数量不会增长到很大
  • 管理脚本中,需要一次性获取所有匹配的键

Redis 保留 KEYS 是因为它简单直观,适合轻量级场景。对于重量级场景,请使用 SCAN

Q2:内部编码切换会丢数据吗?

:不会。内部编码切换是透明的数据重组过程,Redis 会将数据从旧编码格式转换为新编码格式,数据内容完全不变。对外部操作来说,你完全感觉不到这个切换发生过。

Q3:单线程是不是意味着 Redis 无法利用多核 CPU?

:这是一个很好的问题。确实,单个 Redis 实例只能使用一个 CPU 核心。但这不代表 Redis 无法利用多核:

  • 方案一:在同一台机器上启动多个 Redis 实例,每个实例绑定不同的 CPU 核心
  • 方案二:使用 Redis Cluster(集群模式),数据分布到不同节点,每个节点运行在不同的核心/机器上
  • 方案三:Redis 6.0+ 的多线程 IO 可以利用多核处理网络 IO

Q4:Redis 是单线程的,那为什么还要关注"原子性"?

:正因为 Redis 是单线程的,所以每条命令天然就是原子的------这是单线程模型最大的优势之一。你不需要像在多线程环境那样使用锁来保证数据一致性。但要注意,如果你使用 Lua 脚本或多条命令的组合操作,原子性需要由脚本本身来保证。


五、总结与下一步行动

本章核心回顾

本章我们学习了 Redis 的三个预备知识,它们是理解后续所有内容的基石:

模块 核心内容 最关键的一句话
全局命令 KEYS、EXISTS、DEL、EXPIRE、TTL、TYPE 操作的是"键",与值的类型无关
内部编码 对外五种类型,内部多种编码 内外分离,自动切换,对用户透明
单线程模型 命令排队执行,纯内存 + epoll + 免锁 快是因为避开了线程开销,而不是因为线程多

你的下一步行动

  • 动手验证:在本地 Redis 中执行本文的每个示例命令,亲眼观察返回结果
  • 深度探索 :使用 OBJECT ENCODING 查看你项目中每个键的内部编码,感受 Redis 的自动选择机制
  • 建立直觉 :存入 100 个不同类型的键,用 KEYSTYPETTL 等命令自由探索
  • 思考题:如果你的项目中有 100 万条缓存数据,你会如何设计键的命名规则和过期策略?

完成这些练习后,你将对 Redis 的基础运作机制有扎实的理解。接下来,就可以信心满满地进入五种数据结构的深度学习之旅了------从 String(字符串类型) 开始!


参考资料

相关推荐
磊 子4 小时前
1.4CPU缓存一致性
java·spring cloud·缓存·系统
Lucky_ldy5 小时前
C语言学习:文件操作
学习
AI算法沐枫5 小时前
大模型 | 大模型之机器学习基本理论
人工智能·python·神经网络·学习·算法·机器学习·计算机视觉
Tirzano5 小时前
超大型组和用户缓存redis
redis·缓存·哈希算法
小新同学^O^6 小时前
简单学习 --> LangChain
python·学习·langchain
阿维的博客日记6 小时前
zset实现延迟队列
redis·zset
无小道6 小时前
Redis——string类型相关指令
redis·指令·string
吃好睡好便好6 小时前
在Matlab中绘制阶梯图
开发语言·人工智能·学习·算法·机器学习·matlab
Restart-AHTCM7 小时前
LangChain学习之提示词模板 (Prompts) - 练习(2/8)
学习·langchain