Redis 数据结构详解:从底层实现到应用场景

引言

Redis 是一个高效、灵活的键值存储系统,广泛应用于缓存、消息队列、实时分析等场景。Redis 提供了丰富的数据结构,每一种数据结构都适用于特定的业务需求。理解这些底层数据结构,不仅能帮助你更好地使用 Redis,也能加深你对 Redis 内部实现的理解。

本文将详细介绍 Redis 的核心数据结构,包括:

  • String
  • Hash
  • List
  • Set
  • Sorted Set (Zset)
  • Bitmap
  • HyperLogLog
  • Geo
  • Stream

此外,我们还将深入解析 Zset 的底层实现,特别是 跳表 和 Redis 7.0 引入的 ListPack,并探讨 Redis 为什么选择跳表而非 B+ 树。

一、Redis 的数据结构概览

Redis 支持的多种数据结构使它能够应对各种复杂的场景。下面是对 Redis 常见数据结构的简要介绍:

String(字符串)

  • 存储值:简单的字符串(例如,数字、文本、二进制数据)

  • 读写能力:支持快速的读取、写入、修改操作。

  • 应用场景

    • 缓存:简单的缓存键值对

    • 计数器:实现页访问计数、秒杀商品库存等功能

Hash(哈希)

  • 存储值:键值对集合(类似于字典或映射)

  • 读写能力:适合存储对象,支持按字段读取和修改。

  • 应用场景

    • 用户信息:存储用户的基本资料(用户名、邮箱、年龄等)

    • 配置管理:存储配置信息并能快速修改

List(列表)

  • 存储值:有序字符串集合

  • 读写能力 :支持两端插入、删除(LPUSHRPUSH),以及索引访问。

  • 应用场景

    • 消息队列:使用 LPUSHRPOP 实现生产者消费者模式

    • 实时数据流:处理顺序数据流,如日志收集

Set(集合)

  • 存储值:无序字符串集合,支持唯一性

  • 读写能力:支持快速插入、删除、查找操作,支持求交集、并集和差集等集合运算。

  • 应用场景

    • 唯一元素集合:如用户的标签、访问过的商品 ID

    • 社交关系:如用户的好友关系、关注列表

Sorted Set(有序集合,Zset)

  • 存储值:每个元素都包含一个分数(score)和一个值,元素会根据分数排序

  • 读写能力:支持按分数区间或排名范围获取元素,支持快速插入和删除

  • 应用场景

    • 排行榜:存储用户积分、游戏得分等

    • 时间序列:如股票价格、传感器数据等

Bitmap(位图)

  • 存储值:用于对 bit 位进行操作的数组

  • 读写能力:可以对单个位进行高效操作,适用于计数、标记等。

  • 应用场景

    • 用户签到:记录每个用户的每日签到情况

    • 活跃用户统计:使用 SETBIT 记录某个时间段内是否活跃

HyperLogLog

  • 存储值:用于统计唯一元素的基数估算,适合大数据量场景

  • 读写能力:基于概率算法,支持高效估算唯一值数量

  • 应用场景

    • 唯一用户统计:统计活跃用户数,避免直接存储大量数据

Geo(地理空间)

  • 存储值:基于经纬度坐标的数据

  • 读写能力:支持按位置范围查询、计算两点之间的距离等

  • 应用场景

    • 实时位置追踪:如共享单车、打车服务中的用户位置

    • 最近餐馆、商店查询等

Stream(流)

  • 存储值:消息流,支持高效的生产和消费操作

  • 读写能力:类似于日志,支持高并发的生产和消费

  • 应用场景

    • 实时日志:系统日志收集、监控数据流

    • 消息队列:提供持久化、顺序消费的消息队列

二、Zset(有序集合)的底层实现

Redis Zset 数据结构概述

Redis 中的有序集合(Zset)是一个按照分数排序的字符串集合,支持以下操作:

  • 插入、删除元素

  • 查询指定范围的元素(按分数排序)

  • 获取某个分数区间内的元素

Zset 的底层数据结构

最初,Redis 使用 压缩列表(Ziplist)跳表(Skiplist) 来实现 Zset 的存储。

(1)压缩列表(Ziplist)
  • 优点:内存节省,适用于元素数量小、范围不大的场景

  • 缺点:插入删除操作的性能较低

(2)跳表(Skiplist)
  • Redis 选择 跳表 作为 Zset 的默认数据结构。

  • 跳表通过多层次的索引结构来加速查找,具有对数时间复杂度 O(log N)


Redis 7.0:ListPack 实现 Zset

  • 从 Redis 7.0 开始,Zset 数据结构由 ListPack 取代了之前的压缩列表和跳表实现。

  • ListPack 是一种新的高效的内存编码方式,支持更低的内存消耗,并且支持更高效的查询和插入。

三、跳表(Skiplist)详解

跳表的基本概念

跳表是一种通过多级索引来加速查找的概率性数据结构。它可以在有序的链表上建立多级索引,每一级的元素个数是上一级的部分元素。

跳表的结构
  • 底层:一个普通的有序链表

  • 上层:多个索引层,元素的数量逐层减少

跳表的层高如何设置?

跳表的层高是动态确定的,通过 概率性算法 来决定:

  • 每个元素有一定概率升到上层

  • 理论上,跳表的层高通常是对数级别,平均层高约为 log N

为什么 Redis 选择跳表而非 B+ 树?

B+ 树 vs 跳表
  • B+ 树:结构更复杂,性能受限于树的平衡和节点管理

  • 跳表 :实现简单,且由于概率机制,跳表具有良好的 内存局部性 ,适合 内存存储 这种快速查找需求

Redis 选择 跳表 的原因:

  • 内存效率:跳表在内存中的实现比 B+ 树简单,且性能更好

  • 实现简洁:跳表的实现不需要复杂的树的平衡机制,增加了 Redis 的易用性和可维护性

  • 高并发:跳表适用于高并发场景,能高效处理大量数据的插入和查询

总结

  • Redis 提供了多种高效的数据结构,能够满足不同业务需求。
  • Zset 的底层实现,从最初的压缩列表到跳表,再到 Redis 7.0 的 ListPack,逐步提高了性能与内存效率。
  • Redis 选择 跳表 而非 B+ 树,因为跳表在内存中的实现更简单、高效,适合快速查找。

Redis 通过这些高效的数据结构,保证了它在高并发、高性能场景中的优势。

相关推荐
一个爱编程的人3 小时前
一个数是不是素数
数据结构·算法
忡黑梨3 小时前
eNSP_从直连到BGP全网互通
c语言·网络·数据结构·python·算法·网络安全
地球资源数据云4 小时前
1900-2023年中国物种分布点位矢量数据集
大数据·数据结构·数据库·数据仓库·人工智能
AI人工智能+电脑小能手4 小时前
【大白话说Java面试题】【Java基础篇】第20题:HashMap在计算index的时候,为什么要对数组长度做减1操作
java·开发语言·数据结构·后端·面试·哈希算法·hash-index
牢姐与蒯4 小时前
cpp数据结构之map
数据结构
IT界的老黄牛4 小时前
停电后 Redis 集群两节点起不来:fix 完还报 Bad file format?多部分 AOF 修复的正确姿势
运维·redis·缓存
故事和你914 小时前
洛谷-算法2-3-分治与倍增5
开发语言·数据结构·c++·算法·动态规划·图论
北顾笙9805 小时前
day37-数据结构力扣
数据结构·算法·leetcode
YaBingSec5 小时前
玄机网络安全靶场:Hadoop YARN ResourceManager 未授权 RCE WP
大数据·数据库·hadoop·redis·笔记·分布式·web安全
qq_40999093?5 小时前
NoSQL数据库解析:Redis
数据库·redis·nosql