概述与核心数据结构
00:00
Redis 8.0概述、字符串SDS、哈希、列表quicklist、集合、有序集合跳表、位图、HyperLogLog、GEO、Stream、Vector Set。
1. Redis 8.0 概述
1.1 Redis 简介
Redis(Remote Dictionary Server)是开源的内存键值数据库,支持丰富的数据结构、持久化、高可用和集群功能。Redis 8.0 引入了 Vector Set 等重要新特性。
1.2 Redis 核心特性
| 特性 | 说明 |
|---|---|
| 内存存储 | 所有数据存储在内存,读写延迟微秒级 |
| 丰富数据结构 | String、Hash、List、Set、ZSet、Stream 等 |
| 持久化 | RDB 快照 + AOF 日志,混合持久化 |
| 高可用 | 主从复制 + Sentinel 哨兵自动故障转移 |
| 集群 | Redis Cluster 无中心分片集群 |
| 模块化 | RedisJSON、RediSearch、RedisBloom 等 |
| 单线程模型 | 命令执行单线程,I/O 多线程(6.0+) |
1.3 Redis 8.0 新特性
- Vector Set: 原生高维向量近似搜索(HNSW 算法)
- Redis for AI: 向量库、推理缓存、VSS 优化
- Redis Flex: 混合存储引擎(SSD + DRAM)
- I/O 多线程增强
- 函数(Functions)替代 Lua 脚本
- ACL 增强与 TLS 改进
2. 字符串(SDS)
2.1 SDS 结构
Redis 使用 SDS(Simple Dynamic String)替代 C 字符串:
// SDS 结构
struct sdshdr {
int len; // 已使用长度
int free; // 剩余空间
char buf[]; // 数据区
};
| 特性 | C 字符串 | SDS |
|---|---|---|
| 获取长度 | O(n) | O(1) |
| 缓冲区溢出 | 可能 | 不会(空间预分配) |
| 二进制安全 | 否 | 是(len 判断结尾) |
| 内存重分配 | 每次修改 | 最多 N 次(预分配+惰性释放) |
2.2 常用命令
# 基本操作
SET key value [EX seconds] [PX ms] [NX|XX] [KEEPTTL]
GET key
DEL key [key ...]
# 设置带过期
SET session:abc123 '{"user":"admin"}' EX 3600 # 1小时过期
SET cache:home '<html>...</html>' EX 300 # 5分钟缓存
# NX: 仅键不存在时设置(分布式锁)
SET lock:order:123 "uuid-xxx" NX EX 30
# 批量操作
MSET key1 val1 key2 val2 key3 val3
MGET key1 key2 key3
# 数值操作
SET counter 100
INCR counter # 101
INCRBY counter 10 # 111
DECRBY counter 5 # 106
INCRBYFLOAT counter 2.5 # 108.5
# 位操作
SETBIT user:active:20240101 100 1 # 第100位设为1
GETBIT user:active:20240101 100 # 返回1
BITCOUNT user:active:20240101 # 统计活跃用户数
BITOP AND result key1 key2 # 位运算
3. 哈希(Hash)
3.1 底层编码
Hash 底层编码:
1. listpack(小对象): field 数量 ≤ hash-max-listpack-entries 且值长度 ≤ hash-max-listpack-value
2. hashtable(大对象): 超过阈值时转换
hashtable 结构:
dict → ht[0] + ht[1](渐进式 rehash)
每个 ht: 数组 + 哈希函数(SipHash)
3.2 常用命令
# 基本操作
HSET user:1001 name "Alice" age 30 email "alice@example.com"
HGET user:1001 name # "Alice"
HMGET user:1001 name age email # 批量获取
HGETALL user:1001 # 获取所有字段
HDEL user:1001 email # 删除字段
HLEN user:1001 # 字段数量
# 数值操作
HINCRBY user:1001 age 1 # 年龄+1
HINCRBYFLOAT user:1001 score 0.5 # 浮点数增加
# 条件操作
HSETNX user:1001 email "new@example.com" # 仅字段不存在时设置
# 判断与遍历
HEXISTS user:1001 name # 字段是否存在
HKEYS user:1001 # 所有字段名
HVALS user:1001 # 所有字段值
HSCAN user:1001 MATCH "na*" # 模式匹配遍历
4. 列表(List)
4.1 底层编码
List 底层编码: quicklist
quicklist = listpack(压缩列表)+ 双向链表
每个节点是一个 listpack,中间节点可压缩(LZF 算法)
配置参数:
list-max-listpack-size: 单个 listpack 大小限制
list-compress-depth: 压缩深度(0=不压缩,1=首尾不压缩)
4.2 常用命令
# 队列操作(FIFO)
LPUSH queue:tasks "task1" "task2" # 左端入队
RPOP queue:tasks # 右端出队
# 栈操作(LIFO)
LPUSH stack:undo "action1"
LPOP stack:undo
# 阻塞操作(消息队列场景)
BLPOP queue:tasks 30 # 阻塞等待30秒
BRPOP queue:tasks 0 # 无限等待
# 查看与裁剪
LLEN queue:tasks # 列表长度
LRANGE queue:tasks 0 -1 # 查看所有元素
LRANGE queue:tasks 0 9 # 前10个
LTRIM queue:tasks 0 99 # 仅保留前100个
# 指定位置操作
LINDEX queue:tasks 0 # 按索引获取
LSET queue:tasks 0 "updated_task" # 按索引设置
LINSERT queue:tasks BEFORE "task2" "task1.5" # 插入
LREM queue:tasks 2 "task1" # 删除指定值
5. 集合(Set)
5.1 底层编码
Set 底层编码:
1. intset: 所有元素都是整数且数量 ≤ set-max-intset-entries(默认512)
2. hashtable: 元素为哈希表的 key,value 为 NULL
5.2 常用命令
# 基本操作
SADD tags:article:1 "redis" "database" "nosql"
SREM tags:article:1 "nosql"
SISMEMBER tags:article:1 "redis" # 是否存在
SMEMBERS tags:article:1 # 所有成员
SCARD tags:article:1 # 成员数量
# 随机操作
SRANDMEMBER tags:article:1 2 # 随机取2个(不删除)
SPOP tags:article:1 # 随机弹出1个
# 集合运算
SADD set:a 1 2 3 4 5
SADD set:b 3 4 5 6 7
SINTER set:a set:b # 交集: {3,4,5}
SUNION set:a set:b # 并集: {1,2,3,4,5,6,7}
SDIFF set:a set:b # 差集: {1,2}
SINTERSTORE result set:a set:b # 交集存入 result
SUNIONSTORE result set:a set:b # 并集存入 result
SDIFFSTORE result set:a set:b # 差集存入 result
# 遍历
SSCAN tags:article:1 MATCH "re*"
6. 有序集合(ZSet)
6.1 底层编码
ZSet 底层编码:
1. listpack: 元素数量 ≤ zset-max-listpack-entries 且值长度 ≤ zset-max-listpack-value
2. skiplist + hashtable:
- skiplist: 按分数排序,支持范围查询 O(logN)
- hashtable: 分数到成员的映射,支持 O(1) 查找
跳表结构:
最高层 ──────────────────────────────→
...
第2层 ──────→ ──────→ ──────→
第1层 → → → → → → → → → → →
平均查询复杂度: O(logN)
空间复杂度: O(N)
6.2 常用命令
# 添加与更新
ZADD leaderboard 100 "Alice" 95 "Bob" 88 "Charlie"
ZADD leaderboard XX 105 "Alice" # 仅更新已存在成员
ZADD leaderboard NX 92 "David" # 仅添加新成员
ZADD leaderboard GT 110 "Alice" # 仅当新分数更大时更新
ZADD leaderboard LT 80 "Bob" # 仅当新分数更小时更新
# 查询
ZSCORE leaderboard "Alice" # 获取分数
ZRANK leaderboard "Alice" # 排名(升序,从0开始)
ZREVRANK leaderboard "Alice" # 排名(降序)
# 范围查询(按分数)
ZRANGEBYSCORE leaderboard 90 100 # 分数 90~100
ZRANGEBYSCORE leaderboard -inf +inf # 所有
ZRANGEBYSCORE leaderboard (90 100 # 开区间 >90
ZCOUNT leaderboard 90 100 # 计数
# 范围查询(按排名)
ZRANGE leaderboard 0 9 WITHSCORES # 前10名(升序)
ZREVRANGE leaderboard 0 9 WITHSCORES # 前10名(降序)
# 删除
ZREM leaderboard "Charlie"
ZREMRANGEBYRANK leaderboard 0 2 # 删除排名0~2
ZREMRANGEBYSCORE leaderboard -inf 60 # 删除分数≤60
# 聚合操作
ZUNIONSTORE result 2 leaderboard1 leaderboard2 WEIGHTS 1 2 AGGREGATE SUM
ZINTERSTORE result 2 leaderboard1 leaderboard2 AGGREGATE MAX
7. 位图(Bitmap)
# 位图操作(基于 String 类型)
SETBIT sign:202401:1001 0 1 # 第1天签到
SETBIT sign:202401:1001 6 1 # 第7天签到
GETBIT sign:202401:1001 0 # 检查第1天是否签到
BITCOUNT sign:202401:1001 # 本月签到次数
BITPOS sign:202401:1001 1 # 第一个签到的天
# 统计活跃用户
SETBIT active:20240101 1001 1 # 用户1001活跃
SETBIT active:20240101 1002 1 # 用户1002活跃
BITCOUNT active:20240101 # 当日活跃用户数
# 连续签到天数
BITFIELD sign:202401:1001 GET u31 0 # 获取31位无符号整数
8. HyperLogLog
# 基数估算(0.81% 标准误差,仅 12KB 内存)
PFADD uv:20240101 "user1" "user2" "user3"
PFADD uv:20240101 "user1" "user4" # 重复不计数
PFCOUNT uv:20240101 # 估算独立访客数
# 合并
PFADD uv:20240102 "user2" "user3" "user5"
PFMERGE uv:week uv:20240101 uv:20240102
PFCOUNT uv:week # 合并后的独立访客数
9. GEO(地理位置)
# GEO 基于 ZSet 实现(使用 GeoHash 编码作为分数)
# 添加地理位置
GEOADD locations 116.397 39.908 "北京" 121.474 31.230 "上海" 113.264 23.129 "广州"
# 计算距离
GEODIST locations "北京" "上海" km # 约 1067.5 km
# 范围查询
GEORADIUS locations 116.397 39.908 500 km WITHDIST WITHCOORD COUNT 10
GEORADIUSBYMEMBER locations "北京" 500 km WITHDIST
# Redis 6.2+ 推荐使用 GEOSEARCH
GEOSEARCH locations FROMMEMBER "北京" BYRADIUS 500 km WITHDIST COUNT 10
GEOSEARCH locations FROMLONLAT 116.397 39.908 BYBOX 500 500 km WITHDIST
# 获取坐标
GEOPOS locations "北京"
# GeoHash 编码
GEOHASH locations "北京"
10. Stream
10.1 Stream 基本操作
# 添加消息
XADD orders:* name "Alice" product "Book" price 29.9
# 返回: "1704067200000-0"(时间戳-序号)
# 自定义 ID
XADD orders:2024 maxlen ~ 10000 * name "Bob" product "Pen" price 5.5
# maxlen ~ 10000: 近似裁剪到10000条
# 读取消息
XRANGE orders:2024 - + # 所有消息
XRANGE orders:2024 - + COUNT 10 # 前10条
XRANGE orders:2024 1704067200000-0 + # 从指定ID开始
XREVRANGE orders:2024 + - COUNT 5 # 最新5条
# 读取新消息(非阻塞)
XREAD COUNT 10 STREAMS orders:2024 $
# 阻塞读取
XREAD COUNT 10 BLOCK 5000 STREAMS orders:2024 $
10.2 消费者组
# 创建消费者组
XGROUP CREATE orders:2024 order-processors $ MKSTREAM
# $ = 从最新消息开始,0 = 从头开始
# 消费者读取
XREADGROUP GROUP order-processors consumer1 COUNT 1 STREAMS orders:2024 >
# 确认消息
XACK orders:2024 order-processors 1704067200000-0
# 查看待处理消息
XPENDING orders:2024 order-processors
# 查看消费者组信息
XINFO GROUPS orders:2024
XINFO CONSUMERS orders:2024 order-processors
# 转移未确认消息给其他消费者
XCLAIM orders:2024 order-processors consumer2 3600 1704067200000-0
11. Vector Set(Redis 8.0 新增)
11.1 Vector Set 概述
Vector Set 是 Redis 8.0 新增的数据结构,支持高维向量近似最近邻搜索(ANN),基于 HNSW(Hierarchical Navigable Small World)算法。
# 添加向量
VSET products:vec item1 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8
VSET products:vec item2 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9
VSET products:vec item3 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2
# 向量搜索(KNN)
VSEARCH products:vec 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 COUNT 5
# 带过滤条件的搜索
VSEARCH products:vec 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 COUNT 5 FILTER category == "electronics"
# 获取向量
VGET products:vec item1
# 删除向量
VDEL products:vec item1
# 查看信息
VINFO products:vec
11.2 Vector Set vs pgvector
| 维度 | Redis Vector Set | pgvector |
|---|---|---|
| 存储 | 内存 | 磁盘(可缓存) |
| 延迟 | 微秒级 | 毫秒级 |
| 索引算法 | HNSW | HNSW / IVFFlat |
| 持久化 | RDB/AOF | 原生持久化 |
| 适用场景 | 实时推荐、缓存 | 大规模向量检索 |
| 数据量 | 受内存限制 | 受磁盘限制 |