Redis 数据类型有哪几种?

8次阅读
没有评论

共计 3884 个字符,预计需要花费 10 分钟才能阅读完成。

Redis 提供 5 种基础数据类型 + 4 种扩展数据类型,共计 9 种:

数据类型底层编码说明典型场景
Stringint / embstr / raw最基本的类型,可存字符串、整数、浮点数缓存、计数器、分布式锁
Listquicklist(双向链表 + ziplist有序可重复的字符串列表消息队列、最新消息排行
Hashziplist / hashtable键值对集合,类似 Java 的 HashMap存储对象、用户信息
Setintset / hashtable无序不重复的字符串集合标签、共同好友、去重
ZSet(Sorted Set)ziplist / skiplist + hashtable有序不重复集合,每个元素关联一个 score排行榜、延迟队列
扩展类型说明典型场景
Bitmap位操作,基于 String 实现签到打卡、用户活跃统计
HyperLogLog基数估算,基于 String 实现UV 统计(允许误差)
GEO地理位置信息,基于 ZSet 实现附近的人、距离计算
Stream消息流(Redis 5.0 新增)消息队列(比 List 更完善)

深度解析

一、五种基础数据类型

1. String(字符串)

String 是 Redis 中最简单的数据类型,一个 Key 对应一个 Value。它可以存储字符串、整数、浮点数,最大能存 512MB 的数据。

底层编码有三种:

  • int:当值为整数且不超过 long 范围时使用,8 字节长整型
  • embstr:当字符串长度 ≤ 44 字节时使用,一次内存分配,紧凑存储
  • raw:当字符串长度 > 44 字节时使用,SDS(Simple Dynamic String)实现

Redis 数据类型有哪几种?

上图展示了 String 类型在不同场景下的三种编码方式。关键点如下:

  • int 编码:值为整数时,直接存储在 RedisObject 的 ptr 字段中,无需额外分配内存,效率最高。
  • embstr 编码:短字符串(≤ 44 字节)时,RedisObject 和 SDS 在一次内存分配中连续存放,CPU 缓存命中率高,分配和释放都只需一次操作。
  • raw 编码:长字符串(> 44 字节)时,RedisObject 和 SDS 分开分配,ptr 指针指向独立的 SDS 内存块。需要两次内存分配,但不受连续内存的限制。

常见使用场景

# 简单缓存
SET user:1001 "张三"
GET user:1001

# 计数器(原子操作)
SET article:1001:views 0
INCR article:1001:views    # views + 1
INCRBY article:1001:views 10  # views + 10

# 分布式锁
SET lock:order:1001 "unique_id" NX EX 30

2. List(列表)

List 是一个有序可重复的字符串链表,支持从两端插入和弹出元素。

底层采用 quicklist(快速列表)实现,它是 ziplist(压缩列表) + 双向链表的组合体。

Redis 数据类型有哪几种?

上图展示了 List 底层的 quicklist 结构。核心设计思想:

  • 双向链表:每个节点(quicklistNode)通过 prev 和 next 指针相连,支持双向遍历。
  • 每个节点是一个 ziplist:不是每个元素一个节点,而是一个节点存多个连续元素(ziplist),兼顾内存紧凑和操作效率。
  • 为什么这样设计:纯双向链表每个元素都有前后指针,内存开销大;纯 ziplist 虽然紧凑,但元素太多时插入删除需要大量内存搬移。quicklist 取两者之长,每个 ziplist 节点控制在合理大小(默认 8KB),中间节点还可以用 LZF 压缩。

常见使用场景

# 消息队列(LPUSH + BRPOP 实现阻塞队列)
LPUSH queue:task "task_data"
BRPOP queue:task 30  # 阻塞等待 30 秒

# 最新列表(如朋友圈时间线)
LPUSH timeline:user:1001 "msg_id:2001"
LRANGE timeline:user:1001 0 9  # 获取最新 10 条

3. Hash(哈希)

Hash 是一个键值对集合,类似 Java 中的 HashMap,适合用来存储对象。

底层编码有两种:

  • ziplist:当元素数量较少(默认 ≤ 128 个)且所有值都较短(默认 ≤ 64 字节)时使用
  • hashtable:当不满足 ziplist 条件时,转为真正的哈希表

Redis 数据类型有哪几种?

上图展示了 Hash 类型的两种编码及转换逻辑:

  • ziplist 编码:字段和值以连续的方式存储在压缩列表中,没有指针开销,内存极其紧凑。适合存储少量字段的对象。缺点是查找时需要遍历,时间复杂度 O(n),但元素少时影响可忽略。
  • hashtable 编码:与 Java 的 HashMap 类似,通过哈希函数定位桶,再用链地址法处理哈希冲突。查找时间复杂度 O(1)。当元素增多或值变大时自动从 ziplist 转换过来。

常见使用场景

# 存储用户信息
HMSET user:1001 name "张三" age 25 city "北京"
HGET user:1001 name          # "张三"
HMGET user:1001 name age     # "张三" "25"

# 修改单个字段(不需要读取整个对象)
HSET user:1001 age 26

小贴士:相比用 String 存储 JSON 对象,Hash 的优势在于可以只读写单个字段,无需序列化/反序列化整个对象,既省带宽又省时间。

4. Set(集合)

Set 是一个无序不重复的字符串集合,支持集合间的交集、并集、差集运算。

底层编码有两种:

  • intset(整数集合):当所有元素都是整数且数量 ≤ 512 时使用
  • hashtable:不满足上述条件时使用,Value 全部设为 null

Redis 数据类型有哪几种?

常见使用场景

# 标签系统
SADD article:1001:tags "Java" "Redis" "面试"
SMEMBERS article:1001:tags

# 共同好友(交集)
SINTER user:1001:friends user:1002:friends

# 去重
SADD unique:visitors "192.168.1.1"
SISMEMBER unique:visitors "192.168.1.1"  # 判断是否已存在

5. ZSet(有序集合)

ZSet(Sorted Set)在 Set 的基础上,给每个元素关联一个 score(分数),按分数自动排序。

底层编码有两种:

  • ziplist:元素少且短时使用
  • skiplist + hashtable:元素较多时使用,跳表保证范围查询效率,哈希表保证 O(1) 查找分数

Redis 数据类型有哪几种?

上图展示了 ZSet 底层的跳表(skiplist)结构。跳表的核心思想:

  • 多层索引:每个节点随机决定层数,层数越高节点越少。查找时从最高层开始,逐层往下找,类似二分查找的思路。
  • 查找效率:平均 O(logN),媲美红黑树,但实现更简单,范围查询更方便(只需在底层链表上遍历)。
  • 为什么不用红黑树:跳表的范围查询更高效,实现更简单(不用旋转维护平衡),内存占用也可以通过调节层高来控制。
  • hashtable 的作用:跳表虽然查找快,但按 member 查 score 仍需 O(logN)。配合 hashtable 后,可以通过 member 直接 O(1) 找到对应节点。

常见使用场景

# 排行榜
ZADD rank:score 100 "张三" 95 "李四" 88 "王五"
ZREVRANGE rank:score 0 2 WITHSCORES  # Top3

# 延迟队列(score 存时间戳)
ZADD delay:queue 1711500000000 "order:1001"
ZRANGEBYSCORE delay:queue 0 <当前时间戳>  # 获取到期任务

二、四种扩展数据类型

1. Bitmap(位图)

基于 String 实现,把 String 当成 bit 数组来操作,适合处理海量布尔值数据。

# 用户签到(key=年月, offset=日期, value=0/1)
SETBIT sign:1001:202603 26 1   # 3 月 26 日签到
GETBIT sign:1001:202603 26     # 查询某天是否签到
BITCOUNT sign:1001:202603      # 统计本月签到天数

极其节省内存:一个月的签到数据只需约 4 字节(31 个 bit)。

2. HyperLogLog

基于概率的基数估算算法,标准误差 0.81%。每个 Key 只需 12KB 内存就能估算 2^64 个不同元素的基数。

# UV 统计
PFADD uv:20260327 "user1" "user2" "user3"
PFCOUNT uv:20260327     # 估算独立访客数
PFMERGE uv:week uv:mon uv:tue  # 合并多天数据

3. GEO(地理位置)

基于 ZSet 实现,使用 GeoHash 编码经纬度为 score,支持距离计算和范围查询。

# 附近的人
GEOADD nearby 116.40 39.90 "天安门" 116.41 39.91 "王府井"
GEORADIUS nearby 116.40 39.90 1 km  # 查找 1km 内的地点
GEODIST nearby "天安门" "王府井" km  # 计算两点距离

4. Stream(消息流)

Redis 5.0 新增,是更完善的消息队列方案,支持消费组、消息确认、持久化,类似轻量版 Kafka。

# 生产消息
XADD stream:order * order_id 1001 amount 99.9

# 消费组消费
XGROUP CREATE stream:order group1 $
XREADGROUP GROUP group1 consumer1 COUNT 1 BLOCK 5000 STREAMS stream:order >

正文完
 0
数据与人
版权声明:本站原创文章,由 数据与人 于2026-08-18发表,共计3884字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,若要转载请注明出处。
评论(没有评论)