Redis 数据类型有哪几种?
2025年12月26日
一则或许对你有用的小广告
欢迎 加入小哈的星球 ,你将获得: 专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新开坑项目: 《Spring AI 项目实战(问答机器人、RAG 增强检索、联网搜索)》 正在持续爆肝中,基于
Spring AI + Spring Boot3.x + JDK 21..., 点击查看; - 《从零手撸:仿小红书(微服务架构)》 已完结,基于
Spring Cloud Alibaba + Spring Boot3.x + JDK 17..., 点击查看项目介绍; 演示链接: http://116.62.199.48:7070/; - 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/
面试考察点
面试官提出这个问题,主要是考察以下几个层面:
- 基础知识掌握:候选人是否能完整、准确地列举出 Redis 的核心数据类型。
- 理解深度与区分度:是否清楚每种数据类型的底层数据结构、基本特性和典型应用场景,而不仅仅是记住名字。
- 实际应用能力:能否结合具体业务场景(如缓存、计数器、社交关系、排行榜等),说明为何选择某种特定数据类型,这反映了候选人的工程实践经验。
- 技术视野:是否了解 Redis 模块化扩展带来的新数据类型(如
JSON,Search),这表明候选人能跟进技术发展。
核心答案
Redis 主要提供了以下 9 种数据类型,包含 5 种基本类型,以及 4 种高级拓展类型:
- String(字符串):最基本的数据类型,可存储文本、数字或二进制数据。
- List(列表):基于双向链表或压缩列表实现的字符串元素集合,按插入顺序排序,支持两端插入和弹出。
- Set(集合):无序、唯一的字符串元素集合。
- Hash(哈希表/字典):由
field-value对组成的映射表,适合存储对象。 - ZSet(Sorted Set, 有序集合):与 Set 类似,但每个元素都关联一个
score(分数),用于排序。元素唯一,但score可以重复。 - Bitmaps(位图):本质上是 String 类型上的一组面向位的操作,用于高效处理位信息(如用户签到)。
- HyperLogLog(基数统计):用于高效(使用固定极小内存)估算集合中唯一元素数量的概率性数据结构。
- Geospatial(地理位置):基于 ZSet 实现,用于存储和操作地理位置信息(经纬度)。
- Stream(流):Redis 5.0 引入,用于实现高性能的消息队列,支持多消费者组和消息持久化。
此外,通过 Redis 模块(如 RedisJSON, RediSearch),还可以支持 JSON、全文搜索等更复杂的数据类型。
深度解析
原理/机制
- String:不仅是简单的文本。其值可以是数字(整数或浮点数),并支持原子性的自增/自减操作。其底层会根据值的类型和长度,采用
int、embstr或raw三种编码格式来优化内存和性能。 - List:早期版本在元素较少且较小时,采用内存紧凑的
ziplist(压缩列表)编码;否则采用双向链表linkedlist。新版本中,quicklist(快速列表,一种ziplist组成的链表)成为了统一的底层实现,兼顾了内存效率和操作性能。 - Hash:底层使用
ziplist(元素少时)或hashtable(哈希表)。相比于将整个对象序列化成 JSON 后存入一个 String,使用 Hash 可以独立访问或修改单个字段,更节省网络开销和内存。 - ZSet:其核心在于排序。内部使用一个
dict(哈希表)来保证元素member的唯一性,同时使用一个skiplist(跳跃表)来根据score维护有序性。跳跃表支持平均 O(log N) 复杂度的范围查询。 - Stream:作为消息队列,其核心结构是追加日志。每个消息有唯一的 ID,支持阻塞式读取,并借鉴了 Kafka 的设计,提供了消费者组的概念,允许同一消息被多个组独立消费,组内多个消费者负载均衡。
最佳实践与场景对比
- String:
- 场景:缓存简单值、计数器(
INCR)、分布式锁(SET key value NX PX timeout)。 - 最佳实践:对于可能频繁更新的对象,考虑拆分为 Hash。
- 场景:缓存简单值、计数器(
- Hash:
- 场景:存储用户信息、商品信息等对象,尤其是当需要频繁修改其中部分字段时。
- 对比:与将所有字段序列化成 JSON String 相比,Hash 在部分更新时优势明显。
- List:
- 场景:简单的消息队列(
LPUSH/RPOP)、最新 N 条动态(LTRIM)。 - 注意:基于 List 的队列没有 ack 机制,消息可能丢失。对于可靠性要求高的场景,应使用 Stream。
- 场景:简单的消息队列(
- Set:
- 场景:共同关注、共同好友(
SINTER)、随机推荐(SRANDMEMBER)。
- 场景:共同关注、共同好友(
- ZSet:
- 场景:实时排行榜(
ZREVRANGE)、延迟队列(将执行时间作为score)。
- 场景:实时排行榜(
- Bitmaps:
- 场景:用户每日签到统计(位偏移对应日期)、活跃用户统计。
- 优势:极其节省空间,1 亿用户的签到状态仅需约 12MB。
- HyperLogLog:
- 场景:统计网站的独立访客(UV)总数。
- 注意:有约 0.81% 的标准误差,且只能统计总数,无法取出单条数据。
常见误区
- 滥用 String 类型:将所有数据都序列化成 JSON 后存入一个大的 String 中,导致无法部分更新和浪费网络带宽。
- 混淆 ZSet 排序与插入顺序:ZSet 的排序只由
score决定,与插入先后无关。 - 对 HyperLogLog 的误解:试图从中获取具体的元素列表,而它只提供基数估算。
- 将 List 用于需要持久化确认的复杂消息队列:应优先选择 Stream。
总结
掌握 Redis 数据类型,关键在于不仅要记住 5 种基础类型和 4 种扩展类型,更要深入理解其底层数据结构的实现原理与各自最匹配的业务场景,从而在系统设计中做出最合理、最高效的选择。