当前位置:首页 > 文章列表 > 数据库 > Redis > RedisTimeSeries TS.ADD 的 ON_DUPLICATE LAST 和 SUM 有什么区别

RedisTimeSeries TS.ADD 的 ON_DUPLICATE LAST 和 SUM 有什么区别

来源:17golang原创 2026-11-05 12:35:11 0浏览 收藏

我第一次遇到这个问题,是在补采一段 RedisTimeSeries 数据时发现某个时间点的数值突然翻倍。写入请求本身没有报错,时间戳也没有变化,真正改变结果的是重试请求里带了 ON_DUPLICATE SUM。如果这类重试代表“同一条采样再次送达”,应该覆盖旧值;如果每次上报代表一笔需要累计的增量,才应该相加。

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

一句话判断:ON_DUPLICATE LAST 把同一时间戳的新值当作修正版,覆盖原值;ON_DUPLICATE SUM 把新值当作同一时间戳下的新增量,与旧值相加。两者都只覆盖当前这一次 TS.ADD 调用,不会替你修改时间序列的长期配置。

一次重复上报为什么会影响整段指标

这类异常的影响面通常不在所有时间点,而只集中在重复写入的时间戳。设备采样、消息重放、网络重试和补数据脚本都可能把同一条记录送来两次。若原始采样是 10,重试请求又带着 12:

  • 用 LAST,这个时间点最终表达“最新一次收到的值”,结果是 12;
  • 用 SUM,这个时间点最终表达“两个值的累计”,结果是 22。

所以排查时不要只看命令是否成功,还要先回答:重复请求是同一采样的重放,还是两次应该累计的增量?这个业务含义决定策略。

RedisTimeSeries TS.ADD 输入、重复时间戳和 LAST、SUM 两种策略的静态关系图
图1:TS.ADD 重复时间戳的策略对照说明图,LAST 表示覆盖,SUM 表示累加,不是运行截图。

时间线里真正的触发条件:时间戳相同

TS.ADD 的时间戳以毫秒为单位,也可以使用 * 让服务端生成当前时间。只有两次采样落在同一个时间戳时,重复策略才会参与决定如何处理旧值。时间戳不同,就不是这篇文章讨论的重复点。

用两个独立的时间序列做对照,可以避免把前一个实验的结果混到后一个实验里:

# 固定一个毫秒时间戳,模拟同一条采样的首次写入
redis-cli TS.ADD meter:last 1710000000000 10

# 同一时间戳再次到达时,用新值覆盖旧值
redis-cli TS.ADD meter:last 1710000000000 12 ON_DUPLICATE LAST

# 读取这个时间点,观察 LAST 的最终值
redis-cli TS.RANGE meter:last 1710000000000 1710000000000

这个例子中,第二次写入表达“12 是这个采样点的修正版”,因此最终值应按 12 理解。这里的关键不是第二次请求更新了整条序列,而是它在同一个时间戳上覆盖了原来的样本。

根因对比:LAST 是替换,SUM 是累计

我后来把异常请求拆成两个最小场景:一个场景模拟设备重试,另一个场景模拟电量脉冲或订单件数这类增量。命令结构很像,但读数含义完全不同。

# 首次写入 10,准备一个可以被重试覆盖的采样点
redis-cli TS.ADD meter:last 1710000000000 10

# 重试带来修正值 12,LAST 只保留这次新值
redis-cli TS.ADD meter:last 1710000000000 12 ON_DUPLICATE LAST

# 首次写入 10,准备一个需要累加增量的采样点
redis-cli TS.ADD meter:sum 1710000000000 10

# 第二个请求代表新增 12,SUM 将旧值和新值相加
redis-cli TS.ADD meter:sum 1710000000000 12 ON_DUPLICATE SUM

# 分别读取两个点,确认比较的是业务语义而不是命令返回格式
redis-cli TS.RANGE meter:last 1710000000000 1710000000000
redis-cli TS.RANGE meter:sum 1710000000000 1710000000000

对这组输入,meter:last 的点应理解为 12,meter:sum 的点应理解为 22。官方命令语义也是如此:LAST 用新值覆盖,SUM 在已有样本时计算“旧值 + 新值”;如果该时间戳还没有旧样本,SUM 就直接使用新值。

这解释了故障的根因:把“重复送达”误判成“新增事件”,会让 SUM 在消息重试时重复计数;反过来,把本应累加的脉冲数据改成 LAST,又会丢掉前一次增量。

修复动作:把策略限制在当前一次 TS.ADD

ON_DUPLICATE 是一次命令级覆盖参数。它只影响当前这条 TS.ADD 如何处理同一时间戳的重复样本,不会把时间序列的长期重复策略永久改掉。这一点很适合修复边界明确的回放任务:你可以让一次补数任务使用 LAST,而不必把整个序列的后续写入逻辑一起改掉。

修复时我会先给数据源分类,再把策略写在调用点:

数据来源重复请求代表什么单次 TS.ADD 建议
设备心跳、周期采样同一采样的重试或重放ON_DUPLICATE LAST
补采脚本修正历史值人工确认后的新版本ON_DUPLICATE LAST
脉冲计数、订单件数增量应该合并的新增量ON_DUPLICATE SUM
无法确定的混合来源请求身份和业务含义不清先暂停自动累加,补齐来源字段

需要特别注意:如果命令同时负责创建一个不存在的时间序列,ON_DUPLICATE 对这次创建没有可比较的旧样本,因此不会产生覆盖或累加效果。真正的策略差异出现在目标时间序列已经存在、且目标时间戳已有样本时。

采样来源、时间戳、重试请求与 LAST、SUM 业务含义之间的静态边界
图2:重复上报修复边界说明图,帮助区分幂等覆盖和增量累计,不是终端或 Redis 控制台截图。

防复发:让重试和新增量在入口就分开

只替换命令参数还不够。下一次排查时,至少要保留采样来源、业务事件标识和采样时间戳,让读者能判断两个请求是不是同一条数据。对于可重试的采样上报,调用方应保持同一个时间戳和事件身份;对于累计事件,应该明确每次请求到底代表一个新事件还是同一个事件的重放。

  • 在日志中同时记录序列 key、时间戳、上报来源和选择的重复策略;
  • 把“消息重试”与“业务新增量”分成不同的写入路径,不要只靠调用方口头约定;
  • 修复历史数据前,先确认同一时间戳的旧值是否已经包含部分累计量;
  • 将 LAST 或 SUM 写入代码注释和接口文档,避免后续维护者把它当成可互换参数。

最后的判断

如果你面对的是“同一采样再次送达”,选 ON_DUPLICATE LAST;如果你面对的是“同一时间点还要合并一笔新发生的增量”,选 ON_DUPLICATE SUM。两者的命令形式几乎只差一个单词,但它们表达的是覆盖模型和累计模型的区别。发布修复前,先根据数据来源确认重复请求的业务含义,再把策略限定在需要它的那次 TS.ADD。

相关问题

ON_DUPLICATE SUM 第一次写入会不会把值加倍?

不会。指定时间戳没有旧样本时,SUM 使用新值;只有已有样本时才进行旧值与新值相加。

ON_DUPLICATE LAST 会修改整个时间序列的默认策略吗?

不会。它是当前命令的覆盖参数,文章讨论的范围只包括这一次 TS.ADD 的重复样本处理。

两个请求时间戳不同,还需要比较 LAST 和 SUM 吗?

如果时间戳不同,就不属于同一时间戳重复写入。此时应先检查采样时间是否被错误转换、截断或回退,再判断是否需要重复策略。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Pixi 怎么在 CI 中检查 pixi.lock 是否和项目配置同步Pixi 怎么在 CI 中检查 pixi.lock 是否和项目配置同步
上一篇
Pixi 怎么在 CI 中检查 pixi.lock 是否和项目配置同步
Pixi 怎么按 feature 建隔离环境并运行同一个项目任务
下一篇
Pixi 怎么按 feature 建隔离环境并运行同一个项目任务
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之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模型性能。
    893次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    894次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    978次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    966次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    793次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码