详解最小化 Kafka 到 ClickHouse 延迟的原理和方法

图片

本文字数:4801;估计阅读时间:13 分钟

审校:大平

本文在公众号【ClickHouseInc】首发

图片

引言

ClickHouse 博客上的很多话题都是由社区参与的公共讨论引起的,诸如 Slack 频道等。随着最近我们正式发布了官方 Kafka 连接器,及其在 Confluent Cloud 中的支持,已经有人联系到我们:咨询将数据从 Kafka 传输到 ClickHouse Cloud 时应该怎么考虑,如何缩短同步的延迟。这是一个很好的讨论话题,我们已经将对这个问题的回答,整理成为本文 - 让我们详细讨论一下吧!

Kafka 连接器是如何工作的?

首先,让我们先分析一下 Kafka 与 ClickHouse 之间的连接是如何工作的(以及我们的连接器在其中的位置)。一个示例的数据流可能如下所示:

图片

从本质上说,生产者将数据提交到主题(A),这些主题由“Kafka Connect”通过轮询(B)获取并发送到连接器,然后连接器将记录推送到 ClickHouse(C)。在上图中,A 与 B独立 ,B 与 C独立  - 它们是三个不同的系统,彼此之间有网络连接。

当然,实现可能会有所不同,但现在我们将讨论这个最普遍的示例设置,以便涵盖大多数的使用场景 - 如果您的设置没有以上涉及到的组件,请随意忽略没有的部分。

什么是延迟?

这可能很显而易见,但值得重复定义它:延迟(在本文中)是数据从点 A 传送到点 B 所花费的时间。它会受到各种因素的影响,最常见的是硬件、软件和网络。

硬件因素通常是导致延迟的物理限制 - 虚拟机大小、处理器速度等。我们将这些留给读者来解决,并专注于连接器的本身,以及它可以控制的变量。

软件因素通常是:设计的限制,而不是物理问题 - 线程数量、数据结构、配置方式等。它们也很常见,并且是本文的大部分内容要重点讨论的。

网络因素通常是节点之间的物理网络、虚拟机之间的虚拟连接、客户端到服务器的距离等。

什么时候延迟会成为一个问题?

在我们深入探讨延迟是怎样产生的之前,简要的讨论一下“何时”和“为什么”也很重要,“我为什么要关心延迟?延迟在什么时候会导致问题的发生?”

在您的用例方面,您才是专家,但我们会提醒您,不要对延迟设定不切实际的期望 - 我们很容易过度的关注延迟的细微改变,其实这些差异不太可能对业务产生重大的影响,例如即使有一两秒的偏差也会导致告警。请记住,在分布式的网络环境中,会存在着一定程度的延迟 - 我们的工作方向是:在尽可能的情况下,更多的是去减轻/稳定延迟,而不是完全消除它。理想情况下,您应该能够确定:多少的延迟是可接受的,并将其保持在一个预定义的范围内 - 这可能是通过 SLA 来管理的。

同样,一个用例可能会比另一个用例容忍更多的延迟 - 如果您是每周分析一次数据,那么这与实时分析数据相比,可能会容忍更多的延迟。即使对于实时分析,“实时”意味着什么?那也是必须有您来决定的 - 再次,在您的用例方面,您才是专家;只要记住:硬件/软件/网络限制等因素都会导致延迟。

该如何测量延迟?

为了确定您的 Kafka 管道中是否存在延迟问题,您需要能测量延迟。

最简单的方法是:在 Kafka 管道的各个点上,将时间戳值追加到消息中。这样在后续,就可以进行比较和可视化,以分析出可能导致延迟的步骤。

我们见过的实现这个目标①真正有效的方法是:使用单消息转换器:

图片

① 有多种可用的选项,例如 JMX,但我们发现 SMT 已经足够好 - YMMV

此转换(transform)采用了多个开箱即用的字段(偏移量、分区、时间戳和主题),并将它们添加到了连接器要传递给 ClickHouse 的对象中,而无需更改消息的生产者。可以将此转换器配置在各个运行的步骤上,这样用户就可以推理出延迟发生在处理管道的哪个部分。

图片

上述转换可以让我们在 Kafka 管道的不同阶段记录耗时。我们还可以记录确切的消息插入 ClickHouse 的时间,作为行的时间点。这可以通过使用 DEFAULT 表达式插入时间戳来实现,然后还可以将其与转换器添加的早期时间戳进行比较:

CREATE TABLE data_testing
(
  `raw` String,
  `generationTimestamp` DateTime64(3),
  `insertTime` DateTime64(3) DEFAULT now()
)
ENGINE = MergeTree
ORDER BY insertTime

注意,我们正在使用“DEFAULT now()”,来让 ClickHouse 生成时间戳,而不是包含在消息本身中 - 这将为我们提供插入的时间。

如果您的消息有生成时间戳,您还可以跟踪以下时间点之间的关系:消息生成 <-> Kafka 插入 <-> ClickHouse 插入。

如何可视化延迟?

常见的可视化延迟的方法是:使用 ClickHouse SQL 控制台(ClickHouse Cloud 上)所提供的内置表:

图片

此图的数据是由一个相当简单的查询创建的,用于计算中位数、第 75 个百分位和第 99 个百分位:

SELECT formatDateTime(insertTime, '%F %k:%i') as byMinutes,
    median(dateDiff('second', generationTimestamp, insertTime)) AS median,
    median(.75)(dateDiff('second', generationTimestamp, insertTime)) AS p_75,
    median(.95)(dateDiff('second', generationTimestamp, insertTime)) AS p_95
FROM default.kafka_data
WHERE insertTime > now() - interval 60 MINUTE
GROUP BY byMinutes
ORDER BY byMinutes ASCENDING

InsertTime 由默认列(前面使用“now()”提到)提供,而 generationTimestamp 是我们生成数据时设置的列 - 您也可以轻松地使用类似于 kafkaField (前面提到的是由转换器创建的)的东西。

注意:示例图表中的数据显示了缓慢增加的延迟时间,而仅看到这一点就,我们就足以判断这里可能存在着问题 - 这就是可视化的力量!

如何应对延迟?

我们将介绍一些解决延迟的方法,但请记住,此列表并不详尽 - 您可能会发现其他更有效的方法。如果发现了,请告诉我们 - 汇聚的信息越多,我们就能更好地帮助更多人!

延迟可能发生在系统的多个部分。我们将在以下每个阶段解决潜在的原因。

Kafka 和 Kafka Connect 之间的延迟

提取和批处理大小

连接器通过 Kafka Connect 独立的获取到记录数据,您可以通过设置 consumer.fetch.min.bytes 和 consumer.fetch.max.bytes 来调整它。您可以想象,这里有一个权衡取舍 - 理想情况下,您获取的记录总数要比批处理大小(即条数)多,以便始终有足够的记录填充批处理。如果您发现并不经常生成消息,甚至可以通过设置 consumer.fetch.max.wait.ms 来调整提取的发生频率 - 可能需要更长的时间,但如果批处理达到了最大条数(因此要优化需要建立连接的数量),提取更有可能命中。

同样,另一方面,连接器收到的批处理由轮询控制(默认值为 500):

consumer.max.poll.records=[NUMBER OF RECORDS]
consumer.max.partition.fetch.bytes=[NUMBER OF RECORDS * RECORD SIZE IN BYTES]

不同的 Kafka Connect 主机,将有不同的处理调整方法 - 例如,请参阅 Confluent 的文档(https://docs.confluent.io/cloud/current/connectors/bring-your-connector/custom-connector-manage.html#override-configuration-properties)以了解他们首选的方法。

分区数量

主题分区的数量会影响插入的数量和批量大小(这可能会增加网络通信的频繁性,正如你所想象的那样)。一百条消息分布在一百个分区上会比单个分区产生更大的影响,尤其是基于运行的任务/工作者数量。由于上述的轮询和提取过程是每个任务执行的(见下文),更多的分区可能会增加填充批次的时间(如果遵循下面的建议,每个分区一个任务),从而潜在地增加延迟。因此,我们通常建议倾向于更少的分区(在合理范围内),而不是更多,但对于分区大小并没有确定的规则。

我们一般建议以每次至少1,000行的相对较大批次插入数据,最好在10,000到100,000行之间(有关更多信息,请参阅我们的最佳实践(https://clickhouse.com/docs/en/cloud/bestpractices/bulk-inserts))。

任务数量

在Kafka Connect中,任务是实际复制数据的工作程序 - 我们已经看到建议您至少具有与分区相同数量的任务,以确保每个“通道”正常运行。

如果您想深入了解任务,请查看Confluent关于此主题的文档(https://docs.confluent.io/platform/current/connect/index.html#tasks)。

部分(Part)过多

我们遇到过的一个问题是“部分过多”错误 - ClickHouse针对大量数据(经过适当批处理)进行了优化,而不是频繁的小插入(经典的“喋喋不休”与“批量”网络辩论)。插入是根据任务处理的 - 每个任务负责将该任务的数据插入ClickHouse - 因此,更多的分区/任务并不总是更好。

Kafka Connect与ClickHouse Cloud之间的延迟

实例休眠

ClickHouse Cloud 在没有处理查询服务时,会让实例进入休眠(以节省成本)状态。这意味着当插入和查询活动存在间隙时,实例可能会被暂停。如果当有新数据涌入时,这个机制就可能导致延迟,因为实例需要被重新启动。

如果这种延迟是不可接受的,用户可以调整服务对工作负载的空闲超时设置 - 将其增加以确保较短的活动暂停期并不会导致空闲。

实例大小

更多的数据将需要更多的容量 - 尽管ClickHouse非常高效,但这个一般的格言仍然适用。ClickHouse Cloud通常会为您处理扩缩容 - 有关更多详细信息,请参阅我们的文档(https://clickhouse.com/docs/en/about-us/cloud#clickhouse-cloud-benefits)。

异步 vs 同步插入

默认情况下,我们的连接器通过同步插入发送数据 - 在继续之前等待确认。从防数据丢失的角度来看,这通常更安全,但它确实会一定程度的引入延迟,因为每次插入都需要确认成功。

另一方面,可以配置异步插入,只需提交数据而无需等待 - 可能会提高吞吐量。如果潜在的丢失消息不是问题(例如,您正在进行消费者分析,并且需要更多的数据而不是特定的条目),这可能是一种更快的方法。请注意,这种方法意味着较低的耐久性保证,最低提供至少一次的语义。

有关配置的更多详细信息,请参阅我们的文档(https://clickhouse.com/docs/en/optimize/asynchronous-inserts)。

结论

在本文中,我们描述了在Kafka和ClickHouse架构中可能出现的延迟问题。除了确定延迟的原因和最小化方法外,我们首先提出了一种简单的衡量和可视化延迟的方法。

希望这对您的ClickHouse之旅有所帮助 - 还有更多内容要发布!

图片

​​联系我们

手机号:13910395701

邮箱:[email protected]

满足您所有的在线分析列式数据库管理需求

猜你喜欢

转载自blog.csdn.net/ClickHouseDB/article/details/134746382