一、Redis 入门基础

1.1 什么是 Redis

Redis 是开源的、基于内存的高性能键值对(Key-Value)数据库,支持数据持久化,常用来做缓存、消息队列、计数器等。

1.2 Redis 核心特点

  1. 基于内存:读写速度极快(每秒 10 万 + 次操作)
  2. 键值对存储:Key 唯一,Value 支持多种数据类型
  3. 数据持久化:可把内存数据保存到磁盘,重启不丢失
  4. 单线程:避免多线程锁竞争,效率更高
  5. 多语言支持: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 种持久化策略
  1. RDB:定时快照(默认开启)
  2. AOF:记录写命令(默认关闭)
  3. RDB + AOF:混合模式(推荐生产)
  4. 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:后台异步(推荐)
  • 其他触发:主从全量复制、执行 SHUTDOWNdebug reload
5. 优点
  • 恢复速度极快
  • 文件体积小,节省磁盘
  • 对性能影响小,适合大数据恢复
6. 缺点
  • 可能丢失数据:最后一次快照后的数据会丢
  • fork 大内存实例时耗时、耗内存
  • 不适合高数据安全要求场景

三、AOF 持久化(Append Only File)

1. 概念

记录每一条写命令,以日志形式追加到文件,重启时重放命令恢复数据。

2. 核心流程
  1. 写命令 → AOF 缓冲区
  2. 按策略同步到磁盘
  3. 文件过大 → 自动重写(压缩)
  4. 重启 → 顺序执行 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

六、持久化选择方案

  1. 纯缓存、允许丢数据:关闭所有持久化
  2. 允许丢几分钟数据、追求性能:只用 RDB
  3. 高数据安全、生产环境AOF(everysec)+ RDB
  4. Redis 集群:必须开启持久化防止全量同步风暴

七、补充要点

  1. RDB fork 原理采用写时复制(Copy-On-Write),主进程和子进程共享内存,修改时才复制页。

  2. AOF 重写不阻塞主进程重写由子进程完成,主进程可继续写入。

  3. 重启加载顺序同时存在 RDB 和 AOF → 优先加载 AOF

  4. 持久化与主从复制主从全量复制 = 主节点生成 RDB → 发给从节点 → 从节点加载。

  5. 性能建议

    • 不要频繁触发 RDB/AOF 重写
    • 大内存实例建议关闭自动 RDB,改用定时任务 BGSAVE

八、高频面试题总结

  1. Redis 有哪几种持久化?RDB、AOF、混合持久化、无持久化。
  2. RDB 和 AOF 区别?速度、文件大小、数据安全性、恢复机制。
  3. AOF 三种策略?always、everysec、no。
  4. AOF 重写作用?压缩日志,减少体积,加快恢复。
  5. 生产推荐用什么?混合持久化(AOF+RDB),appendfsync everysec。

七、Redis 事务基础

一、事务基本定义

Redis 事务是一个单独的隔离操作,事务内所有命令会序列化、按顺序执行,执行过程中不会被其他客户端命令打断,核心作用是串联多个命令、防止插队,保证一批命令依次执行。


二、核心命令

命令 作用
MULTI 开启事务,进入命令组队阶段
EXEC 执行事务,队列中命令依次执行
DISCARD 放弃事务,清空命令队列
WATCH 监视一个 / 多个 key,事务执行前 key 被改动则事务中断
UNWATCH 取消对所有 key 的监视

三、事务执行流程

  1. 开启事务:执行 MULTI,客户端进入事务状态。
  2. 命令入队:输入的命令不会立即执行,而是加入事务队列,返回 QUEUED
  3. 执行 / 放弃
    • 执行: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 成功无回滚

五、事务错误处理机制

  1. 组队阶段错误(语法错、参数错)
    • 队列直接标记失效,EXEC整个事务被丢弃
  2. 执行阶段错误(类型错、值非法)
    • 只有报错命令不执行,其他命令正常执行
  3. 关键结论
    • Redis 事务不保证原子性,不支持回滚

六、并发冲突与锁机制

1. 事务冲突场景

多个客户端同时修改同一个 key(如账户余额),会出现超卖 / 扣减错误

2. 悲观锁(Pessimistic Lock)
  • 思想:每次操作都上锁,其他人阻塞等待。
  • 特点:强一致、并发差。
  • Redis 不原生支持悲观锁。
3. 乐观锁(Optimistic Lock)
  • 思想:不上锁,更新时检查是否被修改,修改则放弃执行。
  • Redis 用 WATCH 实现乐观锁。
4. WATCH 命令(重点)
  • 作用:在 MULTI 前监视 key,事务执行前 key 被修改 → 事务被打断,EXEC 返回 nil
  • 流程:
    1. WATCH key
    2. MULTI
    3. 命令入队
    4. EXEC
  • 示例:
SET balance 10000
WATCH balance
MULTI
DECRBY balance 8000
EXEC
  • 若其他客户端修改了 balance,本事务执行失败。
5. UNWATCH 命令
  • 取消所有 WATCH 监视。
  • 执行 EXEC / DISCARD 后会自动 UNWATCH

注意:Redis 默认没有锁,它是单线程串行执行所有命令,天然保证命令互斥;事务场景下默认使用 WATCH 实现乐观锁,不使用悲观锁。


七、Redis 事务三大特性

  1. 单独的隔离操作命令串行执行,不被其他命令打断。
  2. 无隔离级别概念队列命令在 EXEC不会实际执行
  3. 不保证原子性、不支持回滚执行中部分命令失败,不影响其他命令,无回滚机制。

八、补充要点

  1. Redis 事务不支持的功能
    • 不支持回滚
    • 不支持锁等待
    • 不支持嵌套事务
  2. 适用场景
    • 批量执行命令,保证顺序性
    • 简单的并发控制(配合 WATCH)
    • 不适合强一致性、复杂事务场景
  3. 与关系型数据库事务区别

    表格

    特性 Redis 事务 MySQL 事务
    原子性 不保证 保证
    回滚 不支持 支持
    隔离级别 4 种
    性能 较低
  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 挂 大面积 随机过期、集群、多级缓存

六、总结

  1. 穿透:查询不存在的数据,缓存不存储,流量直接打库。解决:布隆过滤器、缓存空值。
  2. 击穿:一个热点 Key 过期,高并发打库。解决:永不过期、分布式锁。
  3. 雪崩:大量 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
结构规则
  1. L1 最下层:保存全部数据,是完整有序链表
  2. L2~Ln 上层:都是索引层,不存全量数据
  3. 越往上,节点越少,跨度越大
  4. 查找从最上层开始,一路往下跳

3|跳跃表 查找过程

例子:查找 40

  1. L4 开始head → 50,50 > 40 → 不往后走,下到 L3

  2. 来到 L3head → 20 → 50,20 < 40 → 继续50 > 40 → 下到 L2

  3. 来到 L2head →10 →20 →30 →40找到 40!结束。


4|跳跃表 插入过程

  1. 先找到插入位置
  2. 随机生成层数(Redis 最大 32 层)
  3. 在每一层把节点 “插进链表”

⚠️ 关键:层数是随机的,保证索引均匀,不会退化成普通链表。


5|跳跃表 删除过程

  1. 找到节点
  2. 每一层都把该节点删掉
  3. 释放空间

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 的底层实现,优点是实现简单、查找快、支持范围查询与排名


Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐