这些年背过的面试题——Kafka篇

821次阅读  |  发布于10月以前

阿里妹导读

本文是技术人面试系列Kafka篇,面试中关于Kafka都需要了解哪些基础?一文带你详细了解,欢迎收藏!

Why kafka

消息队列的作用:异步、削峰填谷、解耦

中小型公司,技术挑战不是特别高,用 RabbitMQ (开源、社区活跃)是不错的选择;大型公司,基础架构研发实力较强,用 RocketMQ(Java二次开发) 是很好的选择。

如果是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的事实性规范。

RabbitMQ

RabbitMQ开始是用在电信业务的可靠通信的,也是少有的几款支持AMQP协议的产品之一。

优点:

缺点:

RocketMQ借鉴了Kafka的设计并做了很多改进,几乎具备了消息队列应该具备的所有特性和功能。

缺点:

跟周边系统的整合和兼容不是很好。

Kafka

高可用,几乎所有相关的开源软件都支持,满足大多数的应用场景,尤其是大数据和流计算领域,

What Kafka

消息Message

Kafka的数据单元称为消息。可以把消息看成是数据库里的一个“数据行”或一条“记录”。

批次

为了提高效率,消息被分批写入Kafka。提高吞吐量却加大了响应时间。

主题Topic

通过主题进行分类,类似数据库中的表。

分区Partition

Topic可以被分成若干分区分布于kafka集群中,方便扩容单个分区内是有序的,partition设置为一才能保证全局有序

副本Replicas

每个主题被分为若干个分区,每个分区有多个副本。

生产者Producer

生产者在默认情况下把消息均衡地分布到主题的所有分区上:

消费者Comsumer

消费者通过偏移量来区分已经读过的消息,从而消费消息。把每个分区最后读取的消息偏移量保存在Zookeeper 或Kafka上,如果消费者关闭或重启,它的读取状态不会丢失。

消费组ComsumerGroup

消费组保证每个分区只能被一个消费者使用,避免重复消费。如果群组内一个消费者失效,消费组里的其他消费者可以接管失效消费者的工作再平衡,重新分区。

节点Broker

连接生产者和消费者,单个broker可以轻松处理数千个分区以及每秒百万级的消息量。

集群

每隔分区都有一个首领,当分区被分配给多个broker时,会通过首领进行分区复制。

生产者Offset

消息写入的时候,每一个分区都有一个offset,即每个分区的最新最大的offset。

消费者Offset

不同消费组中的消费者可以针对一个分区存储不同的Offset,互不影响。

LogSegment

How Kafka

优点

应用场景

生产消费基本流程

  1. Producer创建时,会创建一个Sender线程并设置为守护线程。
  2. 生产的消息先经过拦截器->序列化器->分区器,然后将消息缓存在缓冲区。
  3. 批次发送的条件为:缓冲区数据大小达到batch.size或者linger.ms达到上限。
  4. 批次发送后,发往指定分区,然后落盘到broker;
    • acks=0只要将消息放到缓冲区,就认为消息已经发送完成。
    • acks=1表示消息只需要写到主分区即可。在该情形下,如果主分区收到消息确认之后就宕机了,而副本分区还没来得及同步该消息,则该消息丢失。
    • acks=all (默认)首领分区会等待所有的ISR副本分区确认记录。该处理保证了只要有一个ISR副本分区存活,消息就不会丢失。
  5. 如果生产者配置了retrires参数大于0并且未收到确认,那么客户端会对该消息进行重试。
  6. 落盘到broker成功,返回生产元数据给生产者。

Leader选举

副本消息同步

首先,Follower 发送 FETCH 请求给 Leader。接着,Leader 会读取底层日志文件中的消 息数据,再更新它内存中的 Follower 副本的 LEO 值,更新为 FETCH 请求中的 fetchOffset 值。最后,尝试更新分区高水位值。Follower 接收到 FETCH 响应之后,会把消息写入到底层日志,接着更新 LEO 和 HW 值。

相关概念:LEO和HW。

Rebalance

leader选举完成后,当以上三种情况发生时,Leader根据配置的RangeAssignor开始分配消费方案,即哪个consumer负责消费哪些topic的哪些partition。一旦完成分配,leader会将这个方案封装进SyncGroup请求中发给coordinator,非leader也会发SyncGroup请求,只是内容为空。coordinator接收到分配方案之后会把方案塞进SyncGroup的response中发给各个consumer。这样组内的所有成员就都知道自己应该消费哪些分区了。

分区分配算法RangeAssignor

增删改查

kafka-topics.sh --zookeeper localhost:2181/myKafka --create --topic topic_x                                 --partitions 1 --replication-factor 1kafka-topics.sh --zookeeper localhost:2181/myKafka --delete --topic topic_xkafka-topics.sh --zookeeper localhost:2181/myKafka --alter --topic topic_x                                --config max.message.bytes=1048576kafka-topics.sh --zookeeper localhost:2181/myKafka --describe --topic topic_x

如何查看偏移量为23的消息?

通过查询跳跃表ConcurrentSkipListMap,定位到在00000000000000000000.index ,通过二分法在偏移量索引文件中找到不大于 23 的最大索引项,即offset 20 那栏,然后从日志分段文件中的物理位置为320 开始顺序查找偏移量为 23 的消息。

切分文件

一致性

幂等性

保证在消息重发的时候,消费者不会重复处理。即使在消费者收到重复消息的时候,重复处理,也要保证最终结果的一致性。所谓幂等性,数学概念就是:f(f(x)) = f(x)

如何实现?

添加唯一ID,类似于数据库的主键,用于唯一标记一个消息。

ProducerID:#在每个新的Producer初始化时,会被分配一个唯一的PIDSequenceNumber:#对于每个PID发送数据的每个Topic都对应一个从0开始单调递增的SN值

如何选举

  1. 使用 Zookeeper 的分布式锁选举控制器,并在节点加入集群或退出集群时通知控制器。
  2. 控制器负责在节点加入或离开集群时进行分区Leader选举。
  3. 控制器使用epoch忽略小的纪元来避免脑裂:两个节点同时认为自己是当前的控制器。

可用性

面试题

线上问题rebalance

因集群架构变动导致的消费组内重平衡,如果kafka集内节点较多,比如数百个,那重平衡可能会耗时导致数分钟到数小时,此时kafka基本处于不可用状态,对kafka的TPS影响极大。

产生的原因:

解决方案:

加大超时时间 session.timout.ms=6s加大心跳频率 heartbeat.interval.ms=2s增长推送间隔 max.poll.interval.ms=t+1 minutes

ZooKeeper 的作用

目前,Kafka 使用 ZooKeeper 存放集群元数据、成员管理、Controller 选举,以及其他一些管理类任务。之后,等 KIP-500 提案完成后,Kafka 将完全不再依赖于 ZooKeeper。

一言以蔽之:KIP-500 ,是使用社区自研的基于 Raft 的共识算法,实现 Controller 自选举。同样是存储元数据,这几年基于Raft算法的etcd认可度越来越高。

越来越多的系统开始用它保存关键数据。比如,秒杀系统经常用它保存各节点信息,以便控制消费 MQ 的服务数量。还有些业务系统的配置数据,也会通过 etcd 实时同步给业务系统的各节点,比如,秒杀管理后台会使用 etcd 将秒杀活动的配置数据实时同步给秒杀 API 服务各节点。

Replica副本的作用

Kafka 只有 Leader 副本才能 对外提供读写服务,响应 Clients 端的请求。Follower 副本只是采用拉(PULL)的方 式,被动地同步 Leader 副本中的数据,并且在 Leader 副本所在的 Broker 宕机后,随时准备应聘 Leader 副本。

为什么不支持读写分离?

如何防止重复消费

如何保证数据不会丢失

如何保证顺序消费

【线上】如何解决积压消费

如何避免消息积压

if (maxOffset - curOffset > 100000) {  // TODO 消息堆积情况的优先处理逻辑  // 未处理的消息可以选择丢弃或者打日志  return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;}// TODO 正常消费过程return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;

如何设计消息队列

需要支持快速水平扩容,broker+partition,partition放不同的机器上,增加机器时将数据根据topic做迁移,分布式需要考虑一致性、可用性、分区容错性

性能上,可以借鉴时间轮、零拷贝、IO多路复用、顺序读写、压缩批处理

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8