kafka的架构和参数

  其他常见问题
内容纲要

概要描述


本文旨在介绍kafka的基础架构和参数

详细说明


Kafka 和传统的消息系统不同在于:

• Kafka是一个分布式系统,易于向外扩展。

• 它同时为发布和订阅提供高吞吐量。

• 它支持多订阅者,当失败时能自动平衡消费者。

• 消息的持久化。

kafka架构图:

file
上图中一个topic配置了3个partition。Partition1有两个offset:0和1。Partition2有4个offset。Partition3有1个offset。副本的id和副本所在的机器的id恰好相同。

如果一个topic的副本数为3,那么Kafka将在集群中为每个partition创建3个相同的副本。集群中的每个broker存储一个或多个partition。多个producer和consumer可同时生产和消费数据。

broker以消息到达的顺序进行存储,每个主题可以配置分区;

分区内部是有顺序的,分区之间不保证顺序;

Kafka broker是无状态的,它不需要标记哪些消息被哪些消费过,也不需要通过broker去保证同一个Consumer Group只有一个Consumer能消费某一条消息,因此也就不需要锁机制,这也为Kafka的高吞吐率提供了有力保障;
这是Kafka用来实现一个Topic消息的广播(发给所有的Consumer)和单播(发给某一个Consumer)的手段。一个Topic可以对应多个Consumer Group。如果需要实现广播,只要每个Consumer有一个独立的Group就可以了。要实现单播只要所有的Consumer在同一个Group里。用Consumer Group还可以将Consumer进行自由的分组而不需要多次发送消息到不同的Topic;

Topic 和 Partition

在 Kafka 中的每一条消息都有一个 Topic。一般来说在我们应用中产生不同类型的数据,都可以设置不同的主题。

一个主题一般会有多个消息的订阅者,当生产者发布消息到某个主题时,订阅了这个主题的消费者都可以接收到生产者写入的新消息。
file

kafka的topic和消费者之间是多对多的关系,假设一个topic分为0,1,2,3个分区, 一个消费者组里面假设有3个消费者,每个分区只能由一个消费者组里的一个消费者消费,每个分区的数据是不一样的,不同分区可能由同一个消费者组的不同消费者消费。

Kafka可以将主题划分为多个分区(Partition),会根据分区规则选择把消息存储到哪个分区中,只要如果分区规则设置的合理,那么所有的消息将会被均匀的分布到不同的分区中,这样就实现了负载均衡和水平扩展。另外,多个订阅者可以从一个或者多个分区中同时消费数据,以支撑海量数据处理能力;

分区策略参考:kafka 分区策略

增加分区可以提供kafka集群的吞吐量。然而,也应该意识到集群的总分区数或是单台服务器上的分区数过多,会增加不可用及延迟的风险;建议分区数=executor数量

在 Kafka 的机器上,每个 Partition 其实都会对应一个日志目录,在目录下面会对应多个日志分段(LogSegment)。

LogSegment 文件由两部分组成,分别为“.index”文件和“.log”文件,分别表示为 Segment 索引文件和数据文件。

任何发布到此 Partition 的消息都会被追加到 Log 文件的尾部,在分区中的每条消息都会按照时间顺序分配到一个单调递增的顺序编号,也就是我们的 Offset。Offset 是一个 Long 型的数字。

我们通过这个 Offset 可以确定一条在该 Partition 下的唯一消息。在 Partition 下面是保证了有序性,但是在 Topic 下面没有保证有序性。
生产者会根据offset值轮循写入partition。

file

消费模型

消息由生产者发送到 Kafka 集群后,会被消费者消费。

Kafka 采取拉取模型(Poll),由自己控制消费速度,以及消费的进度,消费者可以按照任意的偏移量进行消费。

比如消费者可以消费已经消费过的消息进行重新处理,或者消费最近的消息等等。

Kafka实际环境有可能会出现Consumer全部宕机,虽然基于Kafka的高可用特性,消费者群组中的消费者可以实现再均衡,所有Consumer不处理数据的情况很少,但是还是有可能会出现,此时就要求Consumer重启的时候能够读取在宕机期间Producer发送的数据。

通过消费者命令行可以实现,只要在命令行中加上–from-beginning即可 (从最小值消费)
file

高可靠分布式存储模型
在 Kafka 中保证高可靠模型依靠的是副本机制,有了副本机制之后,就算机器宕机也不会发生数据丢失。

高性能的日志存储

Kafka 一个 Topic 下面的所有消息都是以 Partition 的方式分布式的存储在多个节点上。

但是 Kafka 有个问题,如果分区过多,那么日志分段也会很多,写的时候由于是批量写,其实就会变成随机写了,随机 I/O 这个时候对性能影响很大。所以一般来说 Kafka 不能有太多的 Partition。

未开安全集群内的kafka consumer和broker信息都是存储在zk上的:
file

开启安全之后信息是存储在broker上的__consumer_offset 这个topic

查询offset以及group信息可以通过命令:

./kafka-console-consumer.sh --bootstrap-server 172.22.17.1:9092 --topic __consumer_offsets --consumer.config /root/TDH-Client/kafka/config/consumer.properties --formatter "kafka.coordinator.GroupMetadataManager\$OffsetsMessageFormatter"

file

副本机制

Kafka 的副本机制是多个服务端节点对其他节点的主题分区的日志进行复制。

当集群中的某个节点出现故障,访问故障节点的请求会被转移到其他正常节点(这一过程通常叫 Reblance)。

Kafka 每个主题的每个分区都有一个主副本以及 0 个或者多个副本,副本保持和主副本的数据同步,当主副本出故障时就会被替代。

在 Kafka 中并不是所有的副本都能被拿来替代主副本,所以在 Kafka 的 Leader 节点中维护着一个 ISR(In Sync Replicas)集合。

翻译过来也叫正在同步中集合,在这个集合中的需要满足两个条件:

• 节点必须和 ZK 保持连接。

• 在同步的过程中这个副本不能落后主副本太多。

另外还有个 AR(Assigned Replicas)用来标识副本的全集,OSR 用来表示由于落后被剔除的副本集合。

所以公式如下:ISR = Leader + 没有落后太多的副本;AR = OSR+ ISR。

exactly-once

刚好一次,即使 Producer 重试发送消息,消息也会保证最多一次地传递给 Consumer。该语义是最理想的,也是最难实现的。

在 0.10 之前并不能保证 exactly-once,0.11.0 使用事务保证了。

如何实现 exactly-once

要实现 exactly-once 在 Kafka 0.11.0 中有两个官方策略:

单 Producer 单 Topic

每个 Producer 在初始化的时候都会被分配一个唯一的 PID,对于每个唯一的 PID,Producer 向指定的 Topic 中某个特定的 Partition 发送的消息都会携带一个从 0 单调递增的 Sequence Number。

在我们的 Broker 端也会维护一个维度,每次提交一次消息的时候都会对齐进行校验:

• 如果消息序号比 Broker 维护的序号大一以上,说明中间有数据尚未写入,也即乱序,此时 Broker 拒绝该消息,Producer 抛出 InvalidSequenceNumber。

• 如果消息序号小于等于 Broker 维护的序号,说明该消息已被保存,即为重复消息,Broker 直接丢弃该消息,Producer 抛出 DuplicateSequenceNumber。

如果消息序号刚好大一,就证明是合法的。

上面所说的解决了两个问题:

• 当 Prouducer 发送了一条消息之后失败,Broker 并没有保存,但是第二条消息却发送成功,造成了数据的乱序。

• 当 Producer 发送了一条消息之后,Broker 保存成功,Ack 回传失败,Producer 再次投递重复的消息。

上面所说的都是在同一个 PID 下面,意味着必须保证在单个 Producer 中的同一个 Session 内,如果 Producer 挂了,被分配了新的 PID,这样就无法保证了,所以 Kafka 中又有事务机制去保证。

kafka参数详解:
详细参数可以参考文章:
kafka 参数详解

这篇文章对您有帮助吗?

平均评分 0 / 5. 次数: 0

尚无评价,您可以第一个评哦!

非常抱歉,这篇文章对您没有帮助.

烦请您告诉我们您的建议与意见,以便我们改进,谢谢您。