当前位置: 首页 > news >正文

【Redis#9】其他数据结构

引言

Redis 除了我们最常用的 String、Hash、List、Set、ZSet(Sorted Set) 这五种基本数据结构外,还提供了很多高级或特殊用途的数据结构/类型 ,它们可以满足更复杂的业务需求。

✅ Redis 的“五大基本数据结构”回顾

类型特点
String字符串,可以是文本、数字、二进制等
Hash键值对集合,适合存储对象
List有序的字符串列表(底层为链表)
Set无序且不重复的字符串集合
ZSet (Sorted Set)带有分数排序的集合

一、Stream(流)

Redis 5.0 引入,是一个日志型数据结构 ,支持发布订阅、持久化、消费者组 等功能。

可以把 Redis Stream 想象成一个:持久化的、可查询的、支持消费者组的消息队列系统。 基于 Radix Tree + Listpacks(或称 ziplist) 实现的,具有高效写入和读取的能力。

1. Stream 的核心概念

概念说明
Stream存储事件记录的有序队列,每个记录都有唯一 ID
Entry / Message一条消息,包含多个字段(field-value 对)
Consumer Group消费者组,类似 Kafka 的 consumer group,用于多消费者协作消费
Consumer消费者,属于某个消费者组
Pending Entries List (PEL)记录已发给消费者但尚未确认的消息
Claim把未确认的消息重新分配给其他消费者

比如:我们可以用 Stream 实现一个事件,如下:消防员 + 着火事件

事件操作
着火事件Producer 使用XADD写入一条事件消息
消防员Consumer 属于某个消费者组,监听这个 Stream
发现火情Consumer 通过XREADGROUP接收到事件
使用干粉灭火器Consumer 执行业务逻辑(如写数据库、发通知)
确认火已灭Consumer 调用XACK确认事件处理完成
没火时等待使用BLOCK参数阻塞等待新事件到来

2. Stream 支持的功能📦

功能描述
📥 消息写入使用XADD命令添加新消息
📤 消息读取使用XRANGE,XREAD,XREADGROUP等命令读取消息
🔄 消费者组支持多个消费者组并行消费,避免重复消费
🧾 自动偏移量管理消费者组会自动维护消费进度(offset)
⏱️ 阻塞读取类似 BLPOP,使用XREADXREADGROUP COUNT ... BLOCK
🔁 消息重试机制可通过XCLAIM将失败的消息重新分发给其他消费者
🗑️ 消息过期可设置最大条数限制(MAXLEN)实现自动清理
🔐 持久化支持消息写入后会持久化到 AOF 和 RDB 中(如果启用)

3. 常用命令一览🛠️

命令用途
XADD key [MAXLEN ~ count] * field value [field value ...]添加消息
XRANGE key start end [COUNT count]查询指定范围内的消息
XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] id [id ...]从指定位置读取消息
XREADGROUP GROUP group consumer [COUNT count] [BLOCK ms] STREAMS key [key ...] IDLE [min-idle-time]以消费者组方式读取消息
XACK key group id [id ...]确认消息已被成功处理
XCLAIM key group consumer min-idle-time id [id ...]抢占未被确认的消息
XDEL key id [id ...]删除指定消息
XTRIM key MAXLEN ~ count控制 stream 的长度(保留最近的 count 条消息)
XGROUP CREATE key group-name $创建消费者组
XGROUP SETID key group new-id设置消费者组的起始读取位置
XGROUP DELGROUP key group删除消费者组
XINFO STREAM key查看 stream 的详细信息
XINFO GROUPS key查看所有消费者组
XINFO CONSUMERS key group查看某组下的所有消费者

4. 示例操作🔁

1️⃣ 添加消息
XADD mystream * name Alice age 30
# 输出
"1717986912345-0"
  • 每条消息都会有一个自动生成的 ID:<时间戳>-<序列号>
2️⃣ 查询所有消息
XRANGE mystream - +
# 输出
1) 1) "1717986912345-0"2) 1) "name"2) "Alice"3) "age"4) "30"
  • - 表示最小 ID,+ 表示最大 ID
3️⃣ 创建消费者组
XGROUP CREATE mystream mygroup $
  • $ 表示从最后一条消息之后开始消费
4️⃣ 以消费者组方式消费消息
XREADGROUP GROUP mygroup consumer1 COUNT 1 STREAMS mystream >
  • > 表示只读取未被该组消费过的消息
5️⃣ 确认消息已处理
XACK mystream mygroup 1717986912345-0
6️⃣ 查看未确认的消息
XPENDING mystream mygroup

5. 使用场景

场景描述
📬 消息队列替代 RabbitMQ、Kafka,适用于轻量级消息队列系统
📝 日志收集收集分布式系统的日志、事件、监控数据
📲 事件溯源(Event Sourcing)所有状态变更都作为事件流存储
🎮 游戏排行榜更新记录玩家得分变化事件
📊 实时数据分析接收实时数据流,进行聚合、分析
🚦 分布式任务调度多个 worker 协作处理任务流

二、Geospatial(地理位置)

Redis 3.2 引入,用于存储地理位置信息,并支持 距离计算、范围查询 等操作。

Geospatial(地理空间) 是指与地球表面位置相关的信息,通常包括:地理位置(经纬度)、地理对象(点、线、面)、空间关系(距离、包含、交集等)、时间维度(时空变化)

Geospatial 数据可以用于描述任何具有地理属性的事物,比如:城市的位置、道路网络、气象数据、移动设备轨迹、商店分布、用户当前位置

1. Geospatial 技术的核心组成部分🧭

组成部分描述
GIS(Geographic Information System)地理信息系统,用于采集、存储、分析和展示地理空间数据
GPS(Global Positioning System)全球定位系统,用于获取精确的地理位置坐标
RS(Remote Sensing)遥感技术,通过卫星或无人机获取地表信息
GEOJSON / KML / Shapefile常见的地理空间数据格式
地图服务(如 Google Maps、高德地图)提供可视化、导航、搜索等功能

2. Geospatial 应用场景

应用领域示例
物流配送实时追踪包裹位置、规划最优路径
共享出行显示附近车辆、计算距离、预估到达时间
智慧城市监控交通流量、管理公共设施、应急调度
零售行业分析门店周边人流、优化选址策略
农业精准施肥、病虫害监测、产量预测
环境监测追踪污染源、分析气候变化趋势
社交媒体发布带地理位置的内容、查找附近好友
游戏开发构建基于真实世界的 AR 游戏(如 Pokémon GO)

3. 在数据库中支持 Geospatial 的方式🔧

很多数据库都提供了对地理空间数据的支持,下面是一些常见的数据库及其功能:

3.1 Redis GEO

Redis 从 3.2 版本开始支持 GEO 功能 ,可以用来存储地理位置,并进行距离计算和范围查询。

示例

# 添加位置
GEOADD cities 116.4074 39.9042 "北京"
GEOADD cities 121.4737 31.2304 "上海"# 获取某城市的经纬度
GEOPOS cities 北京# 计算两地之间的距离
GEODIST cities 北京 上海 km# 查找附近的城市(500km 内)
GEORADIUS cities 116.4074 39.9042 500 km
  • Redis GEO 是基于 Sorted Set + GeoHash 实现的,适合轻量级 LBS(基于位置的服务)应用。
3.2 MySQL Spatial Data Types

MySQL 支持 POINT, LINESTRING, POLYGON 等空间类型,以及空间索引。

示例

CREATE TABLE locations (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(100),coord POINT SRID 4326
);INSERT INTO locations (name, coord)
VALUES ('北京', POINT(116.4074, 39.9042));-- 查询距离北京 500 公里以内的城市
SELECT name, ST_Distance(coord, POINT(116.4074, 39.9042)) AS distance
FROM locations
HAVING distance <= 500;

Geospatial(地理空间)是指与地球位置相关的数据和技术,广泛应用于地图服务、LBS、智慧交通、环境监测等多个领域。主流数据库(如 Redis、MySQL、PostgreSQL、MongoDB)都提供了对地理空间数据的支持,帮助开发者轻松实现位置查询、距离计算、区域划分等功能

三、HyperLogLog

HyperLogLog 是 Redis 提供的一种 概率数据结构(Probabilistic Data Structure) ,用于 高效估算一个集合中不重复元素的数量(基数,Cardinality)

✅ 它是用来做什么的? ==> 场景:你有一个巨大的数据集,想要知道其中有多少个唯一元素(如独立访问用户、IP 数量等),但又不想用 Set 存储所有元素。 【HyperLogLog 就是为此而生的!】

1. 核心特点🔍

特性描述
用途基数统计(去重计数)
空间效率极高最多占用 12KB 内存,可统计上亿个唯一元素
误差率可控默认误差小于 1%
不可获取具体元素只能统计数量,不能列出具体内容
支持合并操作多个 HLL 可以合并,进行全局统计

2. Redis 中 HyperLogLog 的常用命令📦

命令说明
PFADD key element [element ...]向指定的 HyperLogLog 中添加元素
PFCOUNT key [key ...]返回一个或多个 HyperLogLog 的基数估算值
PFMERGE dest source [source ...]将多个 HyperLogLog 合并为一个

3. 示例操作🔁

# 添加元素
PFADD visitors user1 user2 user3 user4 user5# 查看估计的独立访客数
PFCOUNT visitors
(integer) 5# 再添加一些新用户
PFADD visitors user6 user7 user3  # user3 已存在# 再次查看,user3 不会重复计数
PFCOUNT visitors
(integer) 7# 创建另一个 HyperLogLog
PFADD mobile_visitors user8 user9 user10# 合并两个 HyperLogLog
PFMERGE all_visitors visitors mobile_visitors# 查看合并后的总访问人数
PFCOUNT all_visitors
(integer) 10

4. 使用场景

场景描述
📊 网站 UV 统计每日/每月独立访客数统计(比使用 Set 节省内存百倍)
🌐 IP 去重计数统计攻击源 IP、访问来源 IP 的数量
👥 用户行为分析如“每日活跃用户数”、“不同设备登录数”等
📡 日志聚合在大数据平台中做轻量级实时统计
🧮 数据预处理预估去重数据规模,决定是否需要更精确的计算方式

5. 空间效率对比💾

数据结构存储1万个字符串所需内存存储100万个字符串所需内存
Set~几 MB几百 MB 到 1GB+
HyperLogLog最多 12KB始终是 12KB

Redis 的 HLL 实现使用了稀疏和密集两种存储格式,最终统一压缩为最多 12KB。

6. 注意事项⚠️

⚠️ 注意:它只是一个 近似算法 ,不能获取精确值。

问题建议
是否精确?❌ 否,是一个近似算法(误差 < 1%)
是否能查具体元素?❌ 否,只能统计数量
是否适合小数据集?✅ 也适合,但如果你要完全精确,还是用 Set 更好
是否支持合并?✅ 支持,这是其一大优势
是否支持持久化?✅ 是,写入 AOF 和 RDB

小结:HyperLogLog 是 Redis 提供的一个高效估算唯一元素数量的概率数据结构,非常适合用于大规模去重统计(如 UV、IP 数量等),仅需极小内存即可完成超大体量的数据估算,是大数据统计分析中的利器

四、Bitmaps(位图)

Redis 的 Bitmaps 并不是一种独立的数据结构 ,而是基于 String 类型 实现的一种高效操作二进制位(bit)的方式。

它非常适合用于:用户签到系统、日活统计(DAU)、布尔状态记录(如是否已读、是否登录等)、紧凑的去重计数

1. 核心特点

特性描述
存储方式基于 String,每个字符是 8 bit
操作粒度每个 bit 可单独设置、获取、统计
节省内存1 字节可表示 8 个布尔值,极大节省空间
支持位运算AND、OR、XOR、NOT 等
适用场景状态标记、签到、访问统计

2. 常用命令📦

命令说明
SETBIT key offset value设置某个 bit 位的值(0 或 1)
GETBIT key offset获取某个 bit 位的值
BITCOUNT key [start end]统计被设为 1 的 bit 数量
BITPOS key bit [start] [end]查找第一个值为指定 bit 的位置
BITOP operation destkey key [key ...]对多个 bitmap 做位运算(AND/OR/XOR/NOT)

3. 示例操作🔁

3.1 用户签到系统(一个月)
# 用户 ID 为 1001,表示他在第 0 天(1号)和第 7 天(8号)签到了
SETBIT user:1001:sign_in 0 1
SETBIT user:1001:sign_in 7 1# 查询某天是否签到
GETBIT user:1001:sign_in 0   # 返回 (integer) 1
GETBIT user:1001:sign_in 3   # 返回 (integer) 0# 统计总共签到几天
BITCOUNT user:1001:sign_in   # 返回 (integer) 2
3.2 统计日活跃用户(DAU)

假设你有 100,000 个用户,ID 从 0 到 99999。每天记录一个用户是否登录:

# 今天是 2025-04-05
SETBIT dau:20250405 1001 1   # 用户 1001 登录了
SETBIT dau:20250405 2002 1   # 用户 2002 登录了# 查询总登录人数
BITCOUNT dau:20250405        # 返回 (integer) 2
3.3 多日签到合并统计(BitOp)

你想知道用户 1001 在连续三天内的签到情况:

# 第一天签到
SETBIT user:1001:day1 0 1
SETBIT user:1001:day1 2 1# 第二天签到
SETBIT user:1001:day2 1 1
SETBIT user:1001:day2 2 1# 合并两天签到情况(按 OR 运算)
BITOP OR user:1001:total_sign user:1001:day1 user:1001:day2# 查看合并后的签到总数
BITCOUNT user:1001:total_sign   # 返回 (integer) 3 (0,1,2 都为 1)

4. 使用场景

场景描述
📅 用户签到系统每个 bit 表示一天是否签到
👥 日活跃用户统计(DAU)每个 bit 表示一个用户当天是否活跃
📮 已读消息标记记录用户是否阅读过某条消息
🎮 游戏成就系统每个 bit 表示一项成就是否完成
🧮 紧凑布尔状态存储替代多个 key,减少内存开销
📊 数据压缩用最少的空间表达大量布尔状态

5. 内存占用对比💾

数据类型1w 个布尔值所需内存100w 个布尔值所需内存
Hash / Set几 MB ~ 几十 MB几百 MB ~ 1GB+
Bitmaps1250 Bytes~124KB

💡 一个 BitMap 可以用 12KB 内存来表示超过 10 万个布尔值

⚠️ 注意事项

问题建议
是否精确✅ 是(无误差)
是否支持并发✅ 是(Redis 是单线程原子操作)
是否适合小数据集✅ 是
是否能查询具体哪些 bit 为 1❌ 否(只能统计数量或查找位置)
是否支持压缩✅ 是(Redis 内部做了优化)

小结:Redis Bitmaps 是一种基于 String 的高效位操作机制,非常适合用来做签到系统、日活统计、布尔状态管理等场景,仅需极小内存即可处理上百万级别的布尔状态,是 Redis 中非常实用的“隐藏神器”。

五、Bitfields

Bitfields 是 Redis 提供的一种高级数据结构,它允许你在 Redis 的 String 类型中操作二进制位(bit)的多个字段(field) 。它是对 BITFIELD 命令的支持,从 Redis 3.2 版本开始引入。

1. Bitfields 是什么?🧠

Redis 中的 String 是二进制安全的字节数组 ,一个 String 最多可以存储 512MB 的数据。而 BITFIELD 命令允许我们在这些字节中定义多个 “位字段”(bitfield) ,每个字段可以是:

  • 指定长度的 有符号整数(signed integer)
  • 或者无符号整数(unsigned integer)

我们可以对这些字段进行 读取、写入、增减等操作 ,非常适合用于紧凑的数据表示和高效的状态管理。

2. 使用场景

📅 用户签到系统用 1 bit 表示一天是否签到,365 天只需 46 字节
🎮 游戏角色状态存储角色属性、技能等级、成就等信息
📊 高频计数器精确控制字段大小,节省内存空间
🧮 位标志集合代替多个布尔值,减少 key 数量

3. BITFIELD 常用命令🛠️

3.1 定义并操作多个字段
BITFIELD key [GET type pos] [SET type pos val] [INCRBY type pos delta]

参数说明

  • type:字段类型,如:
    • u4 表示 4 位无符号整数(0 ~ 15)
    • i8 表示 8 位有符号整数(-128 ~ 127)
  • pos:字段起始的 bit 位置(从 0 开始)
  • val:要设置的值
  • delta:增量值
3.2 示例操作🔁

① 记录用户每月签到情况(31天)

# 设置第0天为已签到(1),第1天未签到(0)
BITFIELD user:1001:sign_in SET u1 0 1 SET u1 1 0# 查询第0天和第1天签到状态
BITFIELD user:1001:sign_in GET u1 0 GET u1 1# 输出
1) (integer) 1
2) (integer) 0

② 使用带符号整数操作计数器

# 设置第0位为 4 位有符号整数,初始值为 5
BITFIELD user:points SET i4 0 5# 查询该字段的值
BITFIELD user:points GET i4 0
(integer) 5# 增加 2
BITFIELD user:points INCRBY i4 0 2
(integer) 7# 减少 5
BITFIELD user:points INCRBY i4 0 -5
(integer) 2

③ 紧凑存储个状态字段

比如你想存储一个游戏角色的状态:

字段类型占用位数取值范围
HP(生命值)无符号10 bits0 ~ 1023
MP(魔法值)无符号8 bits0 ~ 255
状态标志有符号2 bits-2 ~ 1
# 初始化 HP=500, MP=200, 状态=-1
BITFIELD player:101 SET u10 0 500 SET u8 10 200 SET i2 18 -1# 查询所有字段
BITFIELD player:101 GET u10 0 GET u8 10 GET i2 18# 输出
1) (integer) 500
2) (integer) 200
3) (integer) -1

4. Bitfields 的优势

优点说明
💾 内存占用极低比多个 key 更节省内存
⚡ 高效访问所有操作都在一个 key 中完成
🧮 支持多种数据格式支持有符号/无符号整数
🔄 原子性操作支持原子增减,适合并发计数
🧩 结构灵活可自定义字段大小和偏移量

5. 注意事项⚠️

  • 所有操作都是基于 bit 级别 ,需要自己计算偏移位置。
  • 不支持直接删除某个字段,只能重置整个 key。
  • 如果字段超出范围,会自动截断(wrap around)或溢出。
  • 适用于内部状态存储,不适合频繁查询的业务逻辑。

结论:Redis 的 Bitfields 是一种强大的二进制字段操作工具,它允许你在字符串中按位定义多个字段,并对其进行读写、增减等操作,非常适合用来做状态管理、签到系统、紧凑计数器等高性能、低内存消耗的场景

六、Module 扩展模块

Redis 支持通过加载模块来扩展新的数据结构。例如:

📌 RedisJSON(JSON 数据结构)

  • 存储 JSON 格式数据
  • 支持 JSONPath 查询和修改字段
JSON.SET user:1001 $ '{"name":"Tom","age":25}'
JSON.GET user:1001 $.name

📌 RedisTimeSeries(时间序列数据库)

  • 高效存储和查询时间序列数据(如监控指标、传感器数据)
TS.CREATE temperature:1 LABELS sensor type temp
TS.ADD temperature:1 * 25.5
TS.RANGE temperature:1 0 -1

📌 其他常见模块

  • RedisGraph(图数据库)
  • RedisSearch(全文搜索 + 聚合)
  • RedisAI(机器学习模型部署)

在这里插入图片描述


文章转载自:

http://67v1SnVu.mwqbp.cn
http://e056E474.mwqbp.cn
http://9biclZta.mwqbp.cn
http://aAxVn3lB.mwqbp.cn
http://Zrqf7HhF.mwqbp.cn
http://50zrCIgG.mwqbp.cn
http://KZS4r4lS.mwqbp.cn
http://iNAWPVUR.mwqbp.cn
http://SHqt6X5B.mwqbp.cn
http://osMVw0Hz.mwqbp.cn
http://L70RDJxK.mwqbp.cn
http://3iw7kLfb.mwqbp.cn
http://3kI5iZCf.mwqbp.cn
http://n8NrYqDA.mwqbp.cn
http://NBzf1cNd.mwqbp.cn
http://HiSplEqM.mwqbp.cn
http://dljrjOOL.mwqbp.cn
http://qrF6k20J.mwqbp.cn
http://QAFfJ9A3.mwqbp.cn
http://OvdauEcl.mwqbp.cn
http://Xd1nYXjq.mwqbp.cn
http://D6eMk56M.mwqbp.cn
http://3NdZr5n0.mwqbp.cn
http://Jk3T9BGc.mwqbp.cn
http://hviuf0EH.mwqbp.cn
http://19kCJU02.mwqbp.cn
http://sHAqa3QS.mwqbp.cn
http://5gCnQBcN.mwqbp.cn
http://apGDXCI8.mwqbp.cn
http://vtGUqkEq.mwqbp.cn
http://www.dtcms.com/a/381367.html

相关文章:

  • C++使用拉玛努金公式计算π的值
  • 上海市2025CSP-J十连测Round 5卷后感
  • RDB/AOF------Redis两大持久化方法
  • 【图解】idea中快速查找maven冲突
  • Dubbo SPI机制
  • 《Linux 基础指令实战:新手入门的命令行操作核心教程(第一篇)》
  • 【开题答辩全过程】以 “饭否”食材搭配指南小程序的设计与实现为例,包含答辩的问题和答案
  • RabbitMQ 在实际开发中的应用场景与实现方案
  • 有没有什么办法能批量去除很多个PDF文件的水印
  • JavaScript 内存管理与常见泄漏排查(闭包、DOM 引用、定时器、全局变量)
  • ArkAnalyzer源码初步分析I——分析ts项目流程
  • Linux_基础指令(二)
  • 什么是子网?
  • 【前端】【utils】高效文件下载技术解析
  • FastAPI 中内省函数 inspect.signature() 作用
  • 【Linux】Linux进程概念(上)
  • 前端vue使用canvas封装图片标注功能,鼠标画矩形框,标注文字 包含下载标注之后的图片
  • 水库运行综合管理平台
  • langgraph astream使用详解
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(31):文法運用第9回3+(考え方11)
  • shell脚本练习:文件检查与拷贝
  • 书籍成长书籍文字#创业付费杂志《财新周刊》2025最新合集 更33期
  • 《AI游戏开发中的隐性困境:从战斗策略失效到音效错位的深度破局》
  • UVM寄存器模型与通道机制
  • 一个简单的GPU压力测试脚本-python版
  • Linux x86 stability和coredump
  • Claude-Flow AI协同开发:从“CTO”到“人机共生体”的AI协同开发
  • CPR_code
  • 【连接器专题】FPC连接器基础及连接器选型指南
  • 精准、可控、高一致性:谷歌Nano Banana正在终结AI“抽卡”时代