演讲:Netflix 集中式数据删除平台架构

TL;DR · AI 摘要
Netflix构建了集中式数据删除平台,通过编排多系统删除传播、控制Tombstone积累及建立持续审计循环,在保障分布式存储的持久性、可用性与正确性的同时,安全执行大规模数据删除且不影响线上流量。
核心要点
- 采用集中式平台编排跨异构数据存储的删除传播,避免单点误操作导致级联故障。
- 实施Tombstone生命周期管理与持续审计循环,防止删除标记堆积拖垮查询性能。
- 在CAP约束下设计删除机制,优先保证正确性与可用性,以自动化替代高风险人工rm命令。
结构提纲
按章节快速跳转。
误删与未删均带来高昂成本,需在分布式系统的持久性、可用性与正确性之间取得平衡。
单次rm -rf命令可导致生产环境数据丢失,凸显自动化安全删除平台的必要性。
通过统一编排层协调多数据存储删除,隔离业务流量并控制Tombstone累积速率。
建立可验证的审计循环确保删除合规性,降低工程师执行高危操作的心理负担。
思维导图
用一张图看清主题之间的关系。
查看大纲文本(无障碍 / 无 JS 友好)
- Netflix数据删除平台
- 核心挑战
- 误删vs未删成本
- CAP权衡
- 架构方案
- 集中式编排
- Tombstone治理
- 安全保障
- 持续审计循环
- 流量隔离
金句 / Highlights
值得收藏与分享的关键句。
误删和未删都有代价:前者引发事故,后者导致存储膨胀和客户信任流失。
在不影响线上流量的前提下,平衡持久性、可用性与正确性需要编排多系统删除传播。
深夜部署中一条rm -rf命令引发持续数天的级联影响,证明规模化下人工删除不可持续。
标题:Netflix 集中式数据删除平台的架构设计
URL 来源:https://www.infoq.com/presentations/architecting-deletion-system/
发布时间:2026-06-04T10:26:00+0000
Markdown 内容: [InfoQ 首页](https://www.infoq.com/ "InfoQ Homepage")[演讲](https://www.infoq.com/presentations "Presentations")Netflix 集中式数据删除平台的架构设计
观看演讲
播放速度:
下载
49:41
/presentations/architecting-deletion-system/en/slides/Doi-1780568171483.jpg)
摘要
演讲者探讨了在分布式数据存储中执行安全数据删除所面临的架构挑战。在平衡持久性、可用性与正确性的同时,他们阐述了如何编排跨系统的数据删除传播,且不影响线上流量。他们还分享了在控制墓碑记录(tombstone)累积、构建持续审计闭环以及通过集中式平台建立信任方面的经验教训。
讲师简介
Vidhya Arvind 是 Netflix 数据抽象平台的技术负责人兼创始架构师,此前曾就职于 Box 和 Verizon。Shawn Liu 是 Netflix 的高级软件工程师,致力于构建可靠且可扩展的系统,以支持大规模消费者数据生命周期管理。
关于大会
软件正在改变世界。QCon 旧金山站通过促进开发者社区的知识传播与创新来赋能软件开发。作为一场由从业者驱动的大会,QCon 专为那些在团队中推动创新的技术团队负责人、架构师、工程总监和项目经理而设计。
INFOQ 活动
/filters:no_upscale()/sponsorship/eventsnotice/34b23b6d-548d-473c-a609-ec2f8ca684b1/resources/1GuardsquareWebinarJune11-Transcripts-1777545596301.png)2026 年 6 月 11 日,美东时间上午 10 点
演讲者:Anton Baranenko - Guardsquare 产品经理
/filters:no_upscale()/sponsorship/eventsnotice/7dd71c7c-4b0e-4760-b97d-232ac1816637/resources/1NeuBirdWebinarJune25-Transcripts-1777458459989.png)2026 年 6 月 25 日,美东时间下午 1 点
#### 为自主可靠性而架构:将 AI 嵌入您的可观测性技术栈
演讲者:Justin Griffin - NeuBird AI 产品负责人
/filters:no_upscale()/sponsorship/eventsnotice/0b46c1f1-7263-457d-82d9-12be6fa07fbd/resources/1DatadogWebinarJuly9-Transcripts-1779204853394.png)2026 年 7 月 9 日,美东时间中午 12 点
#### AI 分析时代下的日志重思
演讲者:Nicolas Jung - Datadog 日志产品经理
演讲实录
Vidhya Arvind: 你有没有在执行完某个命令后瞬间感到恐慌?是的,我就有过这种经历。我紧接着执行的下一条命令是 pwd,因为我想确认自己到底在哪里执行了那个命令。试想一下,仅仅一条命令就可能酿成灾难,多年的生产数据瞬间化为乌有。这令人不寒而栗地提醒我们:必须严肃对待数据丢失和数据删除问题。现在,我想谈谈曾经发生的一起生产事故,带大家回顾一下当时的经过。那是一次深夜部署,一位工程师灌了大量咖啡,打算在非高峰时段对集群进行部署,当然,他还敲下了一个致命的命令:rm -rf。他本想删除所有内容,但按下回车键的那一刻,他突然意识到灾难即将降临,恐慌随之袭来。
由此引发的连锁反应,让他不得不在接下来的几天甚至几周里疲于应对。你在删除数据时是否有过安全感?我在删除数据时从未感到安心。误删和不删都会带来代价。误删是指发生了意外事故,你本无意删除任何数据,但它却发生了,现在你必须采取补救措施。而不删除数据同样有代价,包括存储成本以及客户信任度的流失。面对这两种情况,再加上关键系统数据库各自拥有五花八门的数据删除机制,实际上我们需要在持久性、可用性和正确性之间寻求平衡。而实现这种平衡往往伴随着人力成本。
这就是我在删除数据时的表情。在所有这些涉及数据丢失的事故中,都存在着隐性的人力成本。也就是说,你在与时间赛跑,内心隐藏着压力、愧疚和恐惧。你会不断回想:我怎样才能避免这次操作,或者如何撤销它?这场危机的核心在于思考:如何才能从根本上杜绝此类事件?能否在有人点击删除按钮之前设置一百道防护栏?数据删除绝不能是事后补救的措施,而必须经过深思熟虑的设计。我是 Vidhya Arvind,Netflix 的主任工程师。
Shawn Liu: 我是 Shawn,Netflix 的高级软件工程师。
安全删除的支柱——持久性
Vidhya Arvind: 首先,我想谈谈安全删除的三大支柱:持久性、可用性和正确性。持久性确保我们确实删除了数据,并且数据保持已删除状态,这一点至关重要。数据存储系统是如何删除数据的?思考这个问题时,你需要考虑几种不同的删除方式。你可以使用生存时间(TTL),即在数据库中设置 TTL;也可以执行硬删除,例如发出删除命令;或者像垃圾回收(GC)那样执行软删除,比如标记-清除算法。当你维护 Cassandra、EVCache、RDS、DynamoDB、Redis、Elasticsearch 等数据库时,你会发现所有这些系统的删除机制都大相径庭。每种操作都需要在性能、运维风险和成本之间进行权衡。
我们先来谈谈生存时间(TTL)。这是一种非常常见的操作。你在某些数据库中设置 TTL,当时间到期时,数据库会自动负责删除数据。Cassandra 原生支持 TTL,但它不会立即删除数据,而是保留数据直到 GC 宽限期结束,然后尝试通过压缩(compaction)来清除数据。在 DynamoDB 中,你可以为属性标记过期时间,随后系统会在后台执行相关任务。EVCache 是一种 LRU 缓存,它不会自动删除数据,而是采用惰性删除策略。Redis 也类似,它支持 TTL,并会定期在后台进行清理。而 Elasticsearch 和 RDS 都不支持原生 TTL。
你必须借助调度任务或标记-清除方法来实现删除。Elasticsearch 提供了生命周期管理功能供你使用。在所有这些场景中,共同点在于都依赖后台进程,如压缩、清理(vacuuming),或是你自己编写的用于删除数据的代码。那么,这些删除操作的成本是什么?删除的成本主要体现在:当压缩、清理或后台任务运行时,会产生资源消耗。如果要删除的数据量过大,会导致 CPU 成本上升和 CPU 使用率飙升。由于读取数据时需要同时读取墓碑记录(tombstones),延迟也会随之增加,甚至可能出现读取超时。此外,存储占用空间也可能因此增大。
接下来谈谈我之前提到的另一种删除类型:硬删除。也就是直接发出删除命令。同样地,每个系统的处理方式各不相同。在 Cassandra 中,当你发出删除指令时,实际上只是写入了一个标记。因为所有数据都是不可变的,系统仅写入一个标记,底层依然是墓碑记录。DynamoDB 则会立即删除数据。EVCache 虽然采用惰性求值的 LRU 缓存,但你的内存分片分配(slab allocation)并未释放,仍然保留在原处,需要某种合并操作来处理。Redis 的情况也非常相似,面对碎片化的内存,你需要某种合并流程。而在 Elasticsearch 中,段(segments)不会自动合并,它们会一直保留,直到后台进程介入处理。
RDS 同样需要进行清理操作。再次强调,并非所有系统都需要后台处理,但部分系统确实需要,且各自的风险也不尽相同。至于软删除,这属于应用层面的操作。你通过将某一列标记为“已删除”来标记数据,然后运行后台进程来实际删除这些数据。对于 Cassandra、Elasticsearch 和 RDS 而言,删除的隐性成本很高;而 DynamoDB 和 EVCache 等其他系统的成本则较低。任何操作都有成本,你必须认真评估这些代价。你能信任自动化程序来删除数据吗?我们通常希望将所有流程自动化,以便一劳永逸。
这就像推倒第一块多米诺骨牌,以为它会顺畅地传导到最后,删除所有相关资源,但你常常会发现自动化有时并不尽如人意。系统中还可能存在“幽灵”现象。你是否注意到系统中的这些幽灵?那些复活的数据、反复重现的残留数据、僵尸进程以及数据复活现象,都是需要重点关注的问题。我想分享上个月 Netflix 发生的一起事故。我们的 Cassandra 集群出现了一次配置错误,这个错误被忽视了,导致我们的进程超过 24 小时未能重启。当进程宕机超过 24 小时会发生什么?
GC 宽限期已过,本该被删除的数据却没有被删除。现在你重新启动节点——这是一次人为操作失误。当节点恢复后,数据又重新出现了。“幽灵”回来了。这引发了连锁反应:本应被删除的数据再次浮现。现在我们该怎么办?如何修复这些数据?首先你必须识别出这些数据。而让这个问题更加复杂的原因又是什么呢?
Shawn Liu: 最大的复杂性之一源于数据在不同系统间的复制与转换方式。例如,你可能将主 Cassandra 集群作为唯一事实来源(source of truth)。同样的数据可能在 Elasticsearch 中建立索引以支持搜索,在 EVCache 中缓存以实现快速访问,并存储在 S3 中用于备份或分析。所有这些仅仅是同一份底层数据的副本,存储在不同的位置以满足性能、冗余或分析等不同需求。真正的挑战出现在你需要删除数据的时候。当一条数据存在于系统中的众多位置时,删除它就不再是简单地从源端删除那么简单了。你必须确保删除操作传播到所有下游系统,无论是缓存、搜索索引还是数据库,不能留下任何残留副本。
这就引出了一个关键问题:我们是否真正清楚所有数据的存储位置,以及数据之间的关联和转换关系?随着系统规模的扩大和数据流日益复杂,追踪这一切变得愈发困难。在如此复杂的系统中删除数据,我们有哪些选择?一种选择是仅删除源端或根记录,而对其他地方的所有副本置之不理。但问题在于:如果你只删除了源端数据,却没有在所有下游系统中同步删除,最终就会产生悬空指针。
例如,当你从 Cassandra 集群中删除一条记录时,相同数据的副本可能仍然存在于 EVCache、S3、DynamoDB 和 Elasticsearch 中。虽然 LRU 缓存最终可能会自行淘汰这些过期数据,但 S3、DynamoDB 和 Elasticsearch 等其他系统会继续存储这些数据,从而导致不必要的存储成本。这意味着你不仅为无用的存储支付了费用,还留下了本应被删除的数据引用。更好的做法是不仅从源端删除数据,还要从所有下游系统中同步删除。也就是说,当你删除一条记录时,也应将删除操作异步传播到每一个副本,无论是缓存、搜索索引还是其他数据库。
这种扇出策略有助于确保系统中任何地方都不存在陈旧或孤立的数据。通过这种方式,你可以避免悬空指针并减少不必要的存储成本。这是一种更全面的方法,能够确保数据在所有位置都被真正删除。实际上,这正是我们在 Netflix 构建集中式数据删除系统时所采用的方法。接下来我们将深入探讨该系统的构建细节。
可用性
在正式讨论删除操作之前,还有一个关键方面需要强调,那就是可用性——即确保在执行删除操作期间系统依然安全稳定地运行。当我们考虑如何在删除过程中保持系统安全时,一个自然的问题随之而来:删除数据真的安全吗?当系统中积累了大量本应删除的数据时,这个问题尤为重要。这其中涉及哪些风险和挑战?以 Cassandra 中的批量删除为例。当发生批量删除时,会产生大量的墓碑标记(tombstone)。随后,当读取请求到来时,Cassandra 仍需扫描所有这些墓碑标记,以确认哪些记录实际上是有效的。
这些额外的工作会增加延迟并拖慢读取速度。在最坏的情况下,这会导致超时和服务级别目标(SLO)未达成,直接影响用户体验。在压缩(compaction)启动之前,清理工作尚未触发,因此系统会持续积累墓碑标记。一旦压缩开始,它将变得非常消耗资源,占用大量的 CPU、内存和 I/O 资源。如果这些操作没有得到良好控制,可能会影响关键的生产负载,导致系统在同时处理删除任务和常规流量时不堪重负,进而引发服务降级甚至中断。批量删除还可能引发压缩风暴。这在基于 LSM-tree 的数据存储系统(如 Cassandra)中尤为棘手。
当大量墓碑标记累积并同时触发压缩任务时,就会发生这种情况。这些进程会消耗大量资源,产生级联效应,可能导致整个集群不稳定。在压缩完成之前,这些墓碑标记仍驻留在磁盘上,因此待压缩的数据会产生持续的存储成本。总之,批量删除可能耗尽资源、拖慢读取速度、触发压缩墓碑和压缩风暴,造成级联效应,破坏系统稳定性并导致存储膨胀。这就是为什么我们需要极其谨慎地处理删除操作,以确保在执行删除期间系统仍能保持健康状态。
正如 Vidhya 之前提到的,删除操作伴随着隐性成本,后台进程可能引发资源争用和意外的性能问题。我们该如何缓解这些风险?以下是几种行之有效的技术手段。其一是分区级删除。逐行删除单条记录会产生大量开销并留下许多墓碑标记,这不仅增加了存储成本,也使数据管理更加复杂。相比之下,一次性删除整个分区要高效得多,因为它最大限度地减少了创建的墓碑标记数量,并使存储占用更易于管理。第二种技术是将删除操作分散执行,而不是让它们集中发生。你可以通过添加 TTL 抖动(jitter)来实现这一点,即为每个条目的过期时间引入一定的随机性。
如果将删除操作集中在一起,这些删除请求可能会在同一时刻导致资源使用量激增。相反,如果将删除操作分散到全天执行,就可以避免峰值出现,使系统保持平稳运行。这样你不会遭遇巨大的资源冲击,而是获得稳定、可控且易于管理的删除流量。你还可以利用资源利用率指标来控制删除的处理速度。例如,我们会监控数据存储、计算和存储的使用情况,并将这些信息提供给消费端应用。这些应用可以根据可用资源对请求进行优先级排序。低优先级的删除请求不必立即处理,我们可以将其延迟并异步执行。这有助于减轻系统压力,优先保障实时流量。
为了保护系统,对删除速率进行限流至关重要。我们通常从较低的速率开始,随着确信系统能够安全承载负载后再逐步提高速率。我们还会监控压缩和资源利用率等指标,根据需要动态调整速率。如果出现故障,我们会采用指数退避策略,避免压垮系统。这给了系统恢复的时间,有助于避免级联问题和中断。左图展示的是我们希望避免的失控行为;右图则是我们的目标:删除操作以可控、可管理的节奏平稳运行。
正确性
至此,我们已经讨论了持久性和可用性。现在让我们把注意力转向正确性,即确保我们的删除操作真正准确且完整。
Vidhya Arvind: 当系统中存在并发写入和竞态条件时,数据正确性尤为重要。在分布式系统中,这是一种常态。假设左侧的客户端 A 正在删除 ID 为 A 的记录,而右侧的客户端 B 正在插入同一条 ID 为 A 的记录。究竟哪个操作会生效?如果没有并发写入,我们自然能确定结果;但在并发写入场景下,系统内部必须进行冲突解决。业界采用了几种常见技术:最后是“最后写入者胜”(Last Write Wins),Cassandra 就采用了这种策略;其次是“条件写入”,RDS 和 Postgres 等系统使用了这种方式;还有一些系统如 EVCache,则采用“尽力而为”的冲突解决机制。
在这些情况下,系统的最终状态确实是未知的,但对于缓存来说这完全可以接受。只要设置了较短的 TTL(生存时间),数据很快就会过期。对于像 Cassandra 这样采用“最后写入者胜”策略的系统,建议在执行删除操作时带上时间戳选项。这里有一个例子:客户端 A 在 T1 时刻将 x 设为 1;随后客户端 B 在 T2 时刻将 x 设为 2;接着客户端 A 又在 T3 时刻将 x 设为 3。这三个操作都会发送到数据库。由于使用了时间戳,最终持久化的是 x=3,即最后一次写入数据库的值。在并发更新期间,对数据和写入操作进行去重至关重要,这样才能确保保留的是最新写入的数据。
幂等令牌是执行所有写入操作时非常关键的工具。什么是幂等令牌?在执行写入时,你需要为该次写入生成一个唯一的时间戳,并使用自动生成或随机生成的令牌,将其附加到每一个写入请求中。这为你提供了一道必要的安全防线,既保证了操作的顺序性,又允许我们对请求进行对冲处理和重试。幂等令牌对于保证数据正确性至关重要,尤其是在采用“最后写入者胜”策略的数据库中。那么,这些时间戳究竟应该在哪里生成呢?由数据库自身生成时间戳是否足够?实际上,当请求到达数据库时,操作的真实顺序已无法准确判断。只有客户端才清楚操作的先后顺序,因此时间戳应当在客户端生成。
建议直接使用客户端生成的时间戳,而不要依赖数据到达数据库时的时间。比较并设置(Compare-and-Set)是我们在这些操作中可以利用的另一种语义。例如,客户端 A 读取到“pending”状态后发起删除请求,同时客户端 B 也读取到相同的“pending”状态并发起删除请求。当这两个操作同时提交时,只有一个会成功,另一个则会被拒绝。最终结果是一个操作被成功应用。这种仅有一个操作生效的场景正是我们所期望的。在条件写入场景中,同样可以结合时间戳来使用。
如果系统中的数据未被删除,会有什么后果?我们的原则是“信任但验证”。虽然我们会为用户提供充足的信息以便其删除数据,但有时用户可能并未执行删除,或者数据因意外残留在系统中,这就需要我们进行审计和验证。Shawn 之前提到了从所有位置彻底删除数据的重要性。接下来我们将探讨如何在 Netflix 的集中式架构中实现这一目标。在数据删除的生命周期中,首先需要识别哪些数据需要删除以及它们存储在哪些位置,这就是我们的识别流程。随后,你需要对系统进行审计,确认这些数据是否确实应该被删除、是否出现了数据复活,或者其主记录来源(MRO)是什么。
接下来便是执行删除操作,且应以最优的方式进行。之后还需持续监控,防止数据复活等情况发生。首先我们来谈谈识别阶段。在识别数据时,需要从多个来源获取输入信息。数据所有者最清楚各个系统中存储了哪些数据,因此应利用自助服务机制来识别这些数据源。此外,还可以借助 Schema Registry 和注解来标记那些必须删除的关键数据。例如,我这里有一个 URI 指向包含敏感信息的数据集,其中 ID 字段包含客户 ID,我希望在实际客户注销时,能够删除与之相关的所有数据。下一步则是审计与验证。
Shawn Liu: 完成识别后,下一步就是审计与验证。下面我们来详细介绍具体的处理流程。首先从离线审计定时工作流说起。我们构建这些工作流旨在精确找出哪些数据可以被删除。具体流程如下:首先,我们将标识符表和数据表备份至 S3;然后,针对这些备份运行定时审计任务,通过匹配和验证来筛选出符合删除条件的数据;最后,将结果写入审计表,从而获得一份清晰完整的待删除数据清单。这种系统化的方法有助于确保我们删除的是正确的数据,避免遗漏。在确定了待删除内容后,便进入验证阶段。
在这一步骤中,我们会再次核查待删除数据列表的准确性和时效性。例如,可以使用测试用的标识符表来检查这些 ID 是否仍存在于数据表中。通过这样的验证与核对,我们确保所有标记为删除的数据都是准确无误的。随后,验证后的结果会被写入最终集合。考虑到备份可能是几小时前的,在此期间部分数据可能已被重新插入或恢复,验证任务也会将这些变更纳入考量,确保只有真正可以安全删除的数据才会进入最终集合。这一严谨的步骤有效保障了我们删除流程的安全性和有效性。
在完成数据的识别、审计和验证之后,我们终于可以在系统中执行删除操作了。让我们来看看这一过程在实际中是如何运作的。此时,审计和验证任务已经为我们提供了可删除数据的完整最终结果。接下来,我们的删除服务接管工作,无论是在 Cassandra、RDS 中,还是通过不同后端系统的删除端点,都会将数据移除。正如 Vidhya 之前提到的,不同的存储引擎表现各异,并可能带来各自的性能影响。我们在设计删除服务时充分考虑了这些因素。例如,如果数据库出现 CPU 或存储使用率激增,我们会自动退避,等待系统恢复正常后再继续执行删除操作。
这种方法有助于避免任何系统过载。我们还确保所有删除操作都记录在日志服务中,从而完整记录被删除的内容、发生时间以及执行删除的服务。这一过程通过 Kafka Topic 异步完成,因此不会拖慢主删除流程。通过这种谨慎且受控的流程,我们可以确保删除操作安全、高效地执行,并具备完整的可追溯性。
最后但同样重要的是,我们生命周期中的最后一个阶段是持续监控。发出删除指令并不意味着我们的工作就此结束。我们仍需持续监控系统,确保所有数据都按预期被删除。持续监控意味着我们定期运行审计周期,以捕获任何失败或未完成的删除操作。在上一个周期中未被删除的数据会在下一次审计中再次出现,并被重新加入删除队列。我们还跟踪关键指标,例如可删除记录的数量、数据超出保留窗口的时长、成功与失败删除的次数等。
这些指标帮助我们快速发现问题,并确保删除流程长期保持可靠。为了给用户提供更多控制和灵活性,我们还支持可插拔的删除接口。这在删除顺序至关重要或用户希望自行管理删除操作的场景中尤为有用。下面是一个可插拔删除接口在实际应用中的示例。您可以看到,用户可以指定自定义删除插件、回调 URL 和负载模板。这使得删除服务能够根据每种场景的最佳协议或逻辑,在不同系统中触发删除操作。这种方法使我们的删除框架具有高度可扩展性,能够满足不同团队和数据存储的多样化需求。
以下是我们删除架构的高层视图。一切始于控制平面,它负责触发审计任务。审计任务扫描标识表和数据表,以确定需要删除的数据。接着,验证任务确认已正确识别目标数据,并准备最终的待删除记录集。然后,删除服务接管工作,从相应系统中移除数据。此外,我们确保将所有删除操作及结果记录在日志服务中,以便拥有完整记录并在需要时进行恢复。该架构确保了我们的删除流程端到端的完整性、可靠性和可追溯性。在建立这一基础之后,下一步就是赢得客户的信任。
Vidhya Arvind: 在所有这些工作中,赢得客户信任是非常重要的一步,尤其是在集中化管理的情况下。没有人会轻易信任一个中央团队去删除他们的数据,因为数据对他们来说至关重要。我想举一个测试账号的例子:当您的设备在进行测试时,数据会从设备一路流经多个微服务,最终到达数据库。在这个例子中,测试账号的数据分布在账户数据库、用户资料数据库、回放系统和游戏系统中。这些数据扩散到了各处,遍布整个系统并随时间不断增长。您肯定不希望这些数据无休止地膨胀。
您需要验证这是一次有效的删除请求,然后执行删除。另一件要做的事是“信任但要验证”。您的客户可能会说:“我已经删除了数据,你们作为中央团队不要再去删我的数据。”当他们这样说时,虽然由您来删除数据是件好事,但也需要遵循“信任但要验证”的原则。审计任务帮助我们验证那些本应被删除的数据确实已被删除,而不是因为流程失败或系统 Bug 导致数据残留。您绝不会希望事后才发现这些问题。同时,在执行删除操作时,我们也需要可见性。您需要集中的仪表板,无论是在审计系统、确定待删除数据集,还是执行删除操作时,都能在一个集中的位置查看所有仪表板,并在每个步骤中监控系统状态。
为了赢得客户更多的信任,您需要一个强大的数据恢复系统。我们写入的日志可以帮助您在 30 天内恢复数据。无论如何,您也不能永久存储这些数据。这是一种低成本的存储方案,仅仅是日志而已。它可以存储在 S3 对象存储中,保留 30 天后过期。这能帮助您恢复数据。有了恢复机制,客户会更加信任您,因为一旦发现任何问题或 Bug,您都可以及时恢复数据。实时删除也有其自身的困境:在处理删除时,系统仍在进行实时的读写操作。传统的删除方式可能会拖慢系统性能。
你希望以缓慢、渐进的方式传播删除操作;你希望实施速率限制;你希望对所有删除操作进行统一编排;你还希望针对每个数据库采用各自的最佳实践。我们还能做得更好吗?当然可以。我们正在迈向一个具备最优优化策略的批量删除未来:我们的目标是将所有待删除的行(类似于墓碑标记)转换为 SSTable 格式的墓碑记录。以 Cassandra 为例,我们会生成 Cassandra SSTables,然后通过 Cassandra 的导入功能从 S3 下载这些文件并加载到 Cassandra 中,随即立即执行压缩以清除数据。这正是我们努力的方向,旨在降低数据摄入成本并提升整体性能。
经验教训
我们学到了哪些经验?首先,必须将数据识别和血缘追踪放在首位,明确所有数据的存储位置。应尽早完成识别工作,并建立一套能够记录血缘信息的系统。其次,要对系统进行审计。错误在所难免,数据可能会有残留,而在分布式系统中故障更是司空见惯。一旦发生故障,数据在系统中的留存时间往往会超出预期。信任但需验证。你需要将所有校验和恢复流程自动化,这样才能赢得客户的信任。此外,应采用事件驱动架构,避免人工干预,从而最大限度地减少对外部操作的依赖。
影响与洞察
Shawn Liu: 让我们先从成果谈起。我们已经能够在海量数据集中识别并管理删除操作。最重要的是,在整个过程中,我们未发生任何数据丢失事故。从下图中可以看到,随着使用率的提升,每日删除量也在稳步增长。即便在这样的增长态势下,系统依然保持稳定,删除任务持续安全、顺畅地运行。这充分证明,只要具备完善的防护机制和流程,即使在这种规模下,也能高效、安全且自信地执行大规模删除操作。基于上述成果,我想进一步强调我们工作的规模。我们已系统性地识别出平台上 1,300 个符合删除条件的数据集,并已完成其中 125 个数据集的审计工作。
我们正在积极跟踪和验证越来越多的数据存储,覆盖范围还在不断扩大。最终,我们在这些数据集中识别出了 768 亿行可删除数据。这些数字不仅体现了我们工作的庞大规模和我们所管理的数据体量,也凸显了建立一套强大的自动化流程来安全高效地处理删除任务的重要性。
谈完了这项工作带来的影响,接下来让我们探讨一些可以应用到您自身系统中的关键要点。以下是我们在实践中总结出的几条核心经验。第一,持续审计。即使有了自动化工作流,检查实际被删除的内容仍有助于及早发现问题,并保持对系统的信心。第二,构建集中式删除平台。这将提供清晰的可见性,简化故障排查,并确保操作的一致性。第三,针对不同系统灵活适配。每种存储引擎的行为各不相同,适用于 Cassandra 的方案未必适用于 RDS 或 S3,因此需要针对每个系统调整策略。第四,积极应用弹性技术,增强流程的容错能力。例如分散 TTL 设置、根据资源使用情况动态降速、实施速率限制以及利用负载削减机制,确保系统在高负载下依然稳定。第五,利用原生格式和工具优化批量删除,以减少开销并提升性能。最后,建立对删除流程的信任。一个可靠且可预测的流程能让所有人对整个端到端系统充满信心。当您将所有这些策略整合在一起时,就可以放心地推倒第一块多米诺骨牌,确信后续一切都会安全、顺畅地按计划进行。
问答环节
参会者 1: 我很好奇,在 Netflix,什么样的数据会被判定为可删除?另外,你们的删除量在很长一段时间内似乎一直维持在较高水平,这很有趣。这个数值最终会归零吗?
Vidhya Arvind: 是的,没错。您看到的是我们正在持续审计系统,但尚未覆盖所有系统。当我们纳入更多待审计的系统时,这些数字就会上升。当我们执行前向删除(即从今天起,凡进入系统的可删除数据都会被实时删除)时,删除量会呈现一条平稳的直线。而当我们通过批量加载完成历史积压数据的删除后,该数值便会归零。我们的目标是,在完成积压删除和前向删除之后,MRO 必须始终为零。至于什么是可删除数据,其实涵盖范围很广。主要是你在生产环境中运行的测试数据,这类数据往往会扩散到各处。因为你需要进行端到端测试,而且需要在生产系统中进行测试。
一旦发生这种情况,测试数据就会四处蔓延,这些都属于可删除数据。前任客户留下的任何数据,也是可删除数据。因系统故障未能成功删除的数据,同样是可删除数据。从全局集中视角来看,只要标识表认定某条数据为可删除,它就会被标记为可删除数据。
参会者 2: 我的问题是关于日志条目的,它的设计意图是什么?仅仅是记录被删除数据的日志,还是实际上捕获了详细信息,以便在发生误删时能够进行恢复?您提到有一个用于记录删除操作的日志,它是仅记录被删除项的键,还是包含完整详情?
Vidhya Arvind: 不,它会记录全部内容,因为恢复系统需要实际数据才能完成数据恢复。
参会者 2: 这样就能提供一种更有针对性的恢复方式,而不必从备份中恢复。
Vidhya Arvind: 是的,但我们将其存储在成本极低的 S3 系统中,每 PB 或 TB 的存储费用可能仅需一美元左右。这样我们就能降低 30 天的存储成本,同时仍然保留数据恢复的能力。通常任何问题都会在一周内显现出来,为了留有更多缓冲余地,我们将数据保留 30 天。
Shawn Liu: 此外,我们对日志表设置了严格的 TTL(生存时间),这限制了我们的恢复窗口,目前为一个月。您必须在一个月内发现问题,我们才能为您提供数据恢复服务。
参与者 3: 我想删除服务应该有一些经过精细调优的代码,以避免占用过多资源吧?
Vidhya Arvind: 我们会利用下游系统的反馈机制。例如,Cassandra 会向下游进程发送计算和存储利用率指标,我们可以据此进行监控并减缓删除操作的速度,这就是其工作原理。RDS、Cassandra 和 EVCache 都采用相同的机制。我们通过下游系统自身提供的利用率数据来感知其负载状态。
参与者 3: 我想知道这个资源消耗比例是全局统一应用的,还是由每个使用该服务的客户端单独定义的?
Vidhya Arvind: 这取决于具体的系统。我们在系统中预留了一定的缓冲空间。以 Cassandra 为例,我们通常在系统中预留 30% 的缓冲。当实时流量占用了这部分缓冲,导致利用率触及缓冲阈值时,我们就会减缓删除操作。毕竟这类删除任务并不紧急,无需立即执行。这些数据本就未被访问,一直静置在那里,本该被删除却因故残留了下来。比如测试数据,有时我们干脆就让它一直留在那里。在这些情况下,立即删除数据并不重要。我们可以等待时机,放慢删除速度,让其在低峰期悄然完成。
参与者 4: 关于审计任务,您提到有时相同的数据可能会被复制到不同的系统中。这些审计任务是独立检查每个系统,还是能够追踪数据在整个系统中的复制路径?
Vidhya Arvind: 我以 Cassandra 为例,因为它是我们规模最大的数据库集群,远超其他任何数据库。对于 Cassandra,我们将数据的备份副本存储在 S3 中。我们可以直接从 S3 读取文件并即时处理数据,从而获取审计结果。我们不进行在线审计,因为扫描全表查找待删除数据会影响系统性能,导致资源利用率飙升,还会消耗读取吞吐量等。在执行这些删除操作时,我们不希望以任何方式影响在线系统。
参与者 5: 我的问题关于你们的删除服务。假设调用删除服务请求删除 Cassandra 中的数据,但此时删除服务宕机了。这种情况你们如何处理?因为数据来源多样,且存储在 S3、Elasticsearch 等不同地方,如果删除服务不可用,你们如何进行回滚?
Shawn Liu: 这涉及两个方面。首先,我们有持续运行的审计机制。首次删除,特别是针对过期会员或测试数据的删除,无需在线处理或极速完成,我们可以在第二天补齐,下一个审计周期会覆盖遗漏的部分。其次,我们为不同的删除服务部署了独立的技术栈或集群。有一个直接删除服务运行在一系列实例上;我们还有一个异步技术栈,其中包含负责调用客户删除端点的删除服务实例。我们按分片进行管理,因此某个集群出现问题不会影响其他分片中的删除服务。
参与者 6: 你们的恢复系统如何将数据恢复到所有曾被删除的位置?这些日志记录维护在哪里?
Vidhya Arvind: 日志服务本身可以被视为一个时序数据库。它记录了时间戳以及发生删除操作的数据集信息。举个例子,如果有客户反馈说:“我看不到我的数据了,它本该在这里,昨天还在。”我们可以立即查询数据库,查看该数据是否存在于删除日志中。一旦确认数据在删除日志里,就说明发生了某种 Bug,且删除时间是已知的。通过比对时间戳,我们可以确定事件发生的范围,并回溯获取该时间段内发生的事件列表——所有这些删除操作都已记录在日志系统中。
如果尝试通过在线系统进行恢复,则必须重新执行插入命令。对于“最后写入优先”(Last Write Wins)策略,关键在于不能覆盖后续的插入操作。如果在删除数据之后又发生了新的插入,我们不能将恢复的数据置于该插入之前。我们会取原始时间戳并增加一毫秒,然后将恢复的数据插入其中,以确保较新的插入记录保持完整。这就是我们采用的冲突解决策略,适用于在线删除场景。而更高效的方式是离线批量恢复:生成一个包含所有需恢复数据的 SSTable,然后直接加载,这种方式速度更快。
查看更多带文字记录的演讲
录制于:

2026 年 6 月 4 日