日志能不能改?SLS LogStore 原生支持更新和删除了

简介: 随着日志承载的业务语义越来越多,数据订正、回填、清理等需求变得越来越常见。SLS 现已为 LogStore 提供原生 update/delete 能力——支持按 RowID 精确修改,按查询条件批量操作,类似计费调账、标签刷新、反馈回填等场景都可以直接在 LogStore 内完成闭环。

作者:无哲


引言:

我们是阿里云日志服务 SLS 团队。SLS 是阿里云上的一站式日志与可观测平台,每天承载着海量企业日志的采集、存储、查询、分析与投递。过去十几年里,写入 LogStore 的日志一直都是不可变的。但最近,我们给它加上了对已有数据的原生 update 和 delete 能力。今天想借这篇文章,聊聊我们为什么要做这件事,以及背后的设计取舍。


前言

“日志能不能改?”


过去十几年,SLS 的答案一直很明确:不能,也不应该。


因为 LogStore 的底层是 Append-only 的设计,写下去就是历史,这也是日志系统在性能、稳定性、审计可信上的核心优势。


那这次,我们为什么要给它加上修改和删除的能力?


要回答这个问题,我们首先回顾一下这些年来日志的发展历程,可以看到日志的用途一直在不断地被拓展。

第一阶段:日志是用来看的

最早的日志就是给人看的。服务出问题了,登上机器 tail -f 一下,grep 几个关键字,看看哪一行报错。到了集中式日志系统这一代,“看日志”这件事被搬到了浏览器里,但本质没变:日志的生命周期仍然很简单,写入、查阅,然后在过期后被清理。


这种使用方式给日志系统带来了一个非常清晰的设计前提:只追加,不修改


写入路径不需要锁,不需要版本对齐;存储布局天然按时间组织;下游消费者只要记录 offset,就能恢复消费进度。日志系统的高吞吐、低成本和稳定性,很大程度上都建立在这套规则之上。

第二阶段:日志是用来分析的

后来,日志开始被结构化、被索引、被查询分析。


SLS 也是在这一阶段不断补齐 SQL、SPL、聚合函数、机器学习算子、告警、仪表盘和投递消费等能力。日志不再只是排查问题时才会打开的文本,而是逐渐成为业务系统里的数据源。


风控系统订阅用户行为日志做实时规则匹配,监控系统基于网关日志计算 P99 和 QPS,安全团队在审计日志里做关联分析,BI 团队把交易日志聚合后喂给报表。


日志从“被人读”,变成了“被程序读”,持续进入分析、告警、报表和自动化消费链路。


但这一阶段仍然没有动摇 Append-only 的基础。写入路径依然是简单追加,只是在追加写之上增强了索引、计算和消费能力。SLS 要解决的问题,是让查询更快、分析更完整、订阅更顺畅,而不是去改变已经写入的数据本身。

第三阶段:“日志”承载了更多的业务场景

随着日志承载的业务语义越来越多,订正、回填、覆盖、清理这类过去很少出现在日志系统里的需求,也开始变得常见。


典型场景包括:


  • 计量计费明细按账期生成后,月底因为优惠、退款或调账需要修正部分记录;
  • AI Pipeline 产出的用户特征或内容标签,模型升级后需要对历史数据批量重算并覆盖旧结果;
  • 风控系统上线新版评分规则后,发现旧规则对部分用户的风险等级评估偏低,需要批量修正;
  • LLM / Agent 应用中的用户反馈、人工标注、质量评分等信息,通常在请求结束后延迟到达,需要回填至原始记录;
  • 采集配置错误、测试流量误入生产后,需要按条件定向清理。


过去遇到这些需求,用户通常需要通过软删重写、外部 KV / 数据库补充可变字段,或者追加新记录再让下游自行合并等方式处理。方案可以走通,但链路更长,维护成本更高,一致性也更难保证。


如果 LogStore 能够原生支持局部更新和删除,这类场景就可以在 LogStore 内部完成闭环,不必再绕道外部系统。

设计取舍

仔细看前面这些场景,数据主体仍然具备典型的日志特征:持续产生、写入量大、天然按时间组织,通常是半结构化的;同时又需要查询、分析、告警、报表,也需要被下游消费和投递。


而正是这些特征,让 LogStore 逐步形成了今天的能力组合:弹性容量、灵活 Schema、高吞吐追加写、低成本存储、强查询分析,以及完善的消费和投递生态。


现在多了局部更新的需求,但核心特征没有变:仍然是大量追加为主、少量修正为辅。


因此这次 LogStore 原生支持 update/delete,核心设计原则是:追加写仍然是主路径,修改与删除是面向已有数据的补充路径。

具体来说,体现在以下几个设计决策上。

1. 修改能力需要显式开启

只有在 LogStore 属性上设置 enableModify=true,才会启用修改与删除能力(开启后不支持再关闭)。


对于访问日志、审计日志、Trace 明细等不需要修改的数据,继续沿用 Append-only 模型即可。

2. 原始数据写入请求仍是 Append-Only

开启 enableModify=true 之后,新数据写入仍然是直接追加写,这意味着写入请求不会按某个业务主键去重,也不会自动覆盖已有记录。如果需要修改或删除已写入的数据,必须通过 update/delete 请求,显式地根据 __rowid__ 或查询条件执行。


这个设计确保了普通写入路径仍然保持高吞吐、低成本和稳定的消费语义


相应地,实时消费 LogHub 和投递任务也仍然基于原始写入流,不感知后续修改或删除。

3. 修改和删除同步可见

普通写入为了保证高性能,索引是准实时构建的,从日志写入到可查询之间可能存在极短延迟。由于普通写入遵循 Append-Only 语义,这不会影响写入顺序。


本次新增的修改和删除操作,则是同步生效的。也就是说,接口返回成功后,后续查询分析即可看到对应效果。


这对于连续局部更新尤其重要:前一次 update 返回成功后,后一次 update 可以确保基于前一次更新后的结果继续生效,从而避免“后一次更新是否看到了前一次更新”的语义歧义。

4. 查询体验不变

开启 enableModify=true 之后,查询分析仍然通过 Search、SQL、SPL 完成,使用方式没有变化。


被修改或删除的数据,会在后续查询分析中体现对应结果。对于使用 LogStore 做检索、分析、报表和管理后台的业务来说,原有查询链路不需要因为 update/delete 能力而重构。

能力形态

开启 enableModify=true 后,LogStore 提供两个维度的修改和删除能力:按 __rowid__ 定点操作单条记录;按查询条件批量操作一批记录。

RowID:行级寻址标识

开启 enableModify=true 后,每条日志会被分配一个稳定的内部行标识 __rowid__。用户通过 Search、SQL 或 SPL 查询拿到 __rowid__,再用它精确指定要修改或删除哪一条。


需要注意的是,__rowid__ 是 LogStore 内部用于行寻址的标识,并不是业务主键,也不是数据库里的 primary key。它仅用于定位已经存在的记录,不能用于“按 ID 插入”或“按 ID 覆盖写入”。


因此,基于 __rowid__ 的操作更适合“先查后改”的场景。例如管理后台查出一批记录,用户选中其中一条,然后按 __rowid__ 精确回写。

按查询条件操作:用业务字段批量修正

如果希望按 request_idbatch_idorder_idtrace_id 等业务字段操作,可以使用按查询条件更新或删除的方式。


调用方只需要指定时间范围和 query 表达式,命中范围内的记录就会被一次性更新或删除。这种方式不需要先查询 __rowid__,只要能够用查询语句描述清楚“哪些记录需要改”,就可以直接发起操作。


需要注意的是,按查询条件操作依赖查询条件命中数据。由于普通写入后的索引构建是异步的,通常需要等数据可查询后再执行修改或删除,因此它不适合“写完立即改”的场景。


另外,单次按查询条件的修改或删除最多命中 1 万行。实际使用中,建议按照业务维度拆分任务,例如按账期、按 batch、按用户、按实例或按时间窗口分批执行,避免一次操作范围过大。

典型场景

综合来看,适合在 LogStore 上使用 update/delete 的业务场景,通常具备以下特征:


  • 数据有典型的日志特征。 持续产生、规模大、以追加写为主,需要检索和分析,同时存在相对低频的修正、回填或清理需求;
  • 修改和写入之间有自然的时间间隔。 比如用户反馈延迟到达、模型按版本重算、月底账期调整;
  • 每次修改的范围相对可控。request_id、按批次、按账期,命中范围天然有限。

下面看几个典型场景。

风控营销:规则升级后的历史标签刷新

以风控场景为例,每笔交易写入 LogStore 时,可能会带上当时模型计算出的风险等级。风控团队上线新版评分规则后,如果发现旧规则对部分交易的风险评估偏低,就需要用新版逻辑刷新一批历史标签。


例如,把近 7 天某个商户的 risk_levelmedium 订正为 high,让下游审核队列、风险看板和报表立刻反映新口径。

client.update_logs(
    project="risk",
    logstore="transactions",
    from_time=seven_days_ago,
    to_time=now,
    query='merchant_id: "M-2049" and risk_level: "medium"',
    log_item={
        "risk_level": "high",
        "risk_model_version": "v3.2",
        "re_evaluated_at": now,
    },
)

类似场景还包括营销渠道归因调整、实验分组策略修复、报表口径字段刷新、内容标签或用户画像重算。它们的共同点是:规则升级了,历史结果也需要跟着刷新。

计量计费:账期结算后的明细修正

计量计费明细按账期持续生成、写入 LogStore 用于汇总和对账。月底结算时,因为优惠核销、退款、客户协商或人工调账,可能需要修正部分记录。


这类场景天然适合 update/delete:调账通常发生在账期结束之后,写入和修改之间有明显时间间隔;修正范围也可以通过账期、用户 ID、实例 ID 等字段圈定,边界清晰。

例如,可以按 billing_period="2026-05"instance_id="inst_8821" 圈定一批记录,只更新 amountadjust_reasonadjusted_at 等字段。


调账结果直接体现在原始明细上,下游报表、汇总账单和审计查询自动看到修正后的数据。

LLM / Agent:延迟反馈的字段回填

LLM / Agent 应用的一次请求会产生大量过程数据。其中,执行明细,比如每个 step、每次 tool call,适合继续保持 Append-Only;但请求结束后延迟到达的信息,很适合回填到原始请求记录上。


这类信息包括用户点赞点踩、运营 badcase 标注、离线质量评分、人工审核结论等。


调用方式与前面类似,按 request_id + 时间范围定位到原始请求记录,将反馈字段回填上去即可。这样 Trace 详情仍然按 trace_id 聚合执行明细,反馈分析和质量评估可以直接查询请求记录上的字段。

运维/管理界面:指定行记录的精确修改

有些场景下,修改是由人在界面上触发的——客服在工单系统里把订单状态从“待处理”改为“已联系”、数据管理员查看采集到的标注数据并修正某条错误标签、运营在 badcase 管理后台对某条 LLM / Agent 请求补充审核意见。


这类操作的典型流程是“先查后改”:界面通过 query 查出一批记录,这些记录里都会带有唯一的 __rowid__;用户选中其中一条修改后,保存时按 __rowid__ 精确定位回写。

# 用户选中某条记录修改后,按 __rowid__ 精确回写
client.update_logs(
    project="ops",
    logstore="work-orders",
    rowid="1|1048576|63",   # 从查询结果中拿到的 __rowid__
    log_item={
        "status": "contacted",
        "handler": "alice",
        "handled_at": now,
    },
)

这种方式适合单条人工修正、审核回写、后台管理操作等场景。相比按业务字段重新圈定条件,__rowid__ 可以精确定位用户在界面上看到的那一条记录。

写在最后

回到最开始的问题:日志能不能改?


如果是传统意义上的运维日志——系统跑了什么、什么时候出了错——答案仍然是不应该改,不可变性本身就是它的价值。


但今天 LogStore 承载的远不止这些。越来越多的业务数据以日志的形态持续产生,它们需要 LogStore 的弹性、检索、分析和消费投递能力,同时又会在业务流程中产生回填、订正或清理需求。


对这类数据,原生的 update/delete 提供了一条直接的路径——不用再绕道外部系统,也不用牺牲 LogStore 本身的优势。

如果您的需求符合前面描述的特征,可以为您的 LogStore 开启 enableModify=true,解锁更多的场景可能。


具体开通方式、API 参数、限制清单与计费说明,请参考官方文档《修改与删除日志数据》:https://help.aliyun.com/zh/sls/modifying-and-deleting-log-data

如果您在使用过程中有任何疑问,欢迎提交工单咨询!

相关文章
|
15天前
|
数据采集 人工智能 搜索推荐
企业智能体的下半场,如何让智能体越用越聪明?
AgentLoop 正在邀测期,点击申请邀测资格。
316 127
|
20天前
|
人工智能 运维 安全
阿里云 Agent Infra 上长出的约束基建
Harness = 定义约束 + 校验输出 + 建立反馈回路。
299 125
|
27天前
|
存储 消息中间件 人工智能
阿里云 OSS 发布 Table Bucket,对象、向量、表格三合一,打造 AI Native 的多模态数据存储统一底座
阿里云 OSS 推出T able Bucket,集成 Apache Iceberg 语义,高效管理海量结构化数据。与对象桶、向量桶协同,构建覆盖非结构化、向量、结构化数据的多模态统一存储底座,支持零改造迁移、实时入湖与跨引擎分析,助力 AI Agent 时代数据高效治理。
538 121
|
7天前
|
消息中间件 存储 Kafka
Kafka 原生消息入湖能力上线!一键打通实时流与数据湖
阿里云消息队列 Kafka 版正式上线原生消息入湖能力。
291 125
|
14天前
|
人工智能 监控 前端开发
Electron 监控:让桌面 Agent 监控触手可及
一行代码实现Electron桌面端全景监控,自动还原崩溃现场、预警内存泄漏、全链路追踪、 SSE流式响应与交互埋点,让 AI 助手运行状态清晰可见,助力快速恢复稳定与流畅。
274 129
|
7天前
|
人工智能 运维 自然语言处理
「Agent 友好」的可观测:阿里云发布观测与智能运维 Skills
开发者只需在 Qoder 等 Agent 客户端中发出一句自然语言指令。借助云监控与STAROps Skill,Agent 即可自主完成数据接入、告警配置、根因诊断,并联动研发工具链完成代码修复与发布。
313 125
|
14天前
|
消息中间件 人工智能 Kafka
AI 时代,实时入湖正在告别 ETL:从 Kafka 到 Iceberg 的架构减法
本文围绕“零 ETL”这一趋势,讨论流数据入湖为什么需要做架构减法,并结合 Kafka × Table Bucket 的实践,分析一种将通用入湖能力前移到消息与表存储链路中的方案,如何在降低复杂度的同时,兼顾实时性、一致性、Schema 演进、CDC 语义与开放生态兼容。
288 130
|
7天前
|
人工智能 安全 Cloud Native
Higress 新发布:AI Gateway 能力增强,Gateway API 及其推理扩展持续打磨
增强 AI 网关能力,持续打磨 Gateway API 及其推理扩展。
360 127
|
20天前
|
人工智能 弹性计算 JSON
基础设施到 Agent 体验丨从 Claude Fable 5 看安全护栏的演进
安全护栏被 Claude Fable 5 推向前台,也许会被应用于更加广泛的场景。你平时感受不到它,但当它生效的时候,它会告诉你。这将是护栏最好的状态。
302 124
|
19天前
|
监控 网络协议 Go
装在内核里的透视镜:云监控 2.0 不改一行代码实现全栈可观测
基于Opentelemetry 无侵入探针,无需改代码、跨语言自动产出符合 OTel 标准的 trace 与 metrics。覆盖 HTTP、gRPC、MySQL、Redis、Kafka、CUDA 等 15+ 协议,并原生支持 OpenAI、通义千问等 GenAI 调用追踪,在云监控2.0 实现可以实现一键接入使用。
425 133