1.Kafka如何保证消息不丢失
生产者:
1.Producer 默认是异步发送消息,这种情况下要确保消息发送成功,有两个方法
a. 把异步发送改成同步发送,这样 producer 就能实时知道消息发送的结果。
b. 添加异步回调函数来监听消息发送的结果,如果发送失败,可以在回调中重试
2.Producer 本身提供了一个重试参数 retries,如果因为网络问题或者 Broker 故障导致发送失败, Producer 会自动重试Kafka:
Kafka为了提高性能,采用的是异步批量 ,存储到磁盘的机制,就是有一定的消息量和时间间隔要求的,刷磁盘的这个动作是操作系统来调度的,如果在刷盘之前系统就崩溃了,就会数据丢失。它没有同步刷盘的机制。
针对这个问题,需要Partition的副本机制,acks机制来解决。Partition的副本机制是针对每个数据分区的高可用策略,每个副本集会包含唯一的一个leader和多个follower,leader负责处理事务类型的请求,follower负责同步leader的数据。
所以Kafka提供了一个 acks的参数,Producer可以设置这个参数,去结合broker的副本机制来共同保障数据的可靠性。
acks=0 表示producer不需要等待broker的响应,就认为消息发送成功了(可能存在数据丢失)
acks=1 表示broker的leader和Partition收到消息之后 不等待其他的follower Partition的同步就给Producer发一个确认,假设leader和Partition
挂了(可能存在数据丢失)
acks=-1表示broker的leader和Partition收到消息之后 并且等待 ISR列表中的follower同步完成,再给Producer返回一个确认(保证数据不丢失)
消费者:
在消费端,Kafka通常不会出现消息丢失的情况。如果发生消息丢失,可以调offset来实现消息的重新消费
2.Kafka如何保证不重复消费
原因: 1.Kafka有个offset的概念,当每个消息被写进去后,都有一个offset,代表他的序号,然后consumer消费该数据之后,隔一段时间,会把自己消费过的消息的offset提交一下,代表我已经消费过了。下次我要是重启,就会继续从上次消费到的offset来继续消费。但是当我们直接kill进程了,再重启。这会导致consumer有些消息处理了,但是没来得及提交offset。等重启之后,少数消息就会再次消费一次
2.在Kafka中有一个Partition Balance机制,就是把多个Partition均衡的分配给多个消费者。消费端会从分配到的Partition里面去消费消息,如果消费者在默认的5分钟内没有处理完这一批消息。就会触发Kafka的Rebalance机制,从而导致offset自动提交失败。而Rebalance之后,消费者还是会从之前没提交的offset位置开始消费,从而导致消息重复消费。
措施:
1.Kafka的幂等性就是为了避免出现生产者重试的时候出现重复写入消息的情况。
开启功能配置(该配置默认为
false
)如下:
javaprop.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG,true);
2.提高消费端的处理性能避免触发 Balance,比如可以用异步的方式来处理消息,缩短单个消息消费
的市场。或者还可以调整消息处理的超时时间。还可以减少一次性从 Broker 上拉取数据的条数。
3.Kafka如何保证消费的顺序性
默认存储和消费消息,是不能保证顺序性的,因为一个topic数据可能存储在不同的分区中,每个分区都有一个按照顺序的存储的偏移量,如果消费者关联了多个分区不能保证顺序性
如果有这样的需求的话,我们是可以解决的,把消息都存储同一个分区下就行了,有两种方式都可以进行设置,**第一个是发送消息时指定分区号,第二个是发送消息时按照相同的业务设置相同的key,**因为默认情况下分区也是通过key的hashcode值来选择分区的,hash值如果一样的话,分区肯定也是一样的。
4.Kafka为什么这么快
- 磁盘顺序读写:Kafka利用磁盘顺序读写来提高性能。在Kafka中,消息是不断地追加到本地磁盘的末尾,而不是随机写入。这种顺序写入的方式可以显著提高磁盘的写入吞吐量,因为顺序写入可以避免磁盘头的频繁移动和寻址操作。
- 稀疏索引:Kafka的索引并不是为每一条消息都建立索引,而是采用稀疏索引的方式。这意味着Kafka在插入一批数据时才会产生一条索引记录,后续利用二分查找可以快速找到对应的数据。这种稀疏索引的设计可以大大提高检索效率,减少不必要的磁盘I/O操作。
- 批量文件压缩:Kafka默认不会删除数据,而是把所有的消息变成一个批量的文件,并对多次插入相同Key对应的Value进行合并,从而实现对消息的批量压缩。这种压缩技术可以减少网络I/O的消耗,提高数据传输的效率。
- 零拷贝机制:Kafka的文件传输最终调用的是Java NIO里面的transferTo方法,这个方法实际上调用的是Linux的sendfile()函数,可以实现零拷贝。零拷贝技术可以避免用户进程和内核空间之间的数据拷贝操作,从而大大提高文件传输的性能。
- 分区并行处理:Kafka通过分区(Partition)实现并行处理。每个主题可以划分多个分区,不同分区可以位于不同的节点上,从而充分利用集群优势实现机器间的并行处理。同时,分区在物理上对应一个文件夹,即使多个分区位于同一个节点,也可以通过配置让同一节点上的不同分区置于不同的磁盘上,实现磁盘间的并行处理。这种并行处理的方式可以显著提高Kafka的吞吐量。
5.Kafka的高可用机制
这个问题比较系统,回答出 kafka 的系统特点,leader 和 follower 的关系,消息读写的顺序即可。
6.为什么需要消息系统,mysql 不能满足需求吗?
(1)解耦:
允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。
(2)冗余:
消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采用的"插入-获取-删除"范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。
(3)扩展性:
因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。
(4)灵活性 & 峰值处理能力:
在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见。如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。
(5)可恢复性:
系统的一部分组件失效时,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。
(6)顺序保证:
在大多使用场景下,数据处理的顺序都很重要。大部分消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。(Kafka 保证一个 Partition 内的消息的有序性)
(7)缓冲:
有助于控制和优化数据流经过系统的速度,解决生产消息和消费消息的处理速度不一致的情况。
(8)异步通信:
很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。