当前位置:首页 > 文章列表 > 数据库 > Redis > Redis ZPOPMIN 怎样实现按分值取出任务

Redis ZPOPMIN 怎样实现按分值取出任务

来源:17golang原创 2026-10-26 21:04:36 0浏览 收藏

把任务 ID 作为有序集合成员、优先级作为分值写入 Redis,再执行 ZPOPMIN key count,即可按分值从小到大取出并移除任务。省略 count 时取一条;请求数量大于剩余数量时,只返回实际可取的成员。它适合“数值越小越优先”的领取模型。

ZPOPMIN 从 Redis 5.0 起提供。它把取最小成员和移除放在一条命令里,但返回任务不代表业务执行成功,也不会自动提供确认、重试或超时回收。本文给出原创可复现样例与性能记录方案,未执行命令或压测,不提供虚构耗时数据。

官方地址:https://redis.io/docs/latest/commands/zpopmin/

先定义排序口径和需要记录的基线

先约定分值含义:本例用 10、20、30 表示优先级,越小越先领取。任务 ID 使用独立标识,不把整个任务内容塞进成员字符串;业务载荷可以由应用根据 ID 查询自己的存储。

如果当前代码采用“先读最小成员,再单独删除”,基线至少记录每次领取的命令数、领取返回耗时、空结果比例和唯一领取的任务数。不要直接把命令吞吐量当成任务完成吞吐量:一个任务可能需要多条命令,任务处理器也可能耗时更长。

观察项记录口径本例状态
领取耗时请求发出至收到返回的 p50、p95、p99待在实际环境测量
批量产出每秒返回的唯一任务 ID 数待测
完成产出每秒成功完成的业务任务数待测
正确性重复领取、未完成、请求结果不明的数量需由任务记录统计

用独立样例确定最小分值任务

以下 Bash 命令要求已安装 redis-cli,连接独立实验 Redis。所有片段在同一 Shell 会话顺序运行。把键后缀改成自己的唯一标识,先确认不存在;若 EXISTS 不是 0,换键名,不删除碰巧遇到的其他数据。

# 仅使用自己独占的实验键
TASK_KEY='demo:article:zpopmin:my-unique-suffix'
redis-cli EXISTS "$TASK_KEY"
# 建立三项任务,任务编号和分值故意不按同一个顺序
redis-cli ZADD "$TASK_KEY" 30 task-alpha 10 task-beta 20 task-gamma
# 查看完整排序,仅用于演示,不代表已经领取任务
redis-cli ZRANGE "$TASK_KEY" 0 -1 WITHSCORES

按上述数据,排序预期为 task-beta(10)、task-gamma(20)、task-alpha(30)。ZADD 的成员是唯一的:同一个任务 ID 再次写入通常是更新分值,不会多生成一个副本。若每次投递必须是不同任务,就应由业务生成不同的任务 ID。

任务ID成员与优先级分值排序的静态数据关系图
静态数据关系说明图:任务 ID 是有序集合成员,分值定义优先级;相同分值还会受成员顺序影响。

分值相同时,有序集合按成员字节的字典序排序,不保证按提交先后。不要把 task-2 和 task-10 的文本顺序当成数字顺序。若必须满足同优先级 FIFO,需要额外定义稳定次序及其编码方式;简单复用同一个优先级数值不够。

用一次 ZPOPMIN 替代分开的读与删

# 一次领取最小分值的一条任务,返回成员与分值
redis-cli ZPOPMIN "$TASK_KEY"
# 继续最多领取两条,实际返回数量可能小于请求数量
redis-cli ZPOPMIN "$TASK_KEY" 2
# 此时在独占样例中已取空;不存在的集合也按无成员处理
redis-cli ZCARD "$TASK_KEY"
# 再领取不会等待新任务,应返回空集合结果
redis-cli ZPOPMIN "$TASK_KEY" 1

在三条初始化写入成功、没有其他读写干扰的前提下,第一次预期获得 task-beta,第二次预期获得 task-gamma、task-alpha。最后一项被弹出后键会被删除。具体客户端可能把返回值映射成带分值对象或数组,应使用客户端的正式返回类型,不能直接按终端排版拆字符串。

对同一主节点上的同一个集合,单次命令的取出与移除是一个原子操作。多个消费者竞争时,不能再用“两个客户端先读到了同一个最小 ID”的分步逻辑来解释 ZPOPMIN。若任务被重新入队、请求超时后重试或发生故障切换,业务仍可能遇到重复或结果不明;命令原子性不等于端到端恰好一次。

先 ZRANGE 后 ZREM 的两个独立命令不能直接作为正确的并发领取方案:在读与删之间存在竞争窗口。若旧方案已有事务或脚本,比较性能时要把它的完整协议计算进去,不能只数两条命令就声称已经得到等价对照。

按相同负载测量单条与批量领取

批量参数可以减少每个任务分摊的网络请求,但也会一次移除更多成员。设定 count 时先看处理器空闲并发数和可以承受的在途量,不要让一个进程取走大量暂时处理不了的任务。

# 重新放入演示任务,用来理解 count 只是最多领取数量
redis-cli ZADD "$TASK_KEY" 30 task-alpha 10 task-beta 20 task-gamma
# 请求五条,本例只有三条,因此预期只返回三条
redis-cli ZPOPMIN "$TASK_KEY" 5

正式测量时,在相同 Redis 版本、部署拓扑、连接数、任务 ID 大小和初始任务数量下,分别使用 count 为 1、10、50 的负载。每一轮重新准备等规模的独立数据;不能让第一轮把集合取空,后面的“更快结果”实际只是在测空响应。

长连接压测与逐次启动 redis-cli 的耗时不可混为一谈。后者还包含进程启动和建连成本。保持生产者补充策略一致,分别统计请求返回与任务执行两个阶段,并明确是否包含持久化、复制与网络距离带来的实际环境成本。

把预期结果与真实测量分开记录

这份样例能从命令定义推导领取顺序和数量,不能推导“性能提升几倍”。对于单条领取,原子 ZPOPMIN 需要一条 Redis 命令;使用 count=M 时,一次命令最多返回 M 项。官方复杂度为 O(log(N)×M),N 是集合大小,M 是实际弹出数量。少发请求不代表服务端处理工作量变成常数。

对照维度单条领取批量领取
每次最多拿走1 项count 项
分摊请求成本每项一次领取请求多项可共享一次请求
消费者崩溃的影响范围已取出的单项仍需恢复设计一批未完成项都需恢复设计
真实延迟与吞吐待测待测,结合在途量判断

结果记录应给出实际样本数、测量时长和环境,而不是只放一个最高吞吐值。出现错误或超时的请求要单列,不能丢掉它们以后再把剩余成功请求平均值当成完整结论。

明确失败恢复和延迟任务的边界

Redis原子领取命令与业务处理恢复职责边界图
静态职责说明图:ZPOPMIN 返回并移除成员,业务执行、结果记录和失败恢复仍由任务系统负责。

ZPOPMIN 会立即移除成员。如果进程拿到任务后崩溃,集合本身没有一条“等待确认”的记录可自动回退。不能在弹出后另外写一条处理中记录,就宣称已消除两个操作之间的故障空隙。需要可靠领取时,应另外设计原子的状态迁移、执行租约、幂等和恢复机制;这些不是一个 ZPOPMIN 参数能补齐的能力。

也不要把分值设为将来的执行时间后直接 ZPOPMIN,并以为它会等到时刻到来。它只取当前最小分值,不比较系统时间。BZPOPMIN 则在集合为空时等待成员出现,也不负责等待已有任务的时间分值到期。本文方案定位为按优先级立即领取。

空集合要一直循环调用吗?

可以由客户端退避轮询,避免空转;若需求是等待非空集合,可评估 BZPOPMIN,并给出符合服务退出要求的超时。它与本文非阻塞命令的返回协议也不同。

同一个任务为什么再次 ZADD 后数量没有增加?

有序集合成员唯一,相同 ID 对应同一成员。需要独立投递就生成独立 ID;只想首次入队时才新增,可按业务选择 ZADD NX,但它也不是任务完成后的永久去重记录。

为什么低优先级任务长期拿不到?

若一直有更小分值任务到来,固定排序可能造成饥饿。需要调整优先级模型或调度策略,不能从“每次最小”推导出对所有任务公平。

示例若中断后还留有数据,只清理本次独占键:

# 不操作其他键,不清空数据库
redis-cli DEL "$TASK_KEY"
unset TASK_KEY

技术依据:ZPOPMIN 官方文档、ZADD 官方文档、BZPOPMIN 官方文档。任务字段、示例数据和测量方案均为本文原创。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Redis XPENDING 怎样读取消费者组的空闲消息Redis XPENDING 怎样读取消费者组的空闲消息
上一篇
Redis XPENDING 怎样读取消费者组的空闲消息
Redis ZINTERSTORE 怎样计算多个集合的交集分值
下一篇
Redis ZINTERSTORE 怎样计算多个集合的交集分值
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    718次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    725次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    801次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    761次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    598次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码