Redis数据结构入门:String、Hash、List、Set、SortedSet全面认识

Redis数据结构入门:String、Hash、List、Set、SortedSet全面认识

前面已经了解了 Redis 的基本概念

接下来正式进入 Redis 最核心的一部分:

Redis 数据结构

Redis 虽然是一个 Key-Value 型数据库,但这里的 Value 并不只是普通字符串。

Redis 为不同业务场景提供了多种数据结构。

入门阶段需要重点掌握:

String
Hash
List
Set
SortedSet

除此之外,还经常会接触:

GEO
Bitmap
HyperLogLog

理解这些数据结构,是后续使用 Redis 实现缓存、排行榜、点赞、好友关系、签到、UV 统计等功能的基础。


一、Redis 的数据存储模型

Redis 本质上采用:

Key → Value

的形式保存数据。

例如:

name → Jack

其中:

name

是 Key。

Jack

是 Value。

再比如:

age → 20

或者:

user:1001 → 用户数据

因此可以把 Redis 简单理解成一个非常大的:

Map<String, Object>

当然,这只是为了帮助理解。

Redis 实际的数据存储和底层实现要复杂得多。


二、Redis 的 Key 是什么类型?

Redis 中的 Key 本质上是:

String

因此平时看到的:

name

age

user:1

order:10001

product:1001

本质上都是字符串 Key。

例如:

user:1001:name

也是一个完整的字符串 Key。

所以 Redis 的整体模型可以进一步理解为:

String Key
     ↓
     Value

真正丰富的地方主要在于:

Value 可以采用不同的数据结构

三、Redis 常用的数据结构

入门阶段最重要的五种数据结构是:

Redis
│
├── String
│
├── Hash
│
├── List
│
├── Set
│
└── SortedSet

可以先建立一个整体印象:

类型特点常见用途
String单值结构缓存、计数器、验证码
HashField-Value对象信息
List有序、可重复列表、队列
Set无序、不可重复去重、共同好友
SortedSet有序、不可重复排行榜

后续 Redis 的大量业务应用,本质上就是:

根据业务需求选择合适的数据结构。


四、String 类型

String 是 Redis 中:

最基本、最常用的数据类型。

最简单的结构就是:

Key → Value

例如:

name → Jack

age → 20

city → Shanghai

对应 Redis:

SET name Jack

SET age 20

SET city Shanghai

查询:

GET name

返回:

Jack

五、String 不只是保存字符串

虽然名字叫:

String

但它并不仅仅可以保存普通文字。

String 可以保存:

字符串

整数

浮点数

二进制数据

例如:

name → "Jack"

可以作为普通字符串。

age → 20

可以保存数字。

article:1001:views → 10000

可以作为计数器。

甚至:

对象序列化结果

也可以存储在 String 中。

所以 String 应该理解成:

Redis 中最基础的一种字节序列数据结构。


六、String 的典型使用场景

String 的应用非常广泛。

例如:

缓存数据

product:1001
    ↓
商品信息

例如:

product:1001 → 商品JSON

验证码

code:13800138000 → 9527

再设置过期时间:

5分钟后失效

非常适合:

短信验证码

邮箱验证码

临时Token

等数据。


计数器

例如文章阅读次数:

article:1001:views → 100

执行:

INCR article:1001:views

即可实现:

100
 ↓
101
 ↓
102

这种原子递增操作。

因此 String 很适合:

访问次数

点赞数量

库存计数

接口调用次数

等场景。


七、Hash 类型

Hash 可以理解为:

Key
 ↓
多个 Field → Value

例如保存用户信息:

user:1001
│
├── name → Jack
├── age  → 20
└── city → Shanghai

整体结构:

Key
 ↓
Hash
 ↓
Field → Value

它与 Java 中的:

Map<String, String>

非常相似。


八、Hash 与 String 的区别

假设现在要保存一个用户:

User {
    id: 1001,
    name: "Jack",
    age: 20
}

如果使用 String,可以把整个对象序列化:

user:1001
    ↓
{"id":1001,"name":"Jack","age":20}

结构:

Key
 ↓
整个对象

如果使用 Hash:

user:1001
│
├── id   → 1001
├── name → Jack
└── age  → 20

结构:

Key
 ↓
Field
 ↓
Value

Hash 可以直接针对:

某一个字段

进行操作。

例如只修改:

age

而不需要读取并重新写入整个对象。


九、Hash 的典型应用

Hash 很适合保存:

对象型数据

例如:

用户信息

商品信息

购物车信息

配置项

例如:

product:1001
│
├── name  → iPhone
├── price → 6999
├── stock → 100
└── brand → Apple

如果业务经常需要针对对象中的单独字段进行读写,Hash 会非常自然。


十、List 类型

List 是一个:

按照插入顺序排列的字符串序列。

例如:

A
B
C
D

List 中的元素:

有顺序

并且:

可以重复

例如:

A
B
B
C

是合法的。

可以简单类比 Java 中的:

LinkedList

不过 Redis List 的具体实现和 Java 集合并不相同,这里主要用于帮助理解其使用方式。


十一、List 可以从两端操作

Redis List 一个非常重要的特点是:

可以从左边操作

也可以从右边操作

例如一个 List:

A ← B ← C

可以从左侧添加:

LPUSH

也可以从右侧添加:

RPUSH

同样可以从两侧获取或移除元素。

所以 List 非常适合模拟:

队列

栈

等数据结构。


十二、使用 List 实现队列

普通队列强调:

先进先出

也就是:

FIFO

全称:

First In First Out

例如:

A → B → C

A 最先进入,那么:

A

应该最先出去。

可以通过 List 两端操作实现:

一端插入
+
另一端取出

形成:

进入顺序:

A
B
C

取出顺序:

A
B
C

十三、使用 List 实现栈

栈强调:

后进先出

即:

LIFO

全称:

Last In First Out

例如:

A
B
C

C 最后进入,那么 C 最先出去:

C
B
A

通过:

同一端插入
+
同一端取出

就可以利用 Redis List 实现类似栈的效果。


十四、List 的典型使用场景

List 可以用于:

消息列表

最新动态

简单消息队列

任务队列

时间线

例如:

article:list
│
├── article3
├── article2
└── article1

新文章加入后放到最前面:

article4
article3
article2
article1

这样就可以快速获取:

最新N条数据

需要注意:

如果业务需要完整的消息确认、消费组、重试等消息队列能力,通常应该考虑 Redis Streams 或专业消息队列,而不是简单依赖 List。


十五、Set 类型

Set 是一个:

无序且元素唯一的集合。

例如:

A
B
C

如果再次加入:

A

集合中仍然只有:

A
B
C

不会出现重复值。

这与 Java 中的:

HashSet

在使用概念上比较类似。


十六、Set 最重要的特点

可以归纳成两个关键词:

无序

唯一

因此:

A
B
C

加入顺序可能是:

A → B → C

但读取时不应该依赖固定顺序。

同时:

A
A
A

加入多次以后:

A

只会保留一个。

因此 Set 天然适合:

去重

场景。


十七、Set 支持集合运算

Set 一个非常重要的能力是:

集合运算

包括:

交集

并集

差集

例如:

集合 A
=
{1, 2, 3}

集合 B
=
{2, 3, 4}

交集:

A ∩ B
=
{2, 3}

并集:

A ∪ B
=
{1, 2, 3, 4}

差集:

A - B
=
{1}

这些能力在社交业务中非常有价值。


十八、Set 实现共同好友

例如:

张三的好友:

friend:zhangsan
=
{李四, 王五, 赵六}

李雷的好友:

friend:lilei
=
{王五, 赵六, 韩梅梅}

求:

friend:zhangsan
∩
friend:lilei

得到:

{王五, 赵六}

这就是:

共同好友

因此 Set 非常适合:

共同关注

共同好友

兴趣标签

用户去重

等业务。


十九、Set 实现关注关系

例如某个用户关注:

follow:1001
│
├── 1002
├── 1003
└── 1004

另一个用户关注:

follow:2001
│
├── 1003
├── 1004
└── 1005

取交集:

1003
1004

就能快速得到:

共同关注

这也是 Redis Set 非常典型的业务应用。


二十、SortedSet 类型

SortedSet 也称为:

ZSet

它与 Set 有一个共同特点:

元素不能重复

但是 SortedSet 比 Set 多了一个非常关键的东西:

Score

每个元素都会关联一个:

分数

结构:

Member → Score

例如:

Jack → 100

Rose → 90

Tom → 80

Redis 可以按照:

Score

进行排序。


二十一、SortedSet 为什么叫有序集合?

普通 Set:

A
B
C

元素没有业务排序依据。

SortedSet:

Jack → 100

Rose → 90

Tom → 80

每个 Member 都对应一个 Score。

于是 Redis 可以按照:

100
90
80

进行排序。

形成:

1. Jack  100

2. Rose   90

3. Tom    80

这就是:

Sorted Set

有序集合。


二十二、SortedSet 最典型的应用:排行榜

假设游戏积分:

张三 → 1000

李四 → 800

王五 → 1200

存入 SortedSet:

game:rank

那么 Redis 可以根据分数进行排序:

第1名 王五 1200

第2名 张三 1000

第3名 李四 800

因此 SortedSet 非常适合:

游戏排行榜

销售排行榜

文章热度榜

主播排行榜

商品销量榜

等业务。


二十三、Set 与 SortedSet 的区别

两者非常容易混淆。

可以直接通过一张表区分:

特性SetSortedSet
元素唯一是是
是否有序不保证业务顺序按 Score 排序
是否有 Score否是
支持集合运算是是
典型场景去重、关系排行榜

核心区别:

Set
 ↓
唯一

SortedSet
 ↓
唯一 + Score + 排序

二十四、List 与 Set 的区别

List:

有序

可重复

Set:

无序

不可重复

例如 List:

A
B
B
C

是允许的。

而 Set:

A
B
B
C

最终实际上只有:

A
B
C

所以:

是否允许重复

是判断使用 List 还是 Set 的重要标准之一。


二十五、五种常用类型整体对比

可以把五种数据结构统一整理为:

数据类型数据特点是否有序是否重复常见场景
String单个值--缓存、计数
HashField-Value-Field唯一对象
List元素列表有序可以队列、列表
Set元素集合无业务顺序不可以去重、关系
SortedSetMember+Score有序不可以排行榜

可以先牢牢记住:

String
 ↓
单值

Hash
 ↓
对象

List
 ↓
有序可重复

Set
 ↓
无序不可重复

SortedSet
 ↓
有序不可重复 + Score

二十六、Redis 的特殊数据结构

除了五种常用数据结构之外,Redis 中还经常会接触:

GEO

Bitmap

HyperLogLog

这三种结构解决的是更加特定的问题。


二十七、GEO

GEO 主要用于:

地理位置

相关的数据处理。

可以保存:

经度

纬度

地点名称

例如:

上海 → 经纬度

北京 → 经纬度

广州 → 经纬度

之后可以进行:

计算两地距离

查询某个位置附近的数据

获取坐标

等操作。

因此 GEO 常用于:

附近的人

附近商家

门店查询

距离计算

位置服务

二十八、一个 GEO 应用场景

假设外卖平台保存:

店铺A → 经纬度

店铺B → 经纬度

店铺C → 经纬度

用户当前位置:

经度 X

纬度 Y

系统就可以查询:

当前位置5公里以内有哪些店铺?

这就是 GEO 的典型业务需求。


二十九、Bitmap

Bitmap 可以简单理解成:

用一个个二进制位记录状态

每一个位置只有:

0

或者

1

例如:

0 → 未签到

1 → 已签到

一个用户一个月的签到情况:

1 1 0 1 1 0 1 ...

可以非常紧凑地表示:

1号 已签到

2号 已签到

3号 未签到

4号 已签到

因此 Bitmap 特别适合:

大量布尔状态

的存储。


三十、Bitmap 的典型场景

例如:

用户签到

用户在线状态

功能开关

权限状态

活跃用户统计

假设有:

1亿用户

每个用户只需要记录:

今天是否登录

如果每个人保存一个完整字符串,空间浪费很大。

而一个 Bitmap 中:

1 bit

就可以表示:

登录 / 未登录

因此 Bitmap 在大规模布尔状态统计中非常节省空间。

需要注意:

Bitmap 在 Redis 中并不是完全独立于 String 的底层数据类型,而是建立在 String 之上的位操作能力。


三十一、HyperLogLog

HyperLogLog 是一种:

概率统计数据结构

主要用于:

估算一个集合中不重复元素的数量。

这个数量称为:

Cardinality

即:

基数

例如:

A
B
C
A
B
D

不同元素有:

A
B
C
D

所以基数是:

4

三十二、HyperLogLog 的典型应用:UV

网站统计中经常出现两个概念:

PV

UV

PV:

Page View

表示页面访问次数。

例如一个用户访问 10 次:

PV += 10

UV:

Unique Visitor

表示独立访客。

一个用户访问 10 次:

UV 仍然只算 1

例如:

用户A访问10次

用户B访问5次

用户C访问20次

则:

PV = 35

UV = 3

三十三、为什么 UV 统计需要特殊结构?

如果直接用 Set 保存每一个用户:

uv:2026-09-01
│
├── user10001
├── user10002
├── user10003
└── ...

确实可以准确去重。

但是如果网站有:

数千万

甚至数亿

用户,Set 需要保存所有用户标识,内存消耗可能非常大。

HyperLogLog 的特点则是:

牺牲少量精度
      ↓
换取极低的内存占用

因此非常适合:

大规模UV统计

独立设备数量

独立IP数量

等只关心:

大概有多少个不同元素

而不需要保存所有具体元素的场景。


三十四、HyperLogLog 是精确统计吗?

不是。

HyperLogLog 属于:

概率型算法

它得到的是:

近似值

而不是绝对精确值。

因此如果业务要求:

100% 精确

例如:

实际用户数量必须精确到1

就不能简单使用 HyperLogLog 代替精确集合统计。

它更加适合:

网站UV

趋势分析

大规模统计

这类允许极小误差的业务。


三十五、八种常见结构整体关系

入门阶段可以形成这样一张图:

Redis 数据结构
│
├── 常用类型
│   │
│   ├── String
│   │     └── 缓存、计数器
│   │
│   ├── Hash
│   │     └── 对象
│   │
│   ├── List
│   │     └── 列表、队列
│   │
│   ├── Set
│   │     └── 去重、关系
│   │
│   └── SortedSet
│         └── 排行榜
│
└── 特殊能力
    │
    ├── GEO
    │     └── 地理位置
    │
    ├── Bitmap
    │     └── 二值状态
    │
    └── HyperLogLog
          └── 基数统计

这张图可以作为后续 Redis 命令学习的整体知识框架。


三十六、到底应该选择哪一种数据结构?

真正使用 Redis 时,不应该看到 Redis 就全部:

SET
GET

而应该根据业务数据特点选择结构。

可以采用下面的思考方式。


保存一个简单值

例如:

验证码

Token

计数器

缓存字符串

选择:

String

保存一个对象

例如:

用户信息

商品信息

并且需要频繁修改单独字段:

Hash

通常更自然。


保存有顺序、允许重复的数据

例如:

任务列表

简单队列

最新动态

可以考虑:

List

保存不能重复的数据

例如:

用户标签

关注用户

已点赞用户

可以考虑:

Set

保存需要排序的数据

例如:

积分排行榜

销售榜

热度榜

可以考虑:

SortedSet

保存位置数据

例如:

附近商铺

附近车辆

可以考虑:

GEO

保存大量0/1状态

例如:

签到

在线状态

是否活跃

可以考虑:

Bitmap

统计海量不重复数据数量

例如:

网站UV

可以考虑:

HyperLogLog

三十七、一个简单的数据结构选择流程

可以总结成:

我要存什么?
     ↓
只是一个值?
     ↓
String

一个对象多个字段?
     ↓
Hash

需要有顺序?
     ↓
允许重复?
 ┌───────┴───────┐
 是              否
 ↓               ↓
List          SortedSet
              (需要排序)

只需要去重?
     ↓
Set

地理位置?
     ↓
GEO

大量0/1状态?
     ↓
Bitmap

只统计不重复数量?
     ↓
HyperLogLog

当然,真实业务往往比这张图复杂,但它非常适合帮助建立最初的选型意识。


三十八、为什么 Redis 要提供这么多数据结构?

假设 Redis 只有:

String

那么开发者当然也可以自己实现很多功能。

例如排行榜:

把所有人保存成JSON
 ↓
读取整个JSON
 ↓
Java排序
 ↓
再写回Redis

但是这样:

网络开销大

代码复杂

并发控制困难

效率低

Redis 直接提供 SortedSet 后:

用户
 ↓
Score
 ↓
Redis自动维护排序

应用程序只需要执行对应命令即可。

所以 Redis 的强大之处不仅仅在于:

它很快

还在于:

Redis 本身就是一个数据结构服务器。

不同的数据结构直接提供了适合特定业务模型的操作能力。


三十九、数据结构决定命令

Redis 中的命令通常和数据结构密切相关。

例如:

String
 ↓
SET
GET
INCR

Hash:

HSET
HGET
HGETALL

List:

LPUSH
RPUSH
LPOP
RPOP

Set:

SADD
SREM
SMEMBERS

SortedSet:

ZADD
ZRANGE
ZREM

所以学习 Redis 命令时,不应该死记所有命令,而应该:

先理解数据结构
      ↓
再理解对应操作
      ↓
最后记命令

这样学习效率会高很多。


四十、Redis 命令名称其实有规律

观察:

SET

HSET

SADD

ZADD

可以发现很多 Redis 命令都有命名规律。

例如:

H
 ↓
Hash

S
 ↓
Set

Z
 ↓
SortedSet

因此:

HGET

很容易理解为:

Hash GET

而:

HSET

就是:

Hash SET

类似地:

SADD

就是向:

Set

添加元素。

ZADD

就是向:

SortedSet

添加元素。

理解这种规律之后,很多命令会更容易记忆。


四十一、不要只记命令,要理解场景

例如:

String

如果只记:

SET
GET

那么只是会使用命令。

真正理解以后应该知道:

String
 ↓
简单缓存
验证码
Token
计数器

同样:

Set

不只是记住:

SADD
SMEMBERS

更应该马上想到:

去重

共同关注

共同好友

SortedSet 应该马上想到:

排行榜

这才是 Redis 数据结构真正重要的地方。


四十二、几个容易混淆的问题

1. Redis 是 Key-Value,所以 Value 都是 String 吗?

不是。

Key 通常可以理解为字符串,而 Value 可以采用多种 Redis 数据结构,例如:

String

Hash

List

Set

SortedSet

2. List 会自动去重吗?

不会。

List:

允许重复元素

例如:

A
A
A

完全可以存在。


3. Set 有顺序吗?

普通 Set 不应该用于依赖业务顺序的场景。

如果业务需要:

唯一
+
排序

应该考虑:

SortedSet

4. SortedSet 中元素能重复吗?

Member 不能重复。

但不同 Member:

可以拥有相同的 Score

例如:

Jack → 100

Rose → 100

是允许的。


5. Bitmap 是真正独立的 Redis 类型吗?

从底层来说,Bitmap 是建立在:

String

之上的位操作能力。

学习阶段通常会把它作为一种特殊的数据结构能力单独理解。


6. HyperLogLog 能得到绝对准确的 UV 吗?

不能。

HyperLogLog 是:

概率型数据结构

得到的是估算结果。

如果必须获得完全精确的结果,就需要选择其他方案。


四十三、常见面试问题

Q1:Redis 常用的数据结构有哪些?

最常见的五种是:

String

Hash

List

Set

SortedSet

另外还经常会使用:

GEO

Bitmap

HyperLogLog

等能力。


Q2:String 可以保存数字吗?

可以。

Redis String 可以保存字符串、数字以及二进制数据。

当保存整数时,还可以利用:

INCR

DECR

等命令实现原子计数。


Q3:Hash 适合什么场景?

Hash 特别适合保存:

对象型数据

例如:

用户

商品

购物车

每个对象内部可以由多个:

Field → Value

组成。


Q4:List 和 Set 有什么区别?

List:

有序
+
可以重复

Set:

无业务顺序
+
不可重复

Q5:Set 和 SortedSet 有什么区别?

Set:

元素唯一

SortedSet:

元素唯一
+
每个元素有Score
+
按照Score排序

因此 SortedSet 非常适合实现排行榜。


Q6:排行榜应该选择什么类型?

通常可以使用:

SortedSet

其中:

Member
 ↓
用户

Score
 ↓
积分

Redis 可以根据 Score 自动维护顺序。


Q7:共同好友适合使用什么数据结构?

通常可以使用:

Set

分别保存两个用户的好友集合,然后利用:

交集

得到共同好友。


Q8:用户签到可以使用什么结构?

如果每天只需要表示:

签到

未签到

可以考虑使用:

Bitmap

每一位使用:

0 / 1

表示签到状态。


Q9:UV 统计可以使用什么?

如果允许一定统计误差,并且数据规模非常大,可以考虑:

HyperLogLog

它能够使用较少内存估算不重复元素数量。


四十四、核心知识总结

这一部分最重要的是建立 Redis 数据结构的全局认识。

首先:

Redis
 ↓
Key → Value

其中:

Key
 ↓
字符串

而 Value 可以采用多种数据结构。

最常用的五种:

String
 ↓
简单值、缓存、计数器

Hash
 ↓
对象

List
 ↓
有序、可重复

Set
 ↓
无序、唯一

SortedSet
 ↓
唯一 + Score + 排序

三种常见特殊能力:

GEO
 ↓
地理位置

Bitmap
 ↓
0/1状态

HyperLogLog
 ↓
基数统计

最终可以形成这样一张 Redis 数据结构知识图:

                    Redis
                      │
              Key → Value
                      │
      ┌───────────────┴───────────────┐
      │                               │
   常用结构                         特殊能力
      │                               │
 ┌────┼────┬────┬─────┐          ┌────┼────┐
 ↓    ↓    ↓    ↓     ↓          ↓    ↓    ↓
String Hash List Set SortedSet   GEO Bitmap HLL
 │     │    │    │      │        │    │    │
缓存  对象 列表 去重   排行榜    位置 状态 UV

四十五、总结

Redis 并不是一个只能执行:

SET

GET

的简单 Key-Value 数据库。

真正让 Redis 强大的一个重要原因,就是它提供了丰富的数据结构。

开发过程中应该建立这样的思维:

先分析业务数据
       ↓
判断数据特点
       ↓
选择Redis数据结构
       ↓
再选择Redis命令

例如:

简单缓存
 ↓
String

对象
 ↓
Hash

队列
 ↓
List

共同好友
 ↓
Set

排行榜
 ↓
SortedSet

附近商家
 ↓
GEO

用户签到
 ↓
Bitmap

网站UV
 ↓
HyperLogLog

掌握这种“业务场景 → 数据结构 → Redis 命令”的思考方式以后,后续学习 Redis 就不再只是记忆一堆命令,而是在理解为什么某一种结构更适合解决某一类问题。

接下来继续学习 Redis 命令时,可以按照:

通用命令
   ↓
String
   ↓
Key层级设计
   ↓
Hash
   ↓
List
   ↓
Set
   ↓
SortedSet

逐步展开。


若有转载,请标明出处:https://blog.csdn.net/CharlesYuangc/article/details/165092957

更多推荐