Redis 数据类型有哪几种?

一则或许对你有用的小广告

欢迎 加入小哈的星球 ,你将获得: 专属的项目实战(已更新的所有项目都能学习) / 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/

面试考察点

面试官提出这个问题,主要是考察以下几个层面:

  1. 基础知识掌握:候选人是否能完整、准确地列举出 Redis 的核心数据类型。
  2. 理解深度与区分度:是否清楚每种数据类型的底层数据结构基本特性典型应用场景,而不仅仅是记住名字。
  3. 实际应用能力:能否结合具体业务场景(如缓存、计数器、社交关系、排行榜等),说明为何选择某种特定数据类型,这反映了候选人的工程实践经验。
  4. 技术视野:是否了解 Redis 模块化扩展带来的新数据类型(如 JSONSearch),这表明候选人能跟进技术发展。

核心答案

Redis 主要提供了以下 9 种数据类型,包含 5 种基本类型,以及 4 种高级拓展类型:

  1. String(字符串):最基本的数据类型,可存储文本、数字或二进制数据。
  2. List(列表):基于双向链表或压缩列表实现的字符串元素集合,按插入顺序排序,支持两端插入和弹出。
  3. Set(集合):无序、唯一的字符串元素集合。
  4. Hash(哈希表/字典):由 field-value 对组成的映射表,适合存储对象。
  5. ZSet(Sorted Set, 有序集合):与 Set 类似,但每个元素都关联一个 score(分数),用于排序。元素唯一,但 score 可以重复。
  6. Bitmaps(位图):本质上是 String 类型上的一组面向位的操作,用于高效处理位信息(如用户签到)。
  7. HyperLogLog(基数统计):用于高效(使用固定极小内存)估算集合中唯一元素数量的概率性数据结构。
  8. Geospatial(地理位置):基于 ZSet 实现,用于存储和操作地理位置信息(经纬度)。
  9. Stream(流):Redis 5.0 引入,用于实现高性能的消息队列,支持多消费者组和消息持久化。

此外,通过 Redis 模块(如 RedisJSONRediSearch),还可以支持 JSON、全文搜索等更复杂的数据类型。

深度解析

原理/机制

  • String:不仅是简单的文本。其值可以是数字(整数或浮点数),并支持原子性的自增/自减操作。其底层会根据值的类型和长度,采用 intembstrraw 三种编码格式来优化内存和性能。
  • 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% 的标准误差,且只能统计总数,无法取出单条数据

常见误区

  1. 滥用 String 类型:将所有数据都序列化成 JSON 后存入一个大的 String 中,导致无法部分更新和浪费网络带宽。
  2. 混淆 ZSet 排序与插入顺序:ZSet 的排序只由 score 决定,与插入先后无关。
  3. 对 HyperLogLog 的误解:试图从中获取具体的元素列表,而它只提供基数估算。
  4. 将 List 用于需要持久化确认的复杂消息队列:应优先选择 Stream

总结

掌握 Redis 数据类型,关键在于不仅要记住 5 种基础类型和 4 种扩展类型,更要深入理解其底层数据结构的实现原理各自最匹配的业务场景,从而在系统设计中做出最合理、最高效的选择。