2.Kafka的工作原理及数据丢失、数据重复问题

一、概述

   一个分布式消息中间件,基于zookeeper的分布式日志系统。(最新的3.0版本摆脱了对zookeeper的依赖,游标改为记录在一个单独的队列里)

  简单来讲,就是一个存储系统,起一个缓冲作用。

  所谓的消息系统,就是将数据从一个地方传递到另一个地方。消息传递模式有两种:点对点传递模式,发布-订阅模式。Kafka是一种发布-订阅模式。

 


 

二、特点

1.解耦:

  消息系统在处理过程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口。这允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。

2.异步:

  支持用户将消息放入队列中,不立刻处理,需要的时候再去处理。

3.削峰:

  使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。

举个例子:A系统高并发状态下,可能会出现连接异常甚至崩溃的情况,这个时候我们能选择一个中间件,将所有客户的请求都放入消息队列中,A系统只需要从消息队列中拉取消息再做处理即可。

 

 


 

三、角色

1.Topic消息队列:

  发布到Kafka集群的消息的类别。(就看作是一个个的消息队列名,用来找到对应的消息队列)。

  (1)Partition:topic中数据的具体管理单元。   

   一个topic 可以划分为多个partition,分布到多个 broker上管理;

 

   partition 中的每条信息都会被分配一个递增的id(offset);

 

   每个 partition 是一个有序的队列,各个 partition 间是无序的。换句话讲,如果topic有多个partition,消费数据时就不能保证数据的顺序。在需要严格保证消息的消费顺序的场景下,需要将partition数目设为1。

 

   每个partition都可以有多个副本;

 

  分区对于 kafka 集群的好处是:实现topic数据的负载均衡。分区对于消费者来说,可以提高并发度,提高效率。

 

  (2)Broker:

  Kafka集群包含一个或多个服务器,服务器节点称为Broker。容纳多个topic的多个partition。

  (3)Offset:

  消息在这底层存储中的索引位置,看作一个游标,通过它来确定消息的位置。

 

 2.Producer生产者:

   数据的发布者,发送消息给Broker。

 

3.Consumer消费者:

   消费者可以从broker中读取数据。消费者可以消费多个topic中的数据。

 

4.Leader和Follower:

   每个partition有多个副本,其中有且仅有一个作为Leader,Leader是当前负责数据的读写的partition。Follower跟随Leader,所有写请求都通过Leader路由,数据变更会广播给所有Follower,Follower与Leader保持数据同步。如果Leader失效,则从Follower中选举出一个新的Leader。当Follower与Leader挂掉、卡住或者同步太慢,leader会把这个follower从“in sync replicas”(ISR)列表中删除,重新创建一个

Follower。

 


 

四、数据丢失和数据重复问题:

在处理这两个问题之前,先来了解两个机制:ACK应答机制RETIRES延迟重发机制。

  ACK应答机制:

  在生产者端:broker往内存中写数据时,同时也会进行数据持久化操作,并根据你有多少个Leader和Follower,生成副本。内存先向Leader传输,完成后由leader向Follower进行备份。

此时就要考虑到备份的副本是否完成的问题。这里ACK应答机制可设三个参数:

  * 设 0 :不等broker同步完成的确认,继续发送下一条信息。不管数据的持久化,只要内存已处理完,直接传输下一条 (速度快 但不稳定)

  * 设 1 :等broker同步完成1次,就继续发送下一条信息。数据持久化只要Leade一完成,就进行下一次传输,不管Leader向Follower的备份 (速度较快 但如果落盘位置挂掉,没有备份数据)

  * 设 -1 :等broker全部同步完成,再发送下一条信息。等到数据持久化全部完成(包括备份的),才进行下一次的传输 (稳定,全部落盘才进行下一次的数据传输)

   注意:ACK机制只保证写入端的数据安全问题(不丢失),不会去管你数据是否重复等等。

RETIRES延迟重发机制:
  ACK应答机制(即便选择-1完全同步)只能保证数据全部备份下来,但不能确定备份数据的节点是否活跃,假如某台机器宕机,这时就需要重复机制,隔段时间再次重新发送一遍。

    注意:这里虽避免了数据丢失,但可能会造成数据重复。而且,如果重发后还无

响应,就会跳过这条数据继续下一次的发送,造成该数据丢失


所以,总结如下:

造成数据丢失的原因:

  1.  ACK应答机制设置为0,数据没有落盘保存,只是在内存中走了一遭,此时内存中的数据一旦没了,那就会造成数据丢失。

    设置为1,那么数据只会落盘保存到Leader上,Leader还没向Follower中同步时,此时Leader挂掉,数据丢失。

  2.  Offset设置为自动提交,他的机制是定时自动提交,如果提交时,数据还没处理完,但数据偏移量已经改变,下次读取的是下一个位置处的数据,而这部分未处理的数据所在节点一旦出现故障,数据也会丢失。

解决办法:

  ACK应答机制设为-1(或者all),并且关闭手动提交,提交时采用同步模式

prop.put( ProducerConfig.ACKS_CONFIG, "all");

prop.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG,"false");
consumer.commitSync();

 

 

 

 造成数据重复的原因:

  1.延迟重发机制下,节点出现故障导致主从数据同步未完成,他会重新发送一遍

  2.已经消费完成,但是offset还未提交,此时节点挂掉,下一次还是会从之前的offset处里数据,重复消费。

解决办法:

   1.手动维护offset(但仍有风险);

  2.加大kafka.consumer.session.timeout参数,避免错误关闭的情况。

  3.在下游选择Hbase或者redis等进行去重。

  

 

 

 

 

posted on 2021-11-04 22:53  理想三旬_z  阅读(491)  评论(0编辑  收藏  举报

导航