Redis基础知识(源码安装,数据类型,持久化,事务,订阅,缓存三大问题,跳跃表)
一、Redis 入门基础
1.1 什么是 Redis
Redis 是开源的、基于内存的高性能键值对(Key-Value)数据库,支持数据持久化,常用来做缓存、消息队列、计数器等。
1.2 Redis 核心特点
- 基于内存:读写速度极快(每秒 10 万 + 次操作)
- 键值对存储:Key 唯一,Value 支持多种数据类型
- 数据持久化:可把内存数据保存到磁盘,重启不丢失
- 单线程:避免多线程锁竞争,效率更高
- 多语言支持:Java、Python、Go 等都有客户端
1.3 Redis 常用使用场景
- 热点数据缓存(减轻数据库压力)
- 分布式锁、分布式 Session
- 计数器(点赞、播放量、访问量)
- 消息队列、发布订阅
- 排行榜、好友关系、标签系统
二、Redis 安装与基础启动
官网
https://redis.io/downloads/
https://redis.io/downloads/https://download.redis.io/releases/
https://download.redis.io/releases/
2.1 Linux 源码安装
# 1. 安装编译依赖(gcc 编译器)
yum install -y gcc gcc-c++ make
# 2. 下载 Redis 安装包
wget https://download.redis.io/releases/redis-8.6.3.tar.gz
# 3. 解压
tar -zxvf redis-8.6.3.tar.gz
# 4. 进入目录编译
cd redis-8.6.3
make && make install
# 5. 拷贝配置文件
cp redis.conf /etc/redis.conf
2.2 基础配置
编辑 /etc/redis.conf,修改 3 个核心配置:
以下仅学习
# 允许远程访问(注释掉 127.0.0.1)
# bind 127.0.0.1
# 关闭保护模式(否则远程连不上)
protected-mode no
# 后台运行(守护进程)
daemonize yes
生产配置类似:
# 1. 绑定IP(只允许本机 + 信任内网IP,绝对不注释!)
bind 127.0.0.1 192.168.24.145
# 2. 保护模式(生产必须开启!)
protected-mode yes
# 3. 必须设置强密码(最重要!)
requirepass 你的超级强密码
# 4. 后台运行
daemonize yes
# 5. 禁用危险命令(生产必加)
rename-command CONFIG ""
rename-command FLUSHDB ""
rename-command FLUSHALL ""
# 6. 只允许内网访问,绝不暴露公网
2.3 启动 / 连接 / 关闭
# 启动 Redis(指定配置文件)
redis-server /etc/redis.conf
# 连接 Redis 客户端(默认端口 6379)
redis-cli
# 关闭 Redis(安全关闭,不丢数据)
[root@redis ~]# redis-cli -a 123456 shutdown
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
可能出现连接被拒绝的情况:
最常出现的是端口被占用
fuser -k 6379/tcp
| 命令 | 作用 | 适用场景 |
|---|---|---|
fuser -k 6379/tcp |
按端口杀 | 端口被占,不知道谁在占用 |
kill PID |
按进程号杀 | 知道哪个进程,精准杀死 |
三、Redis 核心通用命令(Key 操作)
所有数据类型都通用
| 命令 | 作用 | 示例 |
|---|---|---|
KEYS * |
查看所有 Key(生产禁用,初学用) | KEYS * |
EXISTS key |
判断 Key 是否存在(1 = 存在,0 = 不存在) | EXISTS name |
DEL key |
删除 Key | DEL name |
EXPIRE key 秒 |
给 Key 设置过期时间 | EXPIRE name 60 |
TTL key |
查看 Key 剩余过期时间(-1 = 永久,-2 = 已过期) | TTL name |
TYPE key |
查看 Key 的数据类型 | TYPE name |
FLUSHDB |
清空当前数据库 | FLUSHDB |
SELECT 数字 |
切换数据库(默认 16 个库:0~15) | SELECT 1 |
四、Redis 五大基础数据类型(核心重点)
4.1 String(字符串)
特点
- 最基础、最简单的类型,一个 Key 对应一个 Value
- 二进制安全,可存字符串、数字、图片、序列化对象
- 最大存储 512MB
常用命令
| 命令 | 作用 |
|---|---|
SET key value |
设置键值对 |
GET key |
获取值 |
SETNX key value |
Key 不存在时才设置(防覆盖) |
INCR key |
数字值 +1(原子操作,计数器核心) |
DECR key |
数字值 -1 |
APPEND key value |
追加字符串 |
示例
# 设置字符串
SET name "张三"
# 获取值
GET name
# 数字自增(播放量+1)
SET play 100
INCR play # play 变为 101
# 追加内容
APPEND name "先生"
使用场景
- 缓存用户信息、商品信息
- 计数器(点赞、播放量、访问量)
- 分布式锁、分布式 Session
4.2 List(列表)
特点
- 有序、可重复的字符串列表
- 底层是双向链表,头尾插入 / 删除速度极快
- 按照插入顺序排序
常用命令
| 命令 | 作用 |
|---|---|
LPUSH key value |
从 ** 左边(头部)** 插入元素 |
RPUSH key value |
从 ** 右边(尾部)** 插入元素 |
LPOP key |
从左边弹出元素(删除并返回) |
RPOP key |
从右边弹出元素 |
LRANGE key start end |
查看列表元素(0 -1 表示查看所有) |
LLEN key |
查看列表长度 |
示例
# 左插元素
LPUSH list "a" "b" "c"
# 右插元素
RPUSH list "d"
# 查看所有元素
LRANGE list 0 -1
# 列表长度
LLEN list
使用场景
- 消息队列、任务队列
- 朋友圈时间线、关注列表
- 栈 / 队列结构
4.3 Set(集合)
特点
- 无序、不可重复的字符串集合
- 添加、删除、查找速度极快(O (1))
- 支持交集、并集、差集运算
常用命令
| 命令 | 作用 |
|---|---|
SADD key value |
添加元素(自动去重) |
SMEMBERS key |
查看所有元素 |
SISMEMBER key value |
判断元素是否存在 |
SREM key value |
删除元素 |
SINTER key1 key2 |
求两个集合的交集 |
SUNION key1 key2 |
求两个集合的并集 |
示例
# 添加元素(重复添加无效)
SADD tag "redis" "mysql" "redis"
# 查看所有元素
SMEMBERS tag
# 判断元素是否存在
SISMEMBER tag "mysql"
# 求交集
SADD set1 "a" "b"
SADD set2 "b" "c"
SINTER set1 set2 # 结果:b
使用场景
- 点赞、收藏、打卡(去重)
- 好友关系、共同关注
- 标签系统
4.4 Hash(哈希)
特点
- 一个 Key 对应多个字段(field)+ 值(value)
- 适合存储对象(如用户信息、商品详情)
- 结构:
key → {field1:value1, field2:value2}
常用命令
| 命令 | 作用 |
|---|---|
HSET key field value |
设置字段值 |
HGET key field |
获取单个字段值 |
HMSET key f1 v1 f2 v2 |
批量设置字段 |
HGETALL key |
获取所有字段和值 |
HDEL key field |
删除字段 |
HLEN key |
查看字段数量 |
示例
# 存储用户对象(id=1,name=张三,age=18)
HMSET user:1 name "张三" age 18 gender "男"
# 获取用户名
HGET user:1 name
# 获取所有信息
HGETALL user:1
默认不显示中文,转化为十六进制显示
加以下参数重新进入即可
127.0.0.1:6379> exit
[root@redis ~]# redis-cli -a 123456 --raw
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> HGETALL user:1
name
张三
age
18
gender
男
使用场景
- 存储用户信息、商品信息、订单信息
- 缓存结构化数据
4.5 ZSet(有序集合)
特点
- 有序、不可重复的集合
- 每个元素绑定一个分数(score),按分数自动排序
- 分数可重复,元素不可重复
常用命令
| 命令 | 作用 |
|---|---|
ZADD key score value |
添加元素(按分数排序) |
ZRANGE key start end |
正序查看元素 |
ZREVRANGE key start end |
倒序查看元素 |
ZSCORE key value |
查看元素分数 |
ZREM key value |
删除元素 |
示例
# 添加排行榜(分数:100、90、80)
ZADD rank 100 "张三" 90 "李四" 80 "王五"
# 倒序查看排行榜(从高到低)
ZREVRANGE rank 0 -1
# 查看张三分数
ZSCORE rank "张三"
使用场景
- 排行榜(成绩、热度、销量)
- 带权重的任务队列
五、Redis 核心配置文件(基础必懂)
# 绑定IP(注释掉允许所有IP访问)
# bind 127.0.0.1
# 保护模式(no=允许远程连接,任何人都能连接,数据裸奔)
protected-mode yes
# 后台运行(yes=守护进程)
daemonize yes
# 端口号(默认 6379)
port 6379
# 日志文件路径
logfile "/var/log/redis.log"
# 数据文件存储目录
dir /var/lib/redis
# 连接密码(可选,安全加固)
requirepass 123456
当 protected-mode yes 生效时:
只要 同时满足下面两个危险条件
1.没设置密码(没有 requirepass)
2.bind 监听所有 IP(bind 0.0.0.0,谁都能扫到)
👉 Redis 直接禁止:外网 / 局域网其他 IP 连接
只放行 本地 127.0.0.1
只要你打破上面任意一个条件,防盗门就放开:
你设了密码 ✅
或者你 bind 只指定本机 / 内网 IP ✅
只要有任意一个,就允许外部 IP 正常连。
六、Redis 持久化(防止数据丢失)
一、持久化总览
1. 定义
将内存中的数据写入磁盘,重启时重新加载,防止服务宕机导致数据丢失。
2. Redis 提供 4 种持久化策略
- RDB:定时快照(默认开启)
- AOF:记录写命令(默认关闭)
- RDB + AOF:混合模式(推荐生产)
- No persistence:纯内存,不持久
二、RDB 持久化(Redis Database)
1. 概念
指定时间间隔,将内存数据生成全量快照保存到磁盘(dump.rdb)。
2. 核心原理
- 主进程 fork 子进程
- 子进程写入临时文件 → 完成后替换旧 rdb 文件
- 主进程不阻塞,可继续处理请求
3. 关键配置(redis.conf)
dbfilename dump.rdb # 快照文件名
dir /var/lib/redis # 文件保存目录
save 900 1 # 900秒1次修改 → 快照
save 300 10 # 300秒10次修改 → 快照
save 60 10000 # 60秒1万次修改 → 快照
stop-writes-on-bgsave-error yes # 备份出错则停止写入
rdbcompression yes # 开启LZF压缩
rdbchecksum yes # 开启CRC64校验
4. 触发方式
- 自动触发:满足 save 配置
- 手动触发:
SAVE:阻塞(不推荐)BGSAVE:后台异步(推荐)
- 其他触发:主从全量复制、执行
SHUTDOWN、debug reload
5. 优点
- 恢复速度极快
- 文件体积小,节省磁盘
- 对性能影响小,适合大数据恢复
6. 缺点
- 可能丢失数据:最后一次快照后的数据会丢
- fork 大内存实例时耗时、耗内存
- 不适合高数据安全要求场景
三、AOF 持久化(Append Only File)
1. 概念
记录每一条写命令,以日志形式追加到文件,重启时重放命令恢复数据。
2. 核心流程
- 写命令 → AOF 缓冲区
- 按策略同步到磁盘
- 文件过大 → 自动重写(压缩)
- 重启 → 顺序执行 AOF 命令恢复
3. 关键配置
appendonly yes # 开启AOF(默认no)
appendfilename appendonly.aof # 日志文件名
appendfsync everysec # 同步策略
auto-aof-rewrite-percentage 100 # 增长100%重写
auto-aof-rewrite-min-size 64mb # 最小64M重写
no-appendfsync-on-rewrite no # 重写时是否同步
4. 三种同步策略
| 策略 | 说明 | 安全性 | 性能 |
|---|---|---|---|
| always | 每次命令都落盘 | 最高 | 最低 |
| everysec | 每秒落盘(默认) | 较高 | 较好 |
| no | 由操作系统决定 | 最低 | 最高 |
5. AOF 重写(Rewrite)
- 目的:压缩文件,只保留最小恢复指令集
- 触发:
- 自动:满足百分比 + 大小
- 手动:
BGREWRITEAOF
- 原理:Redis 4.0+ 重写时会把 RDB 快照写在 AOF 头部,速度大幅提升
6. AOF 文件损坏修复
redis-check-aof --fix appendonly.aof
7. 优点
- 数据安全性高,最多丢 1 秒数据
- 日志可读,可人工修复误操作
- 支持重写,文件可控
8. 缺点
- 文件比 RDB 大
- 恢复速度慢
- 对写入性能略有影响
四、RDB vs AOF 对比
| 维度 | RDB | AOF |
|---|---|---|
| 恢复速度 | 快 | 慢 |
| 文件大小 | 小 | 大 |
| 数据安全性 | 可能丢数据 | 高(everysec) |
| 性能影响 | 小 | 中 |
| 适用场景 | 备份、冷备、大数据恢复 | 生产高可用 |
| 重启加载优先级 | 低 | 高(优先加载 AOF) |
五、混合持久化(Redis 4.0+ 推荐)
1. 配置
aof-use-rdb-preamble yes # 默认开启
2. 原理
- AOF 重写时:先写 RDB 全量快照 + 再追加增量命令
- 兼顾:恢复快 + 数据安全 + 文件小
3. 生产最佳实践
- 开启 RDB + AOF 混合模式
- 同步策略:
everysec - 定期备份
dump.rdb
六、持久化选择方案
- 纯缓存、允许丢数据:关闭所有持久化
- 允许丢几分钟数据、追求性能:只用 RDB
- 高数据安全、生产环境:AOF(everysec)+ RDB
- Redis 集群:必须开启持久化防止全量同步风暴
七、补充要点
-
RDB fork 原理采用写时复制(Copy-On-Write),主进程和子进程共享内存,修改时才复制页。
-
AOF 重写不阻塞主进程重写由子进程完成,主进程可继续写入。
-
重启加载顺序同时存在 RDB 和 AOF → 优先加载 AOF。
-
持久化与主从复制主从全量复制 = 主节点生成 RDB → 发给从节点 → 从节点加载。
-
性能建议
- 不要频繁触发 RDB/AOF 重写
- 大内存实例建议关闭自动 RDB,改用定时任务
BGSAVE
八、高频面试题总结
- Redis 有哪几种持久化?RDB、AOF、混合持久化、无持久化。
- RDB 和 AOF 区别?速度、文件大小、数据安全性、恢复机制。
- AOF 三种策略?always、everysec、no。
- AOF 重写作用?压缩日志,减少体积,加快恢复。
- 生产推荐用什么?混合持久化(AOF+RDB),appendfsync everysec。
七、Redis 事务基础
一、事务基本定义
Redis 事务是一个单独的隔离操作,事务内所有命令会序列化、按顺序执行,执行过程中不会被其他客户端命令打断,核心作用是串联多个命令、防止插队,保证一批命令依次执行。
二、核心命令
| 命令 | 作用 |
|---|---|
| MULTI | 开启事务,进入命令组队阶段 |
| EXEC | 执行事务,队列中命令依次执行 |
| DISCARD | 放弃事务,清空命令队列 |
| WATCH | 监视一个 / 多个 key,事务执行前 key 被改动则事务中断 |
| UNWATCH | 取消对所有 key 的监视 |
三、事务执行流程
- 开启事务:执行
MULTI,客户端进入事务状态。 - 命令入队:输入的命令不会立即执行,而是加入事务队列,返回
QUEUED。 - 执行 / 放弃:
- 执行:
EXEC→ 依次执行所有队列命令,返回结果列表。 - 放弃:
DISCARD→ 清空队列,事务取消。
- 执行:
四、三种执行场景
1. 正常执行(组队成功 → 提交成功)
MULTI
SET k1 v1
SET k2 v2
EXEC
结果:两条命令都执行成功。
2. 组队阶段语法错误 → 整个事务取消
MULTI
SET k3 v3
SET k4 # 参数错误
SET k5 v5
EXEC
结果:EXEC 直接报错,所有命令都不执行。
3. 执行时命令错误 → 仅错误命令失败,其他继续
MULTI
SET k3 v3
INCR k3 # 字符串无法自增,执行报错
SET k4 v4
EXEC
结果:
SET k3 v3成功INCR k3报错SET k4 v4成功无回滚。
五、事务错误处理机制
- 组队阶段错误(语法错、参数错)
- 队列直接标记失效,
EXEC时整个事务被丢弃。
- 队列直接标记失效,
- 执行阶段错误(类型错、值非法)
- 只有报错命令不执行,其他命令正常执行。
- 关键结论
- Redis 事务不保证原子性,不支持回滚。
六、并发冲突与锁机制
1. 事务冲突场景
多个客户端同时修改同一个 key(如账户余额),会出现超卖 / 扣减错误。
2. 悲观锁(Pessimistic Lock)
- 思想:每次操作都上锁,其他人阻塞等待。
- 特点:强一致、并发差。
- Redis 不原生支持悲观锁。
3. 乐观锁(Optimistic Lock)
- 思想:不上锁,更新时检查是否被修改,修改则放弃执行。
- Redis 用 WATCH 实现乐观锁。
4. WATCH 命令(重点)
- 作用:在
MULTI前监视 key,事务执行前 key 被修改 → 事务被打断,EXEC 返回 nil。 - 流程:
WATCH keyMULTI- 命令入队
EXEC
- 示例:
SET balance 10000
WATCH balance
MULTI
DECRBY balance 8000
EXEC
- 若其他客户端修改了 balance,本事务执行失败。
5. UNWATCH 命令
- 取消所有 WATCH 监视。
- 执行
EXEC/DISCARD后会自动 UNWATCH。
注意:Redis 默认没有锁,它是单线程串行执行所有命令,天然保证命令互斥;事务场景下默认使用 WATCH 实现乐观锁,不使用悲观锁。
七、Redis 事务三大特性
- 单独的隔离操作命令串行执行,不被其他命令打断。
- 无隔离级别概念队列命令在
EXEC前不会实际执行。 - 不保证原子性、不支持回滚执行中部分命令失败,不影响其他命令,无回滚机制。
八、补充要点
- Redis 事务不支持的功能
- 不支持回滚
- 不支持锁等待
- 不支持嵌套事务
- 适用场景
- 批量执行命令,保证顺序性
- 简单的并发控制(配合 WATCH)
- 不适合强一致性、复杂事务场景
- 与关系型数据库事务区别
表格
特性 Redis 事务 MySQL 事务 原子性 不保证 保证 回滚 不支持 支持 隔离级别 无 4 种 性能 高 较低 - WATCH 注意事项
- WATCH 是乐观锁,高并发下冲突率高。
- 事务失败需重试。
- 不要 WATCH 过多 key,影响性能。
八、Redis 发布订阅(简单消息队列)
原理
发布者往频道发消息,订阅者从频道接收消息,一对多通信。
核心命令
# 订阅者:订阅频道
SUBSCRIBE chat
# 发布者:往频道发消息
PUBLISH chat "hello redis"
使用场景
- 简单消息通知、群聊
- 实时消息推送
127.0.0.1:6379> publish chat "hellow redis"
0
消息发出去了,但 0 个人收到!
因为你还没订阅(subscribe),没人在听这个频道。
订阅模式只能接收消息(这里可以开两个窗口验证)
要退出订阅模式按:
Ctrl + C
九、缓存三大问题
0. 先搞懂:缓存正常工作流程
用户请求 → 先查 Redis
命中 → 直接返回数据
没命中 → 查数据库 → 把结果写回 Redis → 返回数据
下面三个问题,都是 **「缓存没挡住请求,流量打到数据库把库压垮」**。
一、缓存穿透
1. 是什么
用户查一个「根本不存在的数据」缓存里没有 → 去数据库查 → 数据库也没有 → 不会写入缓存下次再来查 → 还是查库 → 无限穿透缓存,直接打库
2. 核心现象
- Redis 命中率极低
- 数据库压力暴涨
- 攻击者故意查 id=-1、id=999999999 这种不存在数据
3. 原理流程图
请求 → Redis(不存在)→ MySQL(不存在)→ 不写缓存
请求 → Redis(不存在)→ MySQL(不存在)→ 不写缓存
请求 → Redis(不存在)→ MySQL(不存在)→ 不写缓存
...
数据库被打死
4. 解决方案
(1)缓存空值(最简单)
查不到也存 null,设置短过期(30s~1min)。
if (DB 查不到) {
Redis.set(key, null, 30s);
}
(2)布隆过滤器
- 把所有存在的 id 提前放进布隆过滤器
- 请求来了先过过滤器 → 不存在直接拦截
- 优点:极省内存、极快
- 缺点:有极小误判率
(3)参数校验 + 黑名单
- 非法 id 直接拒绝
- 高频攻击 IP 拉黑
(4)接口限流
防恶意刷接口。
二、缓存击穿(热点 Key 失效)
1. 是什么
一个超级热点 Key 刚好过期一瞬间几万请求过来 → 缓存没命中 → 全部查数据库 → 数据库瞬间卡死
2. 核心特点
- 数据是存在的!
- 只有一个 Key 过期
- 高并发、热点数据(商品详情、热搜、活动页)
3. 原理流程图
上万请求同时来 → 热点Key过期
→ Redis 全部不命中
→ 全部打数据库
→ 数据库瞬间 100% CPU → 宕机
4. 解决方案
(1)热点 Key 永不过期(最常用)
活动、爆款商品直接设置 never expire。
(2)互斥锁(分布式锁)
只让一个线程去查数据库重建缓存,其他线程等待。
if (Redis 没命中) {
加锁
查数据库
写缓存
解锁
}
(3)过期时间加随机值
避免集中失效。
三、缓存雪崩(大面积失效,最危险)
1. 是什么
大量 Key 同一时间过期 或 Redis 直接宕机所有请求都查不到缓存 → 全部打数据库 → 数据库直接雪崩宕机
2. 核心特点
- 大面积 Key 失效
- 缓存层 “崩溃”
- 数据库直接被流量淹没
3. 原因
- 过期时间设置一样,批量过期
- Redis 单机挂了
- 机房故障、重启
4. 原理流程图
大量Key同时过期
↓
成千上万请求 → Redis 全部不命中
↓
全部请求打到数据库
↓
数据库崩溃 → 整个系统不可用
5. 解决方案
(1)过期时间加随机偏移
expire = 3600 + random(0~600)
避免同一时间集体过期。
(2)多级缓存
Nginx 缓存 + Redis + 本地缓存一层挂了还有一层。
(3)Redis 高可用(集群 / 哨兵)
防止 Redis 单点挂掉。
(4)限流、熔断、降级
扛不住就拒绝请求,保护数据库。
(5)缓存预热
启动时提前把数据加载进 Redis。
四、三张图总结
穿透图
请求 → Redis(无) → DB(无) → 不写缓存 → 循环打DB
击穿图
万请求 → 热点Key过期 → Redis无 → 全部打DB
雪崩图
大量Key过期 → Redis全空 → 全部打DB → DB崩溃
五、三者区别
| 问题 | 原因 | 范围 | 解决方案 |
|---|---|---|---|
| 穿透 | 查不存在数据 | 全局 | 布隆、缓存空值 |
| 击穿 | 热点 Key 过期 | 一个 Key | 永不过期、互斥锁 |
| 雪崩 | 大量 Key 过期 / Redis 挂 | 大面积 | 随机过期、集群、多级缓存 |
六、总结
- 穿透:查询不存在的数据,缓存不存储,流量直接打库。解决:布隆过滤器、缓存空值。
- 击穿:一个热点 Key 过期,高并发打库。解决:永不过期、分布式锁。
- 雪崩:大量 Key 同时失效,数据库崩溃。解决:随机过期、多级缓存、高可用集群。
十、跳跃表
0|先搞懂:跳跃表是干嘛的?(最核心)
跳跃表 = 给有序链表加 “多级索引”,让它能像二分查找一样快。它是 Redis 有序集合 ZSet 的底层实现!
1|为什么要有跳跃表?
1)普通有序链表(慢)
查找必须从头遍历到尾时间复杂度 O(N)数据多 → 巨慢
2)跳跃表(快)
加了多层索引,可以跳着走时间复杂度 O(logN)和红黑树一样快,但代码简单 10 倍
2|跳跃表 结构图解
标准图:
# 最上层是索引,最下层是完整数据
L4:head → 50 → → → → → → → → → → → → → nil
L3:head → 20 → 50 → → → → → → → → → → → nil
L2:head → 10 → 20 → 30 → 40 → 50 → 60 → → nil
L1:head → 10 → 20 → 30 → 40 → 50 → 60 → 70 → nil
结构规则
- L1 最下层:保存全部数据,是完整有序链表
- L2~Ln 上层:都是索引层,不存全量数据
- 越往上,节点越少,跨度越大
- 查找从最上层开始,一路往下跳
3|跳跃表 查找过程
例子:查找 40
-
从 L4 开始head → 50,50 > 40 → 不往后走,下到 L3
-
来到 L3head → 20 → 50,20 < 40 → 继续50 > 40 → 下到 L2
-
来到 L2head →10 →20 →30 →40找到 40!结束。
4|跳跃表 插入过程
- 先找到插入位置
- 随机生成层数(Redis 最大 32 层)
- 在每一层把节点 “插进链表”
⚠️ 关键:层数是随机的,保证索引均匀,不会退化成普通链表。
5|跳跃表 删除过程
- 找到节点
- 在每一层都把该节点删掉
- 释放空间
6|Redis 里的跳跃表
1)ZSet 为什么用跳跃表?
- 要排序
- 要范围查找(ZRANGEBYSCORE)
- 要排名(ZRANK)
- 要快
红黑树能做,但太难实现、太难调试、范围查询麻烦。跳跃表:简单、好维护、查找快、支持范围查询。
2)Redis 跳跃表节点结构
typedef struct zskiplistNode {
sds ele; // 元素值(member)
double score; // 分数(排序依据)
struct zskiplistNode *backward; // 后退指针(往前遍历)
struct zskiplistLevel {
struct zskiplistNode *forward; // 前进指针
unsigned long span; // 跨度(算排名用)
} level[];
} zskiplistNode;
每个字段作用
ele:存真实数据score:按它排序backward:反向遍历(ZREVRANGE)forward:指向下一个节点span:两个节点之间跨了多少元素,用来算排名
7|跳跃表时间复杂度
- 查找:O(logN)
- 插入:O(logN)
- 删除:O(logN)
8|跳跃表 VS 红黑树
| 对比项 | 跳跃表 | 红黑树 |
|---|---|---|
| 实现难度 | 简单 | 极难 |
| 查找效率 | O(logN) | O(logN) |
| 范围查询 | 极快 | 麻烦 |
| 并发安全 | 友好 | 不友好 |
| Redis 使用 | ✅ ZSet 底层 | ❌ 不用 |
9|跳跃表总结
跳跃表是多层索引的有序链表,平均时间复杂度 O(logN),是 Redis 有序集合 ZSet 的底层实现,优点是实现简单、查找快、支持范围查询与排名。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)