Kafka Streams 在监控场景的应用与实践
作者:来自 vivo 互联网服务器团队- Pang Haiyun
介绍 Kafka Streams 的原理架构,常见配置以及在监控场景的应用。
一、背景
在当今大数据时代,实时数据处理变得越来越重要,而监控数据的实时性和可靠性是监控能力建设最重要的一环。随着监控业务需求的变化和技术的发展,需要能够实时处理和分析庞大的数据流。作为一种流式处理平台,Kafka Streams 为处理实时数据提供了强大的支持。本文将重点介绍如何利用 Kafka Streams 进行实时数据处理,包括其基本原理、功能和实际应用。通过本文的学习,读者将能够深入了解 Kafka Streams 的优势、在监控场景的应用及实践。
二、Kafka Streams 的基本概念
Kafka Streams 是一个开源的流式处理框架,基于 Kafka 消息队列构建,能够处理无限量的数据流。与传统的批处理不同,Kafka Streams 允许用户以流式处理的方式实时处理数据,而且处理延迟仅为毫秒级。
通过 Kafka Streams ,用户可以进行数据的实时转换、聚合、过滤等操作,同时能够与 Kafka Connect 和 Kafka Producer/Consumer 无缝集成。Kafka Streams 也是一个客户端程序库,用于处理和分析存储在 Kafka 中的数据,并将得到的数据写回 Kafka 或发送到外部系统。
Kafka、Storm、Flink 和 Spark 是大数据领域常用的工具和框架。
1、区别:
-
Kafka 是一个分布式消息系统,主要用于构建实时数据管道和事件驱动的应用程序。它提供了高吞吐量、持久性、可伸缩性和容错性,主要用于数据的发布和订阅。
-
Storm 是一个分布式实时计算系统,用于处理实时数据流。它提供了低延迟、高吞吐量的实时计算能力,适用于实时数据处理和流式计算。
-
Flink 是一个流处理引擎,提供了精确一次的状态处理和事件时间处理等特性。它支持流处理和批处理,并提供了统一的 API 和运行时环境。
-
Spark 是一个通用的大数据处理框架,提供了批处理和流处理的功能。Spark 提供了丰富的数据处理和计算功能,包括 SQL 查询、机器学习、图处理等。
2、Kafka 的优势:
-
持久性和可靠性:Kafka 提供了数据持久化的功能,能够确保数据不丢失,并且支持数据的持久存储和重放。
-
可伸缩性:Kafka 集群可以很容易地进行水平扩展,支持大规模数据处理和高并发访问。
-
灵活性:Kafka 可以与各种不同的数据处理框架集成,作为数据源或数据目的地,使其在实时数据处理的场景中具有广泛的适用性。
总的来说,Kafka 的优势在于其高吞吐量、持久性和可靠性,以及灵活的集成能力,使其成为构建实时数据管道和事件驱动应用程序的理想选择。
2.1 Stream 处理拓扑
2.1.1 流
流是 Kafka Streams 提出的最重要的抽象概念:它表示一个无限的,不断更新的数据集。流是一个有序的,可重放(反复的使用),不可变的容错序列,数据记录的格式是键值对(key-value)。这里的 key 主要记录的是 value 的索引,决定了 Kafka 和 Kafka Streams 中数据的分区,即数据如何路由到 Topic 的特定分区。value 是主要后续处理器要处理的数据。
2.1.2 处理器拓扑
处理器拓扑是一个由流(边缘)连接的流处理(节点)的图。通过 Kafka Streams ,我们可以编写一个或多个的计算逻辑的处理器拓扑,用于对数据进行多步骤的处理。
2.1.3 流处理器
流处理器是处理器拓扑中的一个节点;它表示一个处理的步骤,用来转换流中的数据(从拓扑中的上游处理器一次接受一个输入消息,并且随后产生一个或多个输出消息到其下游处理器中)。
在拓扑中有两个特别的处理器:
-
源处理器(Source Processor):源处理器是一个没有任何上游处理器的特殊类型的流处理器。它从一个或多个 Kafka 主题生成输入流。通过消费这些主题的消息并将它们转发到下游处理器。
-
sink 处理器(Sink Processor):sink 处理器是一个没有下游流处理器的特殊类型的流处理器。它接收上游流处理器的消息发送到一个指定的 Kafka 主题。
(图片来源: Kafka 官网)
Kafka Streams 提供2种方式来定义流处理器拓扑:Kafka Streams DSL 提供了更常用的数据转换操作,如 map 和 filter;低级别 Processor API 允许开发者定义和连接自定义的处理器,以及和状态仓库交互。处理器拓扑仅仅是流处理代码的逻辑抽象。
2.2 时间
在流处理方面有一些重要的时间概念,它们是建模和集成一些操作的重要元素,例如定义窗口的时间界限。
时间在流中的常见概念如下:
-
事件时间 - 当一个事件或数据记录发生的时间点,就是最初创建的“源头”。
-
处理时间 - 事件或数据消息发生在流处理应用程序处理的时间点。即,记录已被消费。处理时间可能是毫秒,小时,或天等。比原始事件时间要晚。
-
摄取时间 - 事件或数据记录是 Kafka broker 存储在 topic 分区的时间点。与事件时间的差异是,当记录由 Kafka broker 追加到目标 topic 时,生成的摄取时间戳,而不是消息创建时间(“源头”)。与处理时间的差异是处理时间是流处理应用处理记录时的时间。比如,如果一个记录从未被处理,那么就没有处理时间,但仍然有摄取时间。
Kafka Streams 通过 TimestampExtractor 接口为每个数据记录分配一个时间戳。该接口的具体实现了基于数据记录的实际内容检索或计算获得时间戳,例如嵌入时间戳字段提供的事件时间语义,或使用其他的方法,比如在处理时返回当前的 wall-clock(墙钟)时间,从而产生了流应用程序的处理时间语义。因此开发者可以根据自己的业务需要选择执行不同的时间。例如,每条记录时间戳描述了流的时间增长(尽管记录在 stream 中是无序的)并利用时间依赖性来操作,如 join。
最后,当一个 Kafka Streams 应用程序写入记录到 Kafka 时,它将分配时间戳到新的消息。时间戳分配的方式取决于上下文:
-
当通过处理一些输入记录(例如,在 process()函数调用中触发的 context.forward())生成新的输出记录时,输出记录时间戳直接从输入记录时间戳继承。
-
当通过周期性函数(如 punctuate())生成新的输出记录时。输出记录时间戳被定义为流任务的当前内部时间(通过 context.timestamp() 获取)。
-
对于聚合,生成的聚合更新的记录时间戳将被最新到达的输入记录触发更新。
本部分简要介绍了 Kafka Streams 的基本概念,下一部分将介绍 Kafka Streams 的在监控场景的应用实践。
三、Kafka Streams 在监控场景的应用
3.1 链路分布示意图
3.2 示例:使用 Kafka Streams 来处理实时数据
流式处理引擎(如 Kafka Streams)与监控数据 ETL 可以为业务运维带来诸多好处,例如实时数据分析、实时监控、事件驱动的架构等。在本部分,我们将重点介绍 Kafka Streams 与监控数据 ETL 的集成,以及如何在监控数据 ETL 中利用 Kafka Streams 进行实时数据处理。
在监控数据ETL架构中,Kafka Streams 扮演着举足轻重的角色。它可以作为一个独立的数据处理服务来处理实时的数据流,并将处理结果输出到其他存储组件(例如,ES、VM等)中。同时,它也可以作为多个数据源之间的数据交换和通信的桥梁,扮演着数据总线的角色。Kafka Streams 的高可用性、高吞吐量和流式处理能力使得它成为监控数据ETL架构中的重要组件之一。
下面给出一个示例,演示了如何将 Kafka Streams 作为监控数据 ETL 来处理实时的数据。假设我们有一个监控数据流 TopicA,我们希望对这些数据进行实时的分析,并将分析结果输出到另一个 TopicB。我们可以创建一个 Kafka Streams 来处理这个需求:
//创建配置类
Properties props = new Properties();
//设置订阅者
props.put(StreamsConfig.APPLICATION_ID_CONFIG, "stream-processing-service");
//设置servers地址
props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "kafka-broker1:9092");StreamsBuilder builder = new StreamsBuilder();
//构建流
KStream<String, String> userActions = builder.stream("TopicA");
//对流进行处理
KTable<String, Long> userClickCounts = userActions.filter((key, value) -> value.contains("click")).groupBy((key, value) -> value.split(":")[0]).count();
//流写回Kafka
userClickCounts.toStream().to("TopicB", Produced.with(Serdes.String(), Serdes.Long()));KafkaStreams streams = new KafkaStreams(builder.build(), props);streams.start();
在这个示例中,我们创建了一个 Kafka Streams 监控数据 ETL,用于处理实时的监控数据流。它对数据进行了过滤、分组和统计分析,并将结果输出到 TopicB。通过这个 ETL,我们可以很容易地实现实时的数据处理功能,并且能够与其他数据源和数据存储组件进行无缝的集成。
3.3 监控 ETL 的流处理示意图
本部分介绍了 Kafka Streams 的在监控场景的应用实践,下一部分将深入探讨 Kafka Streams 的运作原理及实时数据处理的常见操作,并阐述 Kafka Streams 如何实现这些操作。
四、监控数据 ETL 中 Kafka Streams 的运作原理
4.1 架构
Kafka Streams 通过生产者和消费者,并利用 Kafka 自有的能力来提供数据平行性,分布式协调性,故障容错和操作简单性,从而简化了应用程序的开发,在本节中,我们将描述 Kafka Streams 是如何工作的。
下图展示了 Kafka Streams 应用程序的解剖图,让我们来看一下。
(图片来源: Kafka 官网)
Kafka 消费者通过消费1个或多个 Topic 拿到数据,形成输入 Kafka 流,经过处理器拓扑对数据进行统一处理形成输出 Kafka 流,将数据写入1个或多个出流 Topic,这是 kafka 流整体的运行流程。
4.1.1 Stream 分区和任务
Kafka 分区数据的消息层用于存储和传输,Kafka Streams 分区数据用于处理, 在这两种情况下,这种分区规划和设计使数据具有弹性,可扩展,高性能和高容错的能力。Kafka Streams 使用了分区和任务的概念,基于 Kafka 主题分区的并行性模型。在并发环境里,Kafka Streams 和 Kafka 之间有着紧密的联系:
-
每个流分区是完全有序的数据记录队列,并映射到 Kafka 主题的分区。
-
流的数据消息与主题的消息映射。
-
数据记录中的 keys 决定了 Kafka 和 Kafka Streams 中数据的分区,即,如何将数据路由到指定的分区。
应用程序的处理器拓扑通过将其分成多个任务来进行扩展,更具体点说,Kafka Streams 根据输入流分区创建固定数量的任务,其中每个任务分配一个输入流的分区列表(即,Kafka 主题)。分区对任务的分配不会改变,因此每个任务是应用程序并行性的固定单位。然后,任务可以基于分配的分区实现自己的处理器拓扑;他们还可以为每个分配的分区维护一个缓冲,并从这些记录缓冲一次一个地处理消息。作为结果,流任务可以独立和并行的处理而无需手动干预。
重要的是要理解 Kafka Streams 不是资源管理器,而是可在任何地方都能“运行”的流处理应用程序库。多个实例的应用程序在同一台机器上执行,或分布多个机器上,并且任务可以通过该库自动的分发到这些运行的实例上。分区对任务的分配永远不会改变;如果一个应用程式实例失败,则这些被分配的任务将自动地在其他的实例重新创建,并从相同的流分区继续消费。
下面展示了2个分区,每个任务分配了输出流的1个分区。
(图片来源: Kafka 官网)
4.1.2 线程模型
Kafka Streams 允许用户配置线程数,可用于平衡处理应用程序的实例。每个线程的处理器拓扑独立的执行一个或多个任务。例如,下面展示了一个流线程运行2个流任务。
(图片来源: Kafka 官网)
启动更多的流线程或更多应用程序实例,只需复制拓扑逻辑(即复制代码到不同的机器上运行),达到并行处理处理不同的 Kafka 分区子集的目的。要注意的是,这些线程之间不共享状态。因此无需协调内部的线程。这使它非常简单在应用实例和线程之间并行拓扑。Kafka 主题分区的分配是通过 Kafka Streams 利用 Kafka 的协调功能在多个流线程之间透明处理。
如上所述,Kafka Streams 扩展流处理应用程序是很容易的:你只需要运行你的应用程序实例,Kafka Streams 负责在实例中运行的任务之间分配分区。你可以启动多个应用程序线程处理多个输入的 Kafka 主题分区。这样,所有运行中的应用实例,每个线程(即运行的任务)至少有一个输入分区可以处理。
4.1.3 故障容错
Kafka Streams 基于 Kafka 分区的高可用和副本故障容错能力。因此,当流数据持久到 Kafka,即使应用程序故障,如果需要重新处理它,它也是可用的。Kafka Streams 中的任务利用 Kafka 消费者客户端提供的故障容错的能力来处理故障。如果任务故障,Kafka Streams 将自动的在剩余运行中的应用实例重新启动该任务。
此外,Kafka Streams 还确保了本地状态仓库对故障的稳定性。对于每个状态仓库都维持一个追踪所有的状态更新的变更日志主题。这些变更日志主题也分区,因此,每个本地状态存储实例,在任务访问仓里,都有自己的专用的变更日志分区。变更主题日志也启用了日志压缩,以便可以安全的清除旧数据,以防止主题无限制的增长。如果任务失败并在其他的机器上重新运行,则 Kafka Streams 在恢复新启动的任务进行处理之前,重放相应的变更日志主题,保障在故障之前将其关联的状态存储恢复。故障处理对于终端用户是完全透明的。
请注意,任务(重新)初始化的成本通常主要取决于通过重放状态仓库变更日志主题来恢复状态的时间。为了减少恢复时间,用户可以配置他们的应用程序增加本地状态的备用副本(即完全的复制状态)。当一个任务迁移发生时,Kafka Streams 尝试去分配任务给应用实例,提前配置了备用副本的应用实例就可以减少任务(重新)初始化的成本。
4.2 创建流
记录流(KStreams)或变更日志流(KTable或GlobalkTable)可以从一个或多个 Kafka 主题创建源流,(而 KTable 和 GlobalKTable,只能从单个主题创建源流)。
KStreamBuilder builder = new KStreamBuilder();KStream<String, GenericRecord> source1 = builder.stream("topic1", "topic2");
KTable<String, GenericRecord> source2 = builder.table("topic3", "stateStoreName");
GlobalKTable<String, GenericRecord> source2 = builder.globalTable("topic4", "globalStoreName");
4.3 流回写 Kafka
在处理结束后,开发者可以通过 KStream.to 和 KTable.to 将最终的结果流(连续不断的)写回 Kafka 主题。
joined.to("topic4");
如果已经通过上面的to方法写入到一个主题中,但是如果你还需要继续读取和处理这些消息,可以从输出主题构建一个新流,Kafka Streams 提供了便利的方法,through:
// equivalent to
//
// joined.to("topic4");
// materialized = builder.stream("topic4");
KStream materialized = joined.through("topic4");
4.4 流程序的配置与启执行
除了定义的 topology,开发者还需要在运行它之前在 StreamsConfig 配置他们的应用程序,Kafka Streams 配置的完整列表可以在这里找到。
Kafka Streams 中指定配置和生产者、消费者客户端类似,通常,你创建一个 java.util.Properties,设置必要的参数,并通过 Properties 实例构建一个 StreamsConfig 实例。
import java.util.Properties;
import org.apache.kafka.streams.StreamsConfig;
Properties settings = new Properties();
// Set a few key parameters
settings.put(StreamsConfig.APPLICATION_ID_CONFIG, "my-first-streams-application");
settings.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "kafka-broker1:9092");
settings.put(StreamsConfig.ZOOKEEPER_CONNECT_CONFIG, "zookeeper1:2181");// Any further settings
settings.put(... , ...);// Create an instance of StreamsConfig from the Properties instance
StreamsConfig config = new StreamsConfig(settings);
除了 Kafka Streams 自己配置参数,你也可以为 Kafka 内部的消费者和生产者指定参数。根据你应用的需要。类似于 Streams 设置,你可以通过 StreamsConfig 设置任何消费者和/或生产者配置。请注意,一些消费者和生产者配置参数使用相同的参数名。例如,用于配置 TCP 缓冲的 send.buffer.bytes 或 receive.buffer.bytes。用于控制客户端请求重试的 request.timeout.ms 和 retry.backoff.ms。如果需要为消费者和生产者设置不同的值,可以使用 consumer. 或 producer. 作为参数名称的前缀。
Properties settings = new Properties();// Example of a "normal" setting for Kafka Streams
settings.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "kafka-broker-01:9092");
// Customize the Kafka consumer settings
streamsSettings.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, 60000);
// Customize a common client setting for both consumer and producer
settings.put(CommonClientConfigs.RETRY_BACKOFF_MS_CONFIG, 100L);
// Customize different values for consumer and producer
settings.put("consumer." + ConsumerConfig.RECEIVE_BUFFER_CONFIG, 1024 * 1024);
settings.put("producer." + ProducerConfig.RECEIVE_BUFFER_CONFIG, 64 * 1024);// Alternatively, you can use
settings.put(StreamsConfig.consumerPrefix(ConsumerConfig.RECEIVE_BUFFER_CONFIG), 1024 * 1024);
settings.put(StremasConfig.producerConfig(ProducerConfig.RECEIVE_BUFFER_CONFIG), 64 * 1024);
你可以在应用程序代码中的任何地方使用 Kafka Streams ,常见的是在应用程序的 main() 方法中使用。
首先,先创建一个 KafkaStreams 实例,其中构造函数的第一个参数用于定义一个 topology builder(Streams DSL的KStreamBuilder,或 Processor API 的 TopologyBuilder)。
第二个参数是上面提到的 StreamsConfig 的实例。
import org.apache.kafka.streams.KafkaStreams;
import org.apache.kafka.streams.StreamsConfig;
import org.apache.kafka.streams.kstream.KStreamBuilder;
import org.apache.kafka.streams.processor.TopologyBuilder;
// Use the builders to define the actual processing topology, e.g. to specify
// from which input topics to read, which stream operations (filter, map, etc.)
// should be called, and so on.
KStreamBuilder builder = ...; // when using the Kafka Streams DSL
//
// OR
//
TopologyBuilder builder = ...; // when using the Processor API
// Use the configuration to tell your application where the Kafka cluster is,
// which serializers/deserializers to use by default, to specify security settings,
// and so on.
StreamsConfig config = ...;
KafkaStreams streams = new KafkaStreams(builder, config);
在这点上,内部结果已经初始化,但是处理还没有开始。你必须通过调用 start() 方法启动 Kafka Streams 线程:
// Start the Kafka Streams instance
streams.start();
捕获任何意外的异常,设置 java.lang.Thread.UncaughtExceptionHandler。每当流线程由于意外终止时,将调用此处理程序。
streams.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {public uncaughtException(Thread t, throwable e) {// here you should examine the exception and perform an appropriate action!}
);
close() 方法结束程序。
// Stop the Kafka Streams instance
streams.close();
现在,运行你的应用程序,像其他的 Java 应用程序一样(Kafka Sterams 没有任何特殊的要求)。同样,你也可以打包成 jar,通过以下方式运行:
# Start the application in class com.example.MyStreamsApp
# from the fat jar named path-to-app-fatjar.jar.
$ java -cp path-to-app-fatjar.jar com.example.MyStreamsApp
当应用程序实例开始运行时,定义的处理器拓扑将被初始化成1个或多个流任务,可以由实例内的流线程并行的执行。如果处理器拓扑定义了状态仓库,则这些状态仓库在初始化流任务期间(重新)构建。这一点要理解,当如上所诉的启动你的应用程序时,实际上 Kafka Streams 认为你发布了一个实例。现实场景中,更常见的是你的应用程序有多个实例并行运行(如,其他的 JVM 中或别的机器上)。在这种情况下,Kafka Streams 会将任务从现有的实例中分配给刚刚启动的新实例。
五、监控数据 ETL 中 Kafka Streams 参数及其调优
5.1 必配参数:
-
bootstrap.servers:这是 Kafka 集群的地址列表,Kafka Streams 使用它来初始化与 Kafka 的连接。
-
key.deserializer 和 value.deserializer:这些配置定义了流中键和值的序列化和反序列化器。
-
auto.offset.reset:当没有初始偏移量或偏移量无效时,这个配置定义了 Kafka Streams 如何处理。
-
group.id:这对于使用 Kafka Streams 的消费者组来说很重要,它定义了消费者组的ID。
5.2 基础参数:
-
num.stream.threads:定义 Kafka Streams 应用程序中的线程数,默认与处理器的逻辑核心数相等。
-
state.dir:定义 Kafka Streams 存储状态的本地目录。
-
threading.max.instances:定义每个主题分区的最大线程实例数,默认与分区数相等。
-
threading.instances:定义每个主题分区的线程实例数,默认与分区数相等。
5.3 消费者参数:
-
enable.auto.commit:自动提交偏移量,默认值为"true",建议设置为"false",以便更好地控制偏移量的提交。
-
commit.interval.ms:提交偏移量的频率,默认值为5000ms,可以根据需要进行调整。
-
max.poll.records:一次拉取的消息数量,默认值为1000,可以根据网络带宽和处理能力进行调整。
5.4 生产者参数:
-
batch.size:批量发送消息的大小,默认值通常是16384(字节),可以根据网络带宽和 Kafka 集群的性能进行调整。
-
linger.ms:消息在生产者缓冲区中的最小停留时间,默认值为100ms,可以根据需要进行调整。
-
compression.type:压缩类型,可以提高网络带宽利用率,但会增加 CPU 开销。默认值为"none",可以根据需要设置为"gzip"、“snappy"或"lz4”。
对于 Kafka 的调优参数,可以根据实际的应用场景和性能需求进行调整,以达到最佳的性能和稳定性。
六、监控数据 ETL 中 Kafka Streams 的分区倾斜问题原因和解决方式
6.1 原因
分区倾斜是监控数据 ETL 的 Kafka Streams 在处理大规模数据流时遇到的常见问题。分区倾斜指的是在一个流处理应用程序中,某个分区的消息消费速度远远慢于其他分区,或某个分区的延迟积压数据远大于其他分区,导致 Kafka Streams 的实时性受到限制。
产生分区倾斜的原因可能包括:
-
数据分布不均匀:原始数据在 Kafka 主题的分区中分布不均匀,导致某些分区的消息量远大于其他分区。
-
消费者实例数量不足:在 Kafka Streams 应用程序中,消费者的实例数量不足,无法充分处理所有分区的消息。
-
消费者负载不均衡:消费者的负载不均衡(包括但不限于某些消费者实例处理的分区数大于其他实例),导致某些消费者实例处理的消息量远大于其他实例。
-
消费者实例负载不均衡:消费者实例性能不一致或性能被挤占,导致消费能力不均衡,消费速率异常小于平均消费速率
6.2 解决方案
-
数据均衡策略:在设计 Kafka 主题分区分配策略时,可以采用如轮询(Round-robin)或范围(Range)等均衡策略,使得数据在各个分区之间均匀分布。
-
增加消费者实例:根据应用程序的实际情况,适当增加消费者的实例数量,以提高整个系统的处理能力,例如扩容。
-
负载均衡策略:在消费者组内部实现负载均衡,如使用均匀分配消费者(Uniform Distribution Consumer)等策略,确保消费者实例之间的负载均衡,例如重启或剔除倾斜分区实例使 Kafka Streams 的分区进行重新分配。
-
优化消费者处理逻辑:分析消费者处理消息的速度慢的原因,优化处理逻辑,提高消费者的处理能力。
-
调整批次大小和窗口函数:通过调整 Kafka Streams 的批次大小和窗口函数等参数,降低消费者的处理压力。
-
使用侧输出:对于一些处理速度较慢的分区,可以考虑使用侧输出将部分消息引流至其他系统处理,减轻消费者负载。
七、总结
本文介绍了 Kafka Streams 在监控场景中的应用,阐述了 Kafka Streams 的基本概念,包括流、处理器拓扑、流处理器、时间概念等,举例说明了 Kafka Streams 在监控实时数据ETL中的具体应用,并详细解释了 Kafka Streams 的运作原理,包括其架构、创建流、流回写 Kafka、流程序配置与启执行等内容。文章还介绍了 Kafka Streams 的参数及其调优方法,以及可能出现的分区倾斜问题及其解决方法。
本文意在让读者对于 Kafka 流在监控业务的实际应用有所认识,并且了解 Kafka 流的基本概念和原理,阅读本文后对构建自己 Kafka 流应用程序有所帮助,能够理解在监控数据 ETL 常见分区倾斜的原理和解决方式。
引用:Kafka 官网 https://kafka.apache.org/
相关文章:

Kafka Streams 在监控场景的应用与实践
作者:来自 vivo 互联网服务器团队- Pang Haiyun 介绍 Kafka Streams 的原理架构,常见配置以及在监控场景的应用。 一、背景 在当今大数据时代,实时数据处理变得越来越重要,而监控数据的实时性和可靠性是监控能力建设最重要的一环…...

数据结构 -- 二叉树
目录 1、二叉树概念及结构 1.1、概念 1.2、特殊的二叉树 1.3、二叉树的性质 1.4、二叉树的存储结构 1.4.1、顺序存储 -- 看截图:二叉树的顺序存储 1.4.2、链式存储 -- 非完全二叉树用这种方式存储 2、二叉树的遍历 2.1、前序、中序以及后序遍历2.2、层序遍…...

redis数据转移
可能有时候因为硬件的原因我们我们需要更换服务器,如果更换服务器的话,那我们redis的数据该怎样转移呢,按照一下步骤即可完成redis数据的转移 1.进入redis客户端 2.使用 bgsave命令进行数据的备份,此命令完成后会在你的redis安装目…...

Ubuntu Netlink 套接字使用介绍
Netlink 套接字 是 Linux 特有的一种 IPC(进程间通信)机制,用于用户态进程和内核模块之间的通信。它可以用来完成路由管理、设备通知、网络状态更新等任务。 1. Netlink 的基本工作原理 Netlink 是一种双向通信机制。Netlink 消息分为请求和…...

spring boot密码加密方式
1. BCrypt 原理 BCrypt是一种专为密码哈希设计的算法,它被广泛认为是安全的选择之一。它不仅是一个单向函数(即只能加密不能解密),而且还内置了盐(salt)生成机制来防止彩虹表攻击。BCrypt的一个重要特点是…...

springboot根据租户id动态指定数据源
代码地址 码云地址springboot根据租户id动态指定数据源: springboot根据租户id指定动态数据源,结合mybatismysql多数源下的事务管理 创建3个数据库和对应的表 sql脚本在下图位置 代码的执行顺序 先设置主数据库的数据源配置目标数据源和默认数据源有了主库的数据源ÿ…...

使用C语言编写UDP循环接收并打印消息的程序
使用C语言编写UDP循环接收并打印消息的程序 前提条件程序概述伪代码C语言实现编译和运行C改进之自由设定端口注意事项在本文中,我们将展示如何使用C语言编写一个简单的UDP服务器程序,该程序将循环接收来自指定端口的UDP消息,并将接收到的消息打印到控制台。我们将使用POSIX套…...

【AI】✈️问答页面搭建-内网穿透公网可访问!
目录 👋前言 👀一、后端改动 🌱二、内网穿透 💞️三、前端改动 🍹四、测试 📫五、章末 👋前言 小伙伴们大家好,上次本地搭建了一个简单的 ai 页面,实现流式输出问答…...

计算机毕业设计原创定制(免费送源码):NodeJS+MVVM+MySQL 樱花在线视频网站
目 录 摘要 1 1 绪论 1 1.1研究背景 1 1.2系统设计思想 1 1.3B/S体系工作原理 1 1.4node.js主要功能 2 1.5论文结构与章节安排 3 2 樱花在线视频网站分析 4 2.1 可行性分析 4 2.2 系统流程分析 4 2.2.1数据增加流程 5 2.3.2数据修改流程 5 2.3.3数据删除流程 5 …...

ECharts热力图-笛卡尔坐标系上的热力图,附视频讲解与代码下载
引言: 热力图(Heatmap)是一种数据可视化技术,它通过颜色的深浅变化来表示数据在不同区域的分布密集程度。在二维平面上,热力图将数据值映射为颜色,通常颜色越深表示数据值越大,颜色越浅表示数…...

【Lua热更新】下篇
上篇链接:【Lua热更新】上篇 文章目录 三、xLua热更新📖1.概述📚︎2.导入xLua框架🔖3. C#调用Lua3.1Lua解析器3.2Lua文件夹的重定向3.3Lua解析器管理器3.4全局变量获取3.5全局函数获取3.6映射到List和Dictionary3.7映射到类3.8映…...

Facebook 与数字社交的未来走向
随着数字技术的飞速发展,社交平台的角色和形式也在不断演变。作为全球最大社交平台之一,Facebook(现Meta)在推动数字社交的进程中扮演了至关重要的角色。然而,随着互联网的去中心化趋势和新技术的崛起,Face…...

微信小程序实现二维码海报保存分享功能
首先在写这个二维码分享海报的时候试过很多方法,比如:canvas中的这个createCanvasContext创建上下文的方法,去网上一搜就是一大堆,但其实这个方法已经被废弃了。Canvas 实例,可通过 SelectorQuery 获取。这是绘制背景图…...

Android 搭建AIDL Client和Server端,双向通信
一、背景 使用AIDL,搭建Client和Server端,实现跨进程通讯,即两个应用之间可以相互通讯。这里列举AIDL实现的方式和需注意的细节,并附上源码。 二、实现方式 2.1 定义AIDL需要的接口,名字为xxx.aidl,Client和Server端 AIDL接口的包名和aidl文件必须一致,…...

深度学习从入门到精通——图像分割实战DeeplabV3
DeeplabV3算法 参数配置关于数据集的配置训练集参数 数据预处理模块DataSet构建模块测试一下数据集去正则化模型加载模块DeepLABV3 参数配置 关于数据集的配置 parser argparse.ArgumentParser()# Datset Optionsparser.add_argument("--data_root", typestr, defa…...

STM32-笔记5-按键点灯(中断方法)
1、复制03-流水灯项目,重命名06-按键点灯(中断法) 在\Drivers\BSP目录下创建一个文件夹exti,在该文件夹下,创建两个文件exti.c和exti.h文件,并且把这两个文件加载到项目中,打开项目工程文件 加载…...

C++ 只出现一次的数字 - 力扣(LeetCode)
点击链接即可查看题目:136. 只出现一次的数字 - 力扣(LeetCode) 一、题目 给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 你必须设计并实现线性时间…...

C++设计模式:享元模式 (附文字处理系统中的字符对象案例)
什么是享元模式? 享元模式是一个非常实用的结构型设计模式,它的主要目的是节省内存,尤其在需要创建大量相似对象时。 通俗解释: 想象我们在写一本书,每个字母都需要表示出来。如果每个字母都单独用对象表示ÿ…...

android EditText密码自动填充适配
android上的密码(其实不仅仅是密码,可以是用户名也可以是邮箱)自动填充,是需要考虑适配的。 官方文档:https://developer.android.com/identity/autofill/autofill-optimize?hlzh-cn 什么是自动填充 手机厂商一般会…...

LeetCode 刷题笔记
LeetCode 刷题笔记 1. 20241218 (1)2447 std::gcd是C17引入的一个函数,用于计算两个整数的最大公因数。位于<numeric>头文件中。 #include <iostream> #include <numeric> // std::gcdint main() {int a 36;int b 60…...

【Java基础面试题034】Java泛型擦除是什么?
回答重点 泛型擦除指的是Java编译器在编译时将所有泛型信息删除的过程,以确保与Java1.4及之前的版本保持兼容 泛型参数在运行时会被替换为其上界(通常是Object),这样一来在运行时无法获取泛型的实际类型。 作用:泛型…...

使用ssh命令远程登录服务器的两种便捷方式:简化ssh命令、创建bat文件
1. 简化ssh命令 使用记事本打开该路径C:\Users\<你的用户名>\.ssh\下的config文件,粘贴以下代码: Host myserverHostName 192.168.1.1(这里换成你的ip地址)User your_username(这里换成你的用户名)Port 22保存文件后现在在cmd中直接输入ssh myserv…...

access数据库代做/mysql代做/Sql server数据库代做辅导设计服务
针对Access数据库、MySQL以及SQL Server数据库的代做和辅导设计服务,以下是一些关键信息和建议: 一、服务概述 这些服务通常包括数据库的设计、创建、优化、维护以及相关的编程和查询编写等。无论是Access这样的桌面关系数据库管理系统(RDB…...

第十七届山东省职业院校技能大赛 中职组“网络安全”赛项任务书正式赛题
第十七届山东省职业院校技能大赛 中职组“网络安全”赛项任务书-A 目录 一、竞赛阶段 二、竞赛任务书内容 (一)拓扑图 (二)模块A 基础设施设置与安全加固(200分) (三)B模块安全事件响应/网络安全数据取证/…...

Android学习(五)-Kotlin编程语言-面向对象中的 继承-构造函数-接口三模块学习
首先,我们需要定义一个 Person 类: open class Person {var name ""var age 0fun eat() {println("$name is eating.")} } 注意,Person 类前面加上了 open 关键字,表示这个类可以被继承。在 Kotlin 中&am…...

滑动窗口 + 算法复习
维护一个满足条件的窗口大小,然后进行双指针移动 1.最长子串 题目链接:1.最长子串 - 蓝桥云课 #include<bits/stdc.h> #define int long long using namespace std; string s; int k; signed main() {int max_len0,left0;cin>>s>>k;…...

贪心算法 greedy
文章目录 参考贪心算法[Leetcode455 分发饼干](https://leetcode.cn/problems/assign-cookies/description/)分析题解 [Leetcode135 分发糖果](https://leetcode.cn/problems/assign-cookies/description/)分析题解 leetcode435无重叠区间分析题解 参考 https://github.com/ch…...

基于python的家教预约网站-家教信息平台系统
标题:基于 Python 的家教预约网站-家教信息平台系统 内容:1.摘要 本文介绍了一个基于 Python 的家教预约网站-家教信息平台系统。该系统旨在为学生和家长提供一个方便、高效的家教预约平台,同时也为家教老师提供一个展示自己教学能力和经验的机会。本文详细介绍了系…...

基于深度学习多图像融合的屏幕缺陷检测方案
公司项目,已申请专利。 深度学习作为新兴技术在图像领域蓬勃发展,因其自主学习图像数据特征的性能避免了人工设计算法的繁琐,精准的检测性能、高效的检测效率以及对各种不同类型的图像任务都有比较好的泛化性能,使得深度学习技术在…...

MySQL基础笔记(三)
在此特别感谢尚硅谷-康师傅的MySQL精品教程 获取更好的阅读体验请前往我的博客主站! 如果本文对你的学习有帮助,请多多点赞、评论、收藏,你们的反馈是我更新最大的动力! 创建和管理表 1. 基础知识 1.1 一条数据存储的过程 存储数据是处理数…...