阿里、蚂蚁、晟腾、中科加禾精彩分享 AI 基础设施洞见,现购票可享受 9 折优惠 |AICon 了解详情
写点什么

Chaperone:Uber 是如何对 Kafka 进行端到端审计的

  • 佚名

  • 2016-12-20
  • 本文字数:4235 字

    阅读完需:约 14 分钟

随着 Uber 业务规模不断增长,我们的系统也在持续不断地产生更多的事件、服务间的消息和日志。这些数据在得到处理之前需要经过 Kafka。那么我们的平台是如何实时地对这些数据进行审计的呢?

为了监控 Kafka 数据管道的健康状况并对流经 Kafka 的每个消息进行审计,我们完全依赖我们的审计系统 Chaperone。Chaperone 自 2016 年 1 月成为 Uber 的跨数据中心基础设施以来,每天处理万亿的消息量。下面我们会介绍它的工作原理,并说明我们为什么会构建 Chaperone。

Uber 的 Kafka 数据管道概览

Uber 的服务以双活的模式运行在多个数据中心。Apache Kafka 和 uReplicator 是连接 Uber 生态系统各个部分的消息总线。

截止 2016 年 11 月份,Uber 的 Kafka 数据管道概览。数据从两个数据中心聚合到一个 Kafka 集群上。

要让 Uber 的 Kafka 对下游的消费者做出即时响应是很困难的。为了保证吞吐量,我们尽可能地使用批次,并严重依赖异步处理。服务使用自家的客户端把消息发布到 Kafka 代理,代理把这些消息分批转发到本地的 Kafka 集群上。有些 Kafka 的主题会被本地集群直接消费,而剩下的大部分会跟来自其他数据中心的数据一起被组合到一个聚合 Kafka 集群上,我们使用 uReplicator 来完成这种面向大规模流或批处理的工作。

Uber 的 Kafka 数据管道可以分为四层,它们跨越了多个数据中心。Kafka 代理和它的客户端分别是第二层和第一层。它们被作为消息进入第三层的网关,也就是每个数据中心的本地 Kafka 集群。本地集群的部分数据会被复制到聚合集群,也就是数据管道的最后一层。

Kafka 数据管道的数据都会经过分批和确认(发送确认):

Kafka 数据管道的数据流经的路径概览。

Uber 的数据从代理客户端流向 Kafka 需要经过几个阶段:

  1. 应用程序通过调用代理客户端的 produce 方法向代理客户端发送消息。
  2. 代理客户端把收到的消息放到客户端的缓冲区中,并让方法调用返回。
  3. 代理客户端把缓冲区里的消息进行分批并发送到代理服务器端。
  4. 代理服务器把消息放到生产者缓冲区并对代理客户端进行确认。这时,消息批次已经被分好区,并根据不同的主题名称放在了相应的缓冲区里。
  5. 代理服务器对缓冲区里的消息进行分批并发送到本地 Kafka 服务器上。
  6. 本地 Kafka 服务器把消息追加到本地日志并对代理服务器进行确认(acks=1)。
  7. uReplicator 从本地 Kafka 服务器获取消息并发送到聚合服务器上。
  8. 聚合服务器把消息追加到本地日志并对 uReplicator 进行确认(acks=1)。

我们为了让 Kafka 支持高吞吐量,做出了一些权衡。数以千计的微服务使用 Kafka 来处理成百上千的并发业务流量(而且还在持续增长)会带来潜在的问题。Chaperone 的目标是在数据流经数据管道的每个阶段,能够抓住每个消息,统计一定时间段内的数据量,并尽早准确地检测出数据的丢失、延迟和重复情况。

Chaperone 概览

Chaperone 由四个组件组成:AuditLibrary、ChaperoneService、ChaperoneCollector 和 WebService。

Chaperone 架构:AuditLibrary、ChaperoneService、ChaperoneCollector 和 WebService,它们会收集数据,并进行相关计算,自动检测出丢失和延迟的数据,并展示审计结果。

AuditLibrary实现了审计算法,它会定时收集并打印统计时间窗。这个库被其它三个组件所依赖。它的输出模块是可插拔的(可以使用 Kafka、HTTP 等)。在代理客户端,审计度量指标被发送到 Kafka 代理。而在其它层,度量指标直接被发送到专门的 Kafka 主题上。

审计算法是 AuditLibrary 的核心,Chaperone 使用 10 分钟的滚动时间窗来持续不断地从每个主题收集消息。消息里的事件时间戳被用来决定该消息应该被放到哪个时间窗里。对于同一个时间窗内的消息,Chaperone 会计算它们的数量和 p99 延迟。Chaperone 会定时把每个时间窗的统计信息包装成审计消息发送到可插拔的后端,它们可能是 Kafka 代理或者之前提到的 Kafka 服务器。

Chaperone 根据消息的事件时间戳把消息聚合到滚动时间窗内。

审计消息里的 tier 字段很重要,通过它可以知道审计是在哪里发生的,也可以知道消息是否到达了某一个地方。通过比较一定时间段内不同层之间的消息数量,我们可以知道这段时间内所生成的消息是否被成功送达。

ChaperoneService是工作负载最高的一个组件,而且总是处在饥饿的状态。它消费 Kafka 的每一个消息并记录时间戳。ChaperoneService 是基于 uReplicator 的 HelixKafkaConsumer 构建的,这个消费者组件已经被证明比 Kafka 自带的消费者组件(Kafka 0.8.2)更可靠,也更好用。ChaperoneService 通过定时向特定的 Kafka 主题生成审计消息来记录状态。

ChaperoneCollector监听特定的 Kafka 主题,并获取所有的审计消息,然后把它们存到数据库。同时,它还会生产多个仪表盘:

Chaperone 创建的仪表盘,从上面我们看出数据的丢失情况。

从上图可以看出每个层的主题消息总量,它们是通过聚合所有数据中心的消息得出的。如果没有数据丢失,所有的线会完美地重合起来。如果层之间有数据丢失,那么线与线之间会出现裂缝。例如,从下图可以看出,Kafka 代理丢掉了一些消息,不过在之后的层里没有消息丢失。从仪表盘可以很容易地看出数据丢失的时间窗,从而可以采取相应的行动。

从仪表盘上还能看出消息的延迟情况,借此我们就能够知道消息的及时性以及它们是否在某些层发生了传输延迟。用户可以直接从这一个仪表盘上看出主题的健康状况,而无需去查看 Kafka 服务器或 uReplicator 的仪表盘:

Chaperone 提供一站式的仪表盘来查看每个数据中心的主题状态。

最后,WebService提供了 REST 接口来查询 Chaperone 收集到的度量指标。通过这些接口,我们可以准确地计算出数据丢失的数量。在知道了数据丢失的时间窗后,我们可以从 Chaperone 查到确切的数量:

Chaperone 的 Web 界面。

Chaperone 的两个设计目标

在设计 Chaperone 时,为了能够做到准确的审计,我们把注意力集中在两个必须完成的任务上:

1)每个消息只被审计一次

为了确保每个消息只被审计一次,ChaperoneService 使用了预写式日志(WAL)。ChaperoneService 每次在触发 Kafka 审计消息时,会往审计消息里添加一个 UUID。这个带有相关偏移量的消息在发送到 Kafka 之前被保存在 WAL 里。在得到 Kafka 的确认之后,WAL 里的消息被标记为已完成。如果 ChaperoneService 崩溃,在重启后它可以重新发送 WAL 里未被标记的审计消息,并定位到最近一次的审计偏移量,然后继续消费。WAL 确保了每个 Kafka 消息只被审计一次,而且每个审计消息至少会被发送一次。

接下来,ChaperoneCollector 使用 ChaperoneService 之前添加过的 UUID 来移除重复消息。有了 UUID 和 WAL,我们可以确保审计的一次性。在代理客户端和服务器端难以实现一次性保证,因为这样会给它们带来额外的开销。我们依赖它们的优雅关闭操作,这样它们的状态才会被冲刷出去。

2)在层间使用一致性的时间戳

因为 Chaperone 可以在多个层里看到相同的 Kafka 消息,所以为消息内嵌时间戳是很有必要的。如果没有这些时间戳,在计数时会发生时间错位。在 Uber,大部分发送到 Kafka 的数据要么使用 avro 风格的 schema 编码,要么使用 JSON 格式。对于使用 schema 编码的消息,可以直接获取时间戳。而对于 JSON 格式的消息,需要对 JSON 数据进行解码才能拿到时间戳。为了加快这个过程,我们实现了一个基于流的 JSON 消息解析器,这个解析器无需预先解码整个消息就可以扫描到时间戳。这个解析器用在 ChaperoneService 里是很高效的,不过对代理客户端和服务器来说仍然需要付出很高代价。所以在这两个层里,我们使用的是消息的处理时间戳。因为时间戳的不一致造成的层间计数差异可能会触发错误的数据丢失警告。我们正在着手解决时间戳不一致问题,之后也会把解决方案公布出来。

Chaperone 在 Uber 的两大用途

1. 检测数据丢失

在 Chaperone 之前,数据丢失的第一个征兆来自数据消费者,他们会出来抱怨数据的丢失情况。但是等他们出来抱怨已经为时已晚,而且我们无法知道是数据管道的哪一部分出现了问题。有了 Chaperone 之后,我们创建了一个用于检测丢失数据的作业,它会定时地从 Chaperone 拉取度量指标,并在层间的消息数量出现不一致时发出告警。告警包含了 Kafka 数据管道端到端的信息,从中可以看出那些管道组件的度量指标无法告诉我们的问题。检测作业会自动地发现新主题,并且你可以根据数据的重要性配置不同的告警规则和阈值。数据丢失的通知会通过多种通道发送出去,比如页式调度系统、企业聊天系统或者邮件系统,总之会很快地通知到你。

2. 在 Kafka 里通过偏移量之外的方式读取数据

我们生产环境的大部分集群仍然在使用 Kafka 0.8.x,这一版本的 Kafka 对从时间戳到偏移量的索引没有提供原生支持。于是我们在 Chaperone 里自己构建了这样的索引。这种索引可以用来做基于时间区间的查询,所以我们不仅限于使用 Kafka 的偏移量来读取数据,我们可以使用 Chaperone 提供的时间戳来读取数据。

Kafka 对数据的保留是有期限的,不过我们对消息进行了备份,并把消息的偏移量也原封不动地保存起来。借助 Chaperone 提供的索引,用户可以基于时间区间读取这些备份数据,而不是仅仅局限于 Kafka 现存的数据,而且使用的访问接口跟 Kafka 是一样的。有了这个特性,Kafka 用户可以通过检查任意时间段里的消息来对他们的服务进行问题诊断,在必要时可以回填消息。当下游系统的审计结果跟 Chaperone 出现不一致,我们可以把一些特定的消息导出来进行比较,以便定位问题的根源。

总结

我们构建了 Chaperone 来解决以下问题:

  • 是否有数据丢失?如果是,那么丢失了多少数据?它们是在数据管道的哪个地方丢失的?
  • 端到端的延迟是多少?如果有消息延迟,是从哪里开始的?
  • 是否有数据重复?

Chaperone 不仅仅告诉我们系统的健康情况,它还告诉我们是否有数据丢失。例如,在 Kafka 服务器返回非预期的错误时,uReplicator 会出现死循环,而此时 uReplicator 和 Kafka 都不会触发任何告警,不过我们的检测作业会很快地把问题暴露出来。

如果你想更多地了解 Chaperone,可以自己去探究。我们已经把 Chaperone 开源,它的源代码放在 Github 上。

查看英文原文: Introducing Chaperone:How Uber Engineering Audits Kafka End-To-End


感谢陈兴璐对本文的审校。

给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2016-12-20 18:004312
用户头像

发布了 322 篇内容, 共 134.2 次阅读, 收获喜欢 144 次。

关注

评论

发布
暂无评论
发现更多内容

Redis值Sentinel(哨兵)详述,图文并茂才能浅显易懂

李子捌

redis redis sentinel 签约计划第二季

签到功能怎么做?Bitmaps助你一臂之力

李子捌

redis bitmaps 签约计划第二季

27 K8S之服务发现

穿过生命散发芬芳

k8s 11月日更

面试官:GET能上传图片吗?

喵叔

11月日更

在线文本交集计算工具

入门小站

工具

Redis高可用的绝对的利器——持久化(RDB和AOF)

李子捌

redis redis持久化 签约计划第二季

比较 Flutter 日期选择器库【Flutter专题6】

坚果

flutter 签约计划第二季

Flutter 状态管理概述【Flutter 专题 7】

坚果

flutter 签约计划第二季

比特币的账户模型

Rayjun

比特币 区块链

数据库不能没有事务,今天他来了——Redis事务详述

李子捌

redis 事务 签约计划第二季

Flutter在各平台的安装与配置(Windows,macos,linux)【Flutter 专题 0】

坚果

flutter 签约计划第二季

linux双向重定向之tee命令

入门小站

Linux

新能源汽车发展的三种路线及差别

石云升

学习笔记 新能源汽车 11月日更

巧用代理设计模式(Proxy Design Pattern)改善前端图片加载体验

Jerry Wang

设计模式 web开发 代理模式 Proxy 11月日更

ES6, Angular, React 和 ABAP 中的 String Template(字符串模板)

Jerry Wang

JavaScript angular React abap 11月日更

Skip List(跳跃列表)它到底好在哪?今天我们不仅只聊为什么,还手写一个玩玩

李子捌

redis skiplist 签约计划第二季

在Flutter中构建图像选择器【Flutter专题9】

坚果

flutter 签约计划第二季

Redis的LRU(Least Recently Used)算法你了解多少?

李子捌

redis 签约计划第二季

都在用MQ,Redis的Pub/Sub也可以试着了解下

李子捌

redis MQ 签约计划第二季

Redis之Geospatial,助你轻松实现附近的xx功能

李子捌

redis geospatial 签约计划第二季

owasp zap 暴力破解测试

喀拉峻

网络安全 安全 信息安全

分布式系统的全局快照

ElvinYang

分布式系统 一致性 全局快照 Chandy-Lamport Flink ABS

Redis分布式锁就应该这样学,精细胞与卵细胞的故事告诉你真实原理!

李子捌

redis 分布式锁 签约计划第二季

LRU经常被吐槽,要不试试LFU?本文详述LFU(Least Frequently Used)

李子捌

redis 签约计划第二季

HyperLogLog这里面水很深,但是你必须趟一趟

李子捌

redis 签约计划第二季

听说你的服务经常被打崩?试试布隆过滤器(Bloom Filter)

李子捌

redis 布隆过滤器 签约计划第二季

Flutter 状态管理Provider快速指南【Flutter 专题 8】

坚果

flutter 签约计划第二季

金三银四面试必备,“全新”突击真题宝典,阿里腾讯字节都稳了

Geek_1df311

Java 程序员 架构 面试

Redis之主从复制详述,看完这篇文章不再稀里糊涂

李子捌

redis 主从复制 签约计划第二季

Redis集群模式,你若还是一知半解,试试仔细阅读一遍这篇文章

李子捌

redis redis cluster 签约计划第二季

阿里内部“SpringCloudAlibaba学习笔记”强势来袭,开创微服务的新时代

Geek_1df311

Java 编程 架构 微服务

Chaperone:Uber是如何对Kafka进行端到端审计的_语言 & 开发_InfoQ精选文章