什么是Kafka?
Kafka 是一种高吞吐量、分布式、基于发布/订阅的消息系统,最初由 LinkedIn 公司开发,使用 Scala 语言编写,目前是 Apache 的开源项目。
broker:Kafka 服务器,负责消息存储和转发
topic:消息类别,Kafka 按照 topic 来分类消息
partition:topic 的分区,一个 topic 可以包含多个 partition,topic 消息保存在各个 partition 上
offset:消息在日志中的位置,可以理解是消息在 partition 上的偏移量,也是代表该消息的唯一序号
Producer:消息生产者
Consumer:消息消费者
Consumer Group:消费者分组,每个 Consumer 必须属于一个 group
Zookeeper:保存着集群 broker、topic、partition 等 meta 数据;另外,还负责 broker 故障发现,partition leader 选举,负载均衡等功能
Kafka 判断一个节点是否还活着有那两个条件?
- 节点必须可以维护和 ZooKeeper 的连接,Zookeeper 通过心跳机制检查每个节点的连接
- 如果节点是个 follower,它必须能及时的同步 leader 的写操作,延时不能太久
Kafka 消息是采用 Pull 模式?还是 Push 模式?有什么优点缺点?
Kafka 遵循了一种大部分消息系统共同的传统的设计:producer 将消息推送到 broker,consumer 从 broker 拉取消息,一些消息系统比如 Scribe 和 ApacheFlume 采用了 push 模式,将消息推送到下游的 consumer。这样做有好处也有坏处:由 broker 决定消息推送的速率,对于不同消费速率的 consumer 就不太好处理了。消息系统都致力于让 consumer 以最大的速率最快速的消费消息,但不幸的是,push 模式下,当 broker 推送的速率远大于 consumer 消费的速率时, consumer 恐怕就要崩溃了。最终 Kafka 还是选取了传统的 pull 模式。
优点:
Pull 模式的另外一个好处是 consumer 可以自主决定是否批量的从 broker 拉取数据。Push 模式必须在不知道下游 consumer 消费能力和消费策略的情况下决定是立即推送每条消息还是缓存之后批量推送。如果为了避免 consumer 崩溃而采用较低的推送速率,将可能导致一次只推送较少的消息而造成浪费。Pull 模式下,consumer 就可以根据自己的消费能力去决定这些策略。
缺点:
Pull 有个缺点是,如果 broker 没有可供消费的消息,将导致 consumer 不断在循环中轮询, 直到新消息到达。为了避免这点,Kafka 有个参数可以让 consumer 阻塞知道新消息到达,当然也可以阻塞知道消息的数量达到某个特定的量这样就可以批量发。
生产者设计
- 负载均衡(partition 会均衡分布到不同 broker 上)
由于消息 topic 由多个 partition 组成,且 partition 会均衡分布到不同 broker 上,因此,为了有效利用 broker 集群的性能,提高消息的吞吐量,producer 可以通过随机或者 hash 等方式,将消息平均发送到多个 partition 上,以实现负载均衡。
- 批量发送
是提高消息吞吐量重要的方式,Producer 端可以在内存中合并多条消息后,以一次请求的方式发送了批量的消息给 broker,从而大大减少 broker 存储消息的 IO 操作次数。但也一定程度上影响了消息的实时性,相当于以时延代价,换取更好的吞吐量。
消费者设计
- 同一 Consumer Group 中的多个 Consumer 实例,不同时消费同一个 partition。partition 内消息是有序的,Consumer 通过 pull 方式消费消息。Kafka 不删除已消费的消息对于 partition,顺序读写磁盘数据,以时间复杂度 O(1)方式提供消息持久化能力。
Kafka 数据存储设计
- partition 的数据文件(offset,MessageSize,data)
partition中的每条Message包含了以下三个属性:offset,MessageSize,data,其中offset表示 Message 在这个 partition 中的偏移量,offset 不是该 Message 在 partition 数据文件中的实际存储位置,而是逻辑上一个值,它唯一确定了partition中的一条Message,可以认为offset是 partition 中 Message 的 id;MessageSize 表示消息内容 data 的大小;data 为 Message 的具体内容。
- 数据文件分段 segment(顺序读写、分段命令、二分查找)
partition 物理上由多个 segment 文件组成,每个 segment 大小相等,顺序读写。每个 segment 数据文件以该段中最小的 offset 命名,文件扩展名为.log。这样在查找指定 offset 的 Message 的时候,用二分查找就可以定位到该 Message 在哪个 segment 数据文件中。
- 数据文件索引(分段索引、稀疏存储)
Kafka 为每个分段后的数据文件建立了索引文件,文件名与数据文件的名字是一样的,只是文件扩展名为.index。index 文件中并没有为数据文件中的每条 Message 建立索引,而是采用了稀疏存储的方式,每隔一定字节的数据建立一条索引。这样避免了索引文件占用过多的空间,从而可以将索引文件保留在内存中。
数据传输的事物定义有哪三种?
- 最多一次: 消息不会被重复发送,最多被传输一次,但也有可能一次不传输
- 最少一次: 消息不会被漏发送,最少被传输一次,但也有可能被重复传输
- 精确的一次(Exactly once):不会漏传输也不会重复传输,每个消息都传输被一次而且仅仅被传输一次
Kafa consumer 是否可以消费指定分区消息?
Kafa consumer 消费消息时,向 broker 发出"fetch"请求去消费特定分区的消息,consumer 指定消息在日志中的偏移量(offset),就可以消费从这个位置开始的消息,customer 拥有了 offset 的控制权,可以向后回滚去重新消费之前的消息
Kafka 新建的分区会在哪个目录下创建?
在启动 Kafka 集群之前,我们需要配置好 log.dirs 参数,其值是 Kafka 数据的存放目录, 这个参数可以配置多个目录,目录之间使用逗号分隔,通常这些目录是分布在不同的磁盘上用于提高读写性能。
producer 是否直接将数据发送到 broker 的 leader(主节点)?
producer 直接将数据发送到 broker 的 leader(主节点),不需要在多个节点进行分发,为了帮助 producer 做到这点,所有的 Kafka 节点都可以及时的告知:哪些节点是活动的,目标topic 目标分区的 leader 在哪。这样 producer 就可以直接将消息发送到目的地了
Kafka 与传统消息系统之间有三个关键区别?
- Kafka 持久化日志,这些日志可以被重复读取和无限期保留
- Kafka 是一个分布式系统:它以集群的方式运行,可以灵活伸缩,在内部通过复制数据提升容错能力和高可用性
- Kafka 支持实时的流式处理
Kafka 创建 Topic 时如何将分区放置到不同的 Broker 中?
- 副本因子不能大于 Broker 的个数;
- 第一个分区(编号为 0)的第一个副本放置位置是随机从 brokerList 选择的;
- 其他分区的第一个副本放置位置相对于第 0 个分区依次往后移。也就是如果我们有 5 个Broker,5 个分区,假设第一个分区放在第四个 Broker 上,那么第二个分区将会放在第五个Broker上;第三个分区将会放在第一个Broker上;第四个分区将会放在第二个Broker 上,依次类推;
- 剩余的副本相对于第一个副本放置位置其实是由 nextReplicaShift 决定的,而这个数也是随机产生的