前言java
Kafka是最初由Linkedin公司开发,是一个分布式、支持分区的(partition)、多副本的(replica),基于zookeeper协调的分布式消息系统,它的最大的特性就是能够实时的处理大量数据以知足各类需求场景:好比基于hadoop的批处理系统、低延迟的实时系统、storm/Spark流式处理引擎,web/nginx日志、访问日志,消息服务等等,用scala语言编写,Linkedin于2010年贡献给了Apache基金会并成为顶级开源 项目。mysql
关于Kafka的知识总结了个思惟导图nginx
kafka 面试题程序员
一、如何获取 topic 主题的列表web
二、生产者和消费者的命令行是什么?面试
三、consumer 是推仍是拉?sql
四、讲讲 kafka 维护消费状态跟踪的方法数据库
五、讲一下主从同步缓存
六、为何须要消息系统,mysql 不能知足需求吗?安全
七、Zookeeper 对于 Kafka 的做用是什么?
八、数据传输的事务定义有哪三种?
九、Kafka 判断一个节点是否还活着有那两个条件?
十、Kafka 与传统 MQ 消息系统之间有三个关键区别
十一、讲一讲 kafka 的 ack 的三种机制
1三、消费者故障,出现活锁问题如何解决?
1四、如何控制消费的位置
1五、kafka 分布式(不是单机)的状况下,如何保证消息的顺序消费?
1六、kafka 的高可用机制是什么?
1七、kafka 如何减小数据丢失
1八、kafka 如何不消费重复数据?好比扣款,咱们不能重复的扣。
一、如何获取 topic 主题的列表
bin/kafka-topics.sh --list --zookeeper localhost:2181
二、生产者和消费者的命令行是什么?
生产者在主题上发布消息:
bin/kafka-console-producer.sh --broker-list 192.168.43.49:9092 --topicHello-Kafka
注意这里的 IP 是 server.properties 中的 listeners 的配置。接下来每一个新行就是输入一条新消息。
消费者接受消息:
bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topicHello-Kafka --from-beginning
三、consumer 是推仍是拉?
Kafka 最初考虑的问题是,customer 应该从 brokes 拉取消息仍是 brokers 将消息推送到 consumer,也就是 pull 还 push。在这方面,Kafka 遵循了一种大部分消息系统共同的传统的设计:producer 将消息推送到 broker,consumer 从broker 拉取消息。
一些消息系统好比 Scribe 和 Apache Flume 采用了 push 模式,将消息推送到下游的 consumer。这样作有好处也有坏处:由 broker 决定消息推送的速率,对于不一样消费速率的 consumer 就不太好处理了。消息系统都致力于让 consumer 以最大的速率最快速的消费消息,但不幸的是,push 模式下,当 broker 推送的速率远大于 consumer 消费的速率时,consumer 恐怕就要崩溃了。最终 Kafka 仍是选取了传统的 pull 模式。
Pull 模式的另一个好处是 consumer 能够自主决定是否批量的从 broker 拉取数据 。Push 模式必须在不知道下游 consumer 消费能力和消费策略的状况下决定是当即推送每条消息仍是缓存以后批量推送。若是为了不 consumer 崩溃而采用较低的推送速率,将可能致使一次只推送较少的消息而形成浪费。Pull 模式下,consumer 就能够根据本身的消费能力去决定这些策略。
Pull 有个缺点是,若是 broker 没有可供消费的消息,将致使 consumer 不断在循环中轮询,直到新消息到 t 达。为了不这点,Kafka 有个参数可让 consumer阻塞知道新消息到达(固然也能够阻塞知道消息的数量达到某个特定的量这样就能够批量发送)。
四、讲讲 kafka 维护消费状态跟踪的方法
大部分消息系统在 broker 端的维护消息被消费的记录:一个消息被分发到consumer 后 broker 就立刻进行标记或者等待 customer 的通知后进行标记。这样也能够在消息在消费后立马就删除以减小空间占用。
可是这样会不会有什么问题呢?若是一条消息发送出去以后就当即被标记为消费过的,旦 consumer 处理消息时失败了(好比程序崩溃)消息就丢失了。为了解决这个问题,不少消息系统提供了另一个个功能:当消息被发送出去以后仅仅被标记为已发送状态,当接到 consumer 已经消费成功的通知后才标记为已被消费的状态。这虽然解决了消息丢失的问题,但产生了新问题,首先若是 consumer处理消息成功了可是向 broker 发送响应时失败了,这条消息将被消费两次。第二个问题时,broker 必须维护每条消息的状态,而且每次都要先锁住消息而后更改状态而后释放锁。这样麻烦又来了,且不说要维护大量的状态数据,好比若是消息发送出去但没有收到消费成功的通知,这条消息将一直处于被锁定的状态,Kafka 采用了不一样的策略。Topic 被分红了若干分区,每一个分区在同一时间只被一个 consumer 消费。这意味着每一个分区被消费的消息在日志中的位置仅仅是一个简单的整数:offset。这样就很容易标记每一个分区消费状态就很容易了,仅仅须要一个整数而已。这样消费状态的跟踪就很简单了。
这带来了另一个好处:consumer 能够把 offset 调成一个较老的值,去从新消费老的消息。这对传统的消息系统来讲看起来有些难以想象,但确实是很是有用的,谁规定了一条消息只能被消费一次呢?
五、讲一下主从同步
Kafka容许topic的分区拥有若干副本,这个数量是能够配置的,你能够为每一个topci配置副本的数量。Kafka会自动在每一个个副本上备份数据,因此当一个节点down掉时数据依然是可用的。
Kafka的副本功能不是必须的,你能够配置只有一个副本,这样其实就至关于只有一份数据。
六、为何须要消息系统,mysql 不能知足需求吗?
(1)解耦:
容许你独立的扩展或修改两边的处理过程,只要确保它们遵照一样的接口约束。
(2)冗余:
消息队列把数据进行持久化直到它们已经被彻底处理,经过这一方式规避了数据丢失风险。许多消息队列所采用的”插入-获取-删除”范式中,在把一个消息从队列中删除以前,须要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。
(3)扩展性:
由于消息队列解耦了你的处理过程,因此增大消息入队和处理的频率是很容易的,只要另外增长处理过程便可。
(4)灵活性 & 峰值处理能力:
在访问量剧增的状况下,应用仍然须要继续发挥做用,可是这样的突发流量并不常见。若是为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列可以使关键组件顶住突发的访问压力,而不会由于突发的超负荷的请求而彻底崩溃。
(5)可恢复性:
系统的一部分组件失效时,不会影响到整个系统。消息队列下降了进程间的耦合度,因此即便一个处理消息的进程挂掉,加入队列中的消息仍然能够在系统恢复后被处理。
(6)顺序保证:
在大多使用场景下,数据处理的顺序都很重要。大部分消息队列原本就是排序的,而且能保证数据会按照特定的顺序来处理。(Kafka 保证一个 Partition 内的消息的有序性)
(7)缓冲:
有助于控制和优化数据流通过系统的速度,解决生产消息和消费消息的处理速度不一致的状况。
(8)异步通讯:
不少时候,用户不想也不须要当即处理消息。消息队列提供了异步处理机制,容许用户把一个消息放入队列,但并不当即处理它。想向队列中放入多少消息就放多少,而后在须要的时候再去处理它们。
七、Zookeeper 对于 Kafka 的做用是什么?
Zookeeper 是一个开放源码的、高性能的协调服务,它用于 Kafka 的分布式应用。
Zookeeper 主要用于在集群中不一样节点之间进行通讯
在 Kafka 中,它被用于提交偏移量,所以若是节点在任何状况下都失败了,它均可以从以前提交的偏移量中获取除此以外,它还执行其余活动,如: leader 检测、分布式同步、配置管理、识别新节点什么时候离开或链接、集群、节点实时状态等等。
八、数据传输的事务定义有哪三种?
和 MQTT 的事务定义同样都是 3 种。
(1)最多一次: 消息不会被重复发送,最多被传输一次,但也有可能一次不传输
(2)最少一次: 消息不会被漏发送,最少被传输一次,但也有可能被重复传输.
(3)精确的一次(Exactly once): 不会漏传输也不会重复传输,每一个消息都传输被一次并且仅仅被传输一次,这是你们所指望的
九、Kafka 判断一个节点是否还活着有那两个条件?
(1)节点必须能够维护和 ZooKeeper 的链接,Zookeeper 经过心跳机制检查每一个节点的链接
(2)若是节点是个 follower,他必须能及时的同步 leader 的写操做,延时不能过久
十、Kafka 与传统 MQ 消息系统之间有三个关键区别
(1).Kafka 持久化日志,这些日志能够被重复读取和无限期保留
(2).Kafka 是一个分布式系统:它以集群的方式运行,能够灵活伸缩,在内部经过复制数据提高容错能力和高可用性
(3).Kafka 支持实时的流式处理
十一、讲一讲 kafka 的 ack 的三种机制
request.required.acks 有三个值 0 1 -1(all)
0:生产者不会等待 broker 的 ack,这个延迟最低可是存储的保证最弱当 server 挂掉的时候就会丢数据。
1:服务端会等待 ack 值 leader 副本确认接收到消息后发送 ack 可是若是 leader挂掉后他不确保是否复制完成新 leader 也会致使数据丢失。
-1(all):服务端会等全部的 follower 的副本受到数据后才会受到 leader 发出的ack,这样数据不会丢失
十二、消费者如何不自动提交偏移量,由应用提交?
将 auto.commit.offset 设为 false,而后在处理一批消息后 commitSync() 或者异步提交 commitAsync()
即:
ConsumerRecords<> records = consumer.poll();for (ConsumerRecord<> record : records){ 。。。 tyr{ consumer.commitSync() } 。。。}
1三、消费者故障,出现活锁问题如何解决?
出现“活锁”的状况,是它持续的发送心跳,可是没有处理。为了预防消费者在这种状况下一直持有分区,咱们使用 max.poll.interval.ms 活跃检测机制。 在此基础上,若是你调用的 poll 的频率大于最大间隔,则客户端将主动地离开组,以便其余消费者接管该分区。 发生这种状况时,你会看到 offset 提交失败(调用commitSync()引起的 CommitFailedException)。这是一种安全机制,保障只有活动成员可以提交 offset。因此要留在组中,你必须持续调用 poll。
消费者提供两个配置设置来控制 poll 循环:
max.poll.interval.ms:增大 poll 的间隔,能够为消费者提供更多的时间去处理返回的消息(调用 poll(long)返回的消息,一般返回的消息都是一批)。缺点是此值越大将会延迟组从新平衡。
max.poll.records:此设置限制每次调用 poll 返回的消息数,这样能够更容易的预测每次 poll 间隔要处理的最大值。经过调整此值,能够减小 poll 间隔,减小从新平衡分组的
对于消息处理时间不可预测地的状况,这些选项是不够的。 处理这种状况的推荐方法是将消息处理移到另外一个线程中,让消费者继续调用 poll。 可是必须注意确保已提交的 offset 不超过实际位置。另外,你必须禁用自动提交,并只有在线程完成处理后才为记录手动提交偏移量(取决于你)。 还要注意,你须要 pause 暂停分区,不会从 poll 接收到新消息,让线程处理完以前返回的消息(若是你的处理能力比拉取消息的慢,那建立新线程将致使你机器内存溢出)。
1四、如何控制消费的位置
kafka 使用 seek(TopicPartition, long)指定新的消费位置。用于查找的服务器保留的最先和最新的 offset 的特殊的方法也可用(seekToBeginning(Collection) 和seekToEnd(Collection))
1五、kafka 分布式(不是单机)的状况下,如何保证消息的顺序消费?
Kafka 分布式的单位是 partition,同一个 partition 用一个 write ahead log 组织,因此能够保证 FIFO 的顺序。不一样 partition 之间不能保证顺序。可是绝大多数用户均可以经过 message key 来定义,由于同一个 key 的 message 能够保证只发送到同一个 partition。
Kafka 中发送 1 条消息的时候,能够指定(topic, partition, key) 3 个参数。partiton 和 key 是可选的。若是你指定了 partition,那就是全部消息发往同 1个 partition,就是有序的。而且在消费端,Kafka 保证,1 个 partition 只能被1 个 consumer 消费。或者你指定 key( 好比 order id),具备同 1 个 key 的全部消息,会发往同 1 个 partition。
1六、kafka 的高可用机制是什么?
这个问题比较系统,回答出 kafka 的系统特色,leader 和 follower 的关系,消息读写的顺序便可。
1七、kafka 如何减小数据丢失
Kafka到底会不会丢数据(data loss)? 一般不会,但有些状况下的确有可能会发生。下面的参数配置及Best practice列表能够较好地保证数据的持久性(固然是trade-off,牺牲了吞吐量)。
block.on.buffer.full = true
acks = all
retries = MAX_VALUE
max.in.flight.requests.per.connection = 1
使用KafkaProducer.send(record, callback)
callback逻辑中显式关闭producer:close(0)
unclean.leader.election.enable=false
replication.factor = 3
min.insync.replicas = 2
replication.factor > min.insync.replicas
enable.auto.commit=false
消息处理完成以后再提交位移
1八、kafka 如何不消费重复数据?好比扣款,咱们不能重复的扣。
其实仍是得结合业务来思考,我这里给几个思路:
好比你拿个数据要写库,你先根据主键查一下,若是这数据都有了,你就别插入了,update 一下好吧。
好比你是写 Redis,那没问题了,反正每次都是 set,自然幂等性。
好比你不是上面两个场景,那作的稍微复杂一点,你须要让生产者发送每条数据的时候,里面加一个全局惟一的 id,相似订单 id 之类的东西,而后你这里消费到了以后,先根据这个 id 去好比 Redis 里查一下,以前消费过吗?若是没有消费过,你就处理,而后这个 id 写 Redis。若是消费过了,那你就别处理了,保证别重复处理相同的消息便可。
好比基于数据库的惟一键来保证重复数据不会重复插入多条。由于有惟一键约束了,重复数据插入只会报错,不会致使数据库中出现脏数据。欢迎你们关注个人公种浩【程序员追风】,2019年多家公司java面试题整理了1000多道400多页pdf文档,文章都会在里面更新,整理的资料也会放在里面。
最后
欢迎你们一块儿交流,喜欢文章记得关注我点个赞哟,感谢支持!