5 种基本数据类型概览
1)String 字符串
2)List 列表
3)Set 集合
4)Hash 散列
5)Zset 有序集合
String 字符串
适用场景:缓存、计数器、分布式锁,图片等等。
底层原理:使用 SDS (简单动态字符串)。对比 C 语言的原生字符串,Redis 可以安全保存二进制数据(比如音频、图片、视频),并且可以 O(1) 获取字符串长度。可以动态扩容,动态增加内存,避免静态数组大小限制。杜绝缓冲区溢出问题,SDS 会检查内存是否足够。减少修改字符串的内存重分配,惰性空间释放+空间预分配策略。
Redis 3.2 以前
struct sdshdr {
// 已经适用的长度
unsigned int len;
// 剩余长度
unsigned int free;
char buf[];
};
Redis 3.2 以后(为了避免 int 浪费空间)
/* Note: sdshdr5 is never used, we just access the flags byte directly.
* However is here to document the layout of type 5 SDS strings. */
struct __attribute__ ((__packed__)) sdshdr5 {
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len; /* used */
uint8_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
uint16_t len; /* used */
uint16_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
uint32_t len; /* used */
uint32_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
uint64_t len; /* used */
uint64_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
List 列表
适用场景:队列、栈、消息队列。
举个例子,实现用户最近浏览记录等功能,可以使用 List 来存储用户的浏览记录,并通过 lpush/ltrim 操作来实现最近浏览记录的管理。
Redis 的 List 采用双向链表支持反向查找和遍历。
Redis 3.2 以前 List 底层采用 LinkedList(双向链表)和 ZipList(压缩列表),Redis 3.2 后引入了 LinkedList 和 ZipList 的结合 QuickList。
Set 集合
适用场景:求交集,并集,适用与好友列表、投票、社交网络、网页 UV(单个IP 访问量,数据量大用 hyperLogLog)、抽奖系统、随机点名等等。
Set 特点无序,不重复。
举个例子,在社交网络平台中,用户可以添加好友、删除好友,查看好友列表等操作。这种场景下,可以使用 Redis 的 Set 集合来存储用户的好友列表。通过使用 Redis 的 Set 集合来存储用户的好友关系,可以实现快速的添加、删除好友操作,并且支持高效的好友列表查询和好友关系分析。同时,Redis 的 Set 集合还支持去重功能,保证每个用户的好友列表中不会出现重复的好友。
Set 底层实现是由哈希表或者整数集合实现的。
1)如果集合的元素都是整数,并且元素个数小于 512 (默认值,可以自定义设置),Redis 会使用**整数集合(intSet)**作为 Set 类型的底层数据结构,主要目的为了减少内存空间消耗。
2)如果集合元素不满足上述条件,Redis 使用哈希表作为 Set 类型的底层数据结构。
注意事项:大数据量下作交集、差集、并集会导致 Redis 实例阻塞,防范大 Key 问题。
如果是集群模式,建议防止主库在大数据库执行大 Key 被阻塞,选择一个从库完成聚合统计,或者把数据返回客户端,由客户端来完成聚合。
Hash 哈希
哈希由键值对组成,支持添加、删除、查找、求交集、求并集等操作。
适用场景:存储对象的多个属性信息,存储用户信息,购物车等场景。
举个例子,假设我们需要存储每个用户的姓名、年龄和邮箱地址,可以使用 Hash 数据结构来存储这些信息。在 Redis 中,可以使用一个 Hash 对象来表示每个用户的信息,其中 Hash 的键是用户的唯一标识,如用户ID,键值对则存储用户的各个字段信息。
例如
用户ID为 1 的用户信息:姓名:Alice 年龄:25 邮箱地址:alice@example.com
HSET user:1 name Alice
HSET user:1 age 25
HSET user:1 email alice@example.com
Hash 底层实现由压缩列表(ZipList 或者哈希表 Dict)实现。
当哈希类型元素小于 512 个,并且所有元素的值大小(小于64个字节),Redis 使用压缩列表作为底层数据结构。
如果不满足上述条件,采用哈希表作为底层数据结构。
Zset 有序集合
Zset 有序集合相比于 Set 多了一个排序属性 Score 分值,对于有序集合 Zset 来说,每个元素有两个值组成,一个是元素值,一个是排序值(分值)。
使用场景
1)排行榜:可以将用户的分数作为 Zset 中的分数,用户的 ID 作为成员,这样可以根据用户的分数来对用户进行排名。
2)带权重的任务调度:可以将任务的执行时间作为 Zset 中的分数,任务的 ID 作为成员,这样可以按照任务的执行时间对任务进行排序并调度执行。
3)范围查询:可以根据分数的范围来获取一定范围内的成员,如获取分数在某个区间的用户或任务。
举个例子:假设有一个学生社团组织,需要记录学生参加社团活动的积分,并根据积分对学生进行排名。可以使用 Zset 数据结构来存储学生的积分信息,学生的学号作为成员,积分作为分数。
ZADD studentscore 80 1001
ZADD studentscore 75 1002
ZADD studentscore 90 1003
获取学生积分排名
ZREVRANGE studentscore 0 -1 WITHSCORES
Zset 类型底层实现由压缩列表(ZipList)或者跳表(SkipList)
如果有序集合的元素小于 128 个,并且每个元素的值小于 64 字节,采用压缩列表作为 Zset 类型的底层数据结构。
如果不满足上述条件,采用跳表(加快查询效率)作为 Zset 类型的底层数据结构。
总结
1)String(字符串):最简单的数据类型,常用于存储文本、数字等简单数据,适用于缓存、计数器、状态标记等场景。
2)List(列表):有序的字符串元素集合,支持头部和尾部的插入、删除操作,适用于消息队列、最新消息列表等场景。
3)Set(集合):不重复的字符串元素集合,支持交集、并集、差集等操作,适用于去重、共同好友、排重等场景。
4)Hash(哈希):键值对集合,适用于存储对象属性、用户信息、配置信息等场景。
5)Zset(有序集合):每个元素都关联一个分数,支持按分数排序,适用于排行榜、带权重的任务调度、范围查询等场景。
1. 字符串 (String)
-
概述:字符串是Redis中最简单的数据类型,可以存储文本或二进制数据,最大支持512MB。
-
底层原理:Redis内部使用简单的字节数组来存储字符串数据。由于其简单性,字符串在Redis中的操作都非常高效。
-
使用场景:适用于缓存数据、计数器、存储短小的文本等场景。
2. 列表 (List)
-
概述:列表是一个有序的字符串集合,可以包含重复的元素。
-
底层原理:Redis的列表底层使用双向链表实现,支持在两端插入和删除元素,因此在读写两端的操作效率较高。
-
使用场景:适用于实现消息队列、发布订阅系统、实现简单的日志系统等场景。
3. 集合 (Set)
-
概述:集合是一组唯一的字符串集合,不允许重复元素。
-
底层原理:Redis的集合底层使用哈希表实现,因此添加、删除、查找元素的时间复杂度都是O(1)。
-
使用场景:适用于实现好友关系、标签系统、数据去重等场景。
4. 哈希表 (Hash)
-
概述:哈希表是一种键值对的集合,类似于Java中的Map,其中的值也是一个键值对。
-
底层原理:Redis的哈希表底层使用哈希表实现,每个哈希表可以存储多个键值对,对于小哈希表,Redis会使用压缩列表来存储键值对。
-
使用场景:适用于存储对象的属性、缓存对象等场景。
5. 有序集合 (Sorted Set)
-
概述:有序集合是一种有序的字符串集合,每个元素都会关联一个分数,通过分数进行排序。
-
底层原理:Redis的有序集合底层使用跳跃表和哈希表实现,其中跳跃表用于保持元素的有序性,哈希表用于维护元素与分数之间的映射关系。
-
使用场景:适用于实现排行榜、范围查询等场景。
底层原理总结
-
Redis的基本数据类型都是在内存中存储的,因此具有高效的读写性能。
-
Redis通过使用不同的数据结构来实现不同的数据类型,以满足不同的需求。
使用场景总结
-
字符串适用于存储简单的键值对数据、计数器等。
-
列表适用于实现简单的消息队列、发布订阅系统等。
-
集合适用于实现好友关系、数据去重等。
-
哈希表适用于存储对象的属性、缓存对象等。
-
有序集合适用于实现排行榜、范围查询等。
总的来说,Redis提供了丰富的数据类型和高效的底层实现,能够满足各种不同的应用场景需求。