Redis 是一个高性能的键值数据库,但它远超普通的 key-value,因为它的值支持 5 大核心数据结构,包括:String、Hash、List、Set、ZSet,以及高级的结构:Bitmaps、HyperLogLog、GEO。每个都适用于不同的场景。理解它们的底层结构和行为差异,是写出高性能 Redis 应用的前提。
基本数据类型
String(字符串)
特点:
● 最常用的数据结构,占据 Redis 使用的 90% ● value 最大支持 512MB
底层结构:
使用 SDS(Simple Dynamic String) 实现(而不是 C 字符串)
struct sdshdr {
int len; // 实际长度
int free; // 剩余空间
char buf[]; // 字符数组,结尾不带 \0
}
O(1) 获取长度,不需遍历 支持动态扩容和缩容,避免内存碎片
应用形式
● 普通值(name → "Tom") ● 数字型(可以做 INCR/DECR) ● 二进制(可存图片、压缩包等)
SET key value
GET key
INCR age
APPEND key "abc"
GETRANGE key 0 3
List(双端链表)
特点:
● 有序、可重复,适合队列、消息流等场景 ● 可从两端插入/弹出(LPUSH / RPUSH)
底层结构:
- QuickList(Redis 3.2+):由多个 ZipList 压缩表组成的链表
- 老版本用 LinkedList,但性能差、内存碎
插入复杂度:
| 操作 | 时间复杂度 |
|---|---|
| LPUSH/ RPUSH | O(1) |
| LPOP / RPOP | O(1) |
| LINDE | O(N) |
| LRANGE | O(N) |
示例命令:
LPUSH queue task1
RPUSH queue task2
LPOP queue
LRANGE queue 0 -1
Set(无序集合)
特点:
● 无序、去重 ● 支持交集、并集、差集操作
底层结构:
● 小数据量:intset(整数集合,总元素数量不超过 set-max-intset-entries(默认是 512)) ● 大数据量或者非整数成员:hashtable(哈希表) 自动切换,无需手动干预。
示例命令:
SADD tags "java"
SADD tags "redis"
SMEMBERS tags
SISMEMBER tags "java"
SUNION set1 set2
SortedSet(有序集合)
特点:
- 元素唯一,分值(score)可重复
- 按分值排序 → 实现排行榜、延迟队列
底层结构:
组合结构:
- 跳表(SkipList):支持按分数排序
- 哈希表:支持快速查找
复杂度:
| 操作 | 时间复杂度 |
|---|---|
| ZADD/ZREM | O(logN) |
| ZRANGE/ZREVRANK | O(logN + M) |
| ZSCORE/ZCARD | O(1) |
示例命令:
ZADD rank 100 "Alice"
ZADD rank 200 "Bob"
ZRANGE rank 0 -1 WITHSCORES
ZREVRANK rank "Alice"
ZREM rank "Bob"
Hash(键值对集合)
特点:
- 存储对象结构(如用户信息、商品信息)
- 可以看成小型的 Redis 本身:user:1001 → {name:Tom, age:18}
底层结构:
- 小数据量:ziplist(压缩列表)
- 大数据量:hashtable 自动转换触发条件:
- 单个键值 > 64 字节
- 元素数量 > 512 个
HSET user:1001 name "Tom"
HSET user:1001 age 18
HGETALL user:1001
HINCRBY user:1001 age 1
HDEL user:1001 name
重点汇总表
| 数据结构 | 是否有序 | 是否唯一 | 是否支持分数 | 典型场景 | 底层结构 |
|---|---|---|---|---|---|
| String | 否 | 否 | 否 | 缓存、计数器 | SDS |
| List | 是 | 否 | 否 | 消息队列 | QuickList |
| Set | 否 | ✅ 是 | 否 | 标签系统 | intset/hashtable |
| SortedSet | ✅ 是 | ✅ 是 | ✅ 是 | 排行榜、延迟队列 | 跳表 + 哈希表 |
| Hash | 无序 | key 唯一 | 否 | 用户对象缓存 | ziplist/hashtable |
高级类型
Bitmaps
现代计算机用二进制(位)作为信息的基础单位,1个字节等于8位,例如“big”字符串是由3个字节组成,但实际在计算机存储时将其用二进制表示,“big”分别对应的ASCII码分别是98、105、103,对应的二进制分别是01100010、01101001和 01100111。
Bitmaps本身不是一种数据结构,实际上它就是字符串,但是它可以对字符串的位进行操作。
Bitmaps单独提供了一套命令,所以在Redis中使用Bitmaps和使用字符串的方法不太相同。可以把 Bitmaps想象成一个以位为单位的数组,数组的每个单元只能存储0和1,数组的下标在 Bitmaps 中叫做偏移量。
布隆过滤器
1970 年布隆提出了一种布隆过滤器的算法,用来判断一个元素是否在一个集合中。 这种算法由一个二进制数组和一个 Hash 算法组成。
本质上布隆过滤器是一种数据结构,比较巧妙的概率型数据结构(probabilistic data structure),特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”。
相比于传统的 List、Set、Map 等数据结构,它更高效、占用空间更少,但是缺点是其返回的结果是概率性的,而不是确切的。
实际上,布隆过滤器广泛应用于网页黑名单系统、垃圾邮件过滤系统、爬虫网址判重系统等,Google 著名的分布式数据库 Bigtable 使用了布隆过滤器来查找不存在的行或列,以减少磁盘查找的IO次数,Google Chrome浏览器使用了布隆过滤器加速安全浏览服务。
HyperLogLog
HyperLogLog(简称 HLL)是 Redis 提供的一种基数估计(Cardinality Estimation)数据结构,用于统计唯一元素的数量,比如:
有多少个不同的 IP 访问了网站?有多少个独立用户点击了广告?
命令:
pfadd
PFADD uv:2025-07-28 user_id_001
(integer) 1
PFADD uv:2025-07-28 user_id_002
(integer) 1
pfcount
PFCOUNT uv:2025-07-28
(integer) 2
pfmerge
PFADD uv:2025-07-27 user_id_003
PFMERGE uv:all uv:2025-07-27 uv:2027-07-28
(integer) 3
HyperLogLog 基于概率论中伯努利试验并结合了极大似然估算方法,并做了分桶优化。
- List item 转为比特串 通过hash函数,将数据转为64位二进制的比特串。
- 分桶 前14位作为桶编号, 分布不同数据,避免局部集中偏差。 Redis 开发者(antirez)根据实验选择了 p=14(即 m=16384),因为这在误差与空间上达到了最佳平衡。
哈希值(64位):1010 1100 0110 0101 ...(64位总长)
→ 前 14 位(桶编号):10101110011001 → bucket 11257
→ 后 50 位(估稀有性):00000010011... → 前导 0 = 6 → register[11257] = max(当前, 6)
Redis 为什么选 14 记录桶的编号?
Redis 开发者(antirez)根据实验选择了 p=14(即 m=16384),因为这在误差与空间上达到了最佳平衡:
| p | 桶数m | 误差(约) | 空间消耗(每个桶 6 bits) |
|---|---|---|---|
| 10 | 1024 | ~3.25% | 0.75 KB |
| 12 | 4096 | ~1.63% | 3 KB |
| ✅14 | ✅16384 | ✅~0.81% | ✅12 KB(Redis 使用的) |
| 16 | 65536 | ~0.40% | 48 KB |
| 18 | 262144 | ~0.20% | 192 KB |
主要特点
| 特性 | 描述 |
|---|---|
| 功能 | 统计去重后的元素数量(基数) |
| 占用内存 | 永远不超过 12 KB,无论添加多少元素 |
| 是否精确 | ❌ 不精确(误差约 0.81%),但足够用于大数据统计场景 |
| 支持命令 | PFADD、PFCOUNT、PFMERGE |
| 典型用途 | UV统计、独立用户量、唯一访问者、唯一交易用户等 |
GEO
Redis GEO 用于 存储地理坐标(经纬度) 并支持基于位置的 距离计算、范围查询、附近搜索 等操作。
# 添加两个坐标
GEOADD locations 116.397128 39.916527 beijing
GEOADD locations 121.473701 31.230416 shanghai
# 计算两地距离(默认单位:米)
GEODIST locations beijing shanghai
# 指定单位为千米
GEODIST locations beijing shanghai km