kafka总结

四:Kafka总结
1、生产者丢失数据和重复数据
Kafka有两种同步方式:同步(sync)、异步(async),默认是同步,可以通过参数producer.type来设置,Kafka通过配置request.required.acks属性来生产消息:
0——代表不进行消息是否成功接收的确认
1——代表当leader接收成功时确认
-1——代表leader和follower都接收成功的确认

1.1)消息发送时数据丢失的情形:
acks=0,不和kafka集群进行消息接收的确认,那么当网络异常、缓冲区满了等情况时,就会出现数据丢失;
acks=1,同步模式下,在只有leader接收成功并确认后,leader挂了,副本没有同步完成,就会造成数据丢失;
解决方案:
针对数据丢失:
1.同步模式下:
producer.type=sync
request.required.acks=-1
2.异步模式下:
如果是异步模式:通过buffer来进行控制数据的发送,有两个值来进行控制,时间阈值与消息的数量阈值,如果buffer满了数据还没有发送出去,如果设置的是立即清理模式,风险很大,一定要设置为阻塞模式,不限制阻塞超时时间 block.on.buffer.full = true
如果其中有一个步骤异常,都会触发kafka的重试机制

1.2)重复消息场景:
生产发送的消息没有收到正确的broke响应,导致producer重试,producer发出一条消息,broke落盘以后因为网络等种种原因
发送端得到一个发送失败的响应或者网络中断,然后producer收到一个可恢复的Exception重试消息导致消息重复。  
解决办法:
启动kafka的幂等性
enable.idempotence=true 同时要求 ack=all 且 retries>1。
幂等原理:
每个生产者producer都有一个唯一id,producer每发送一条数据,都会带上一个sequence,当消息落盘,sequence就会递增1。
那么只需要判断当前消息的sequence是否大于当前最大sequence,大于就代表此条数据没有落盘过,可以正常消费。不大于就代表落盘过,
这个时候重发的消息会被服务端拒掉从而避免消息重复
2、消费者丢失消息和重复数据
auto.offset.reset: 可理解为kafka consumer读取数据的策略:earliest|latest|none
earliest: 当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消费
latest: 当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,消费新产生的该分区下的数据
none: topic各分区都存在已提交的offset时,从offset后开始消费;只要有一个分区不存在已提交的offset,则抛出异常
2.1)丢失场景
设置的自动提交offset,当消费者已经消费到了消息,也记录了新的偏移量offset,但是后面的业务失败了或者,没来得及处理就挂了,这时候因为offset已经更新了,这条消息也再消费不到了
解决办法:
设置为手动提交成功,当业务代码都执行完成之后,再进行手动提交,确保消息被真正处理到
2.2)重复场景
数据消费完没有及时提交offset到broke。
消息消费端在消费过程中挂掉没有及时提交offset到broke,另一个消费端启动拿之前记录的offset开始消费,由于offset的滞后性可能会导致新启动的客户端有少量重复消费


一、基于Receiver的方式

这种方式使用Receiver来获取数据。Receiver是使用Kafka的高层次Consumer API来实现的。receiver从Kafka中获取的数据都是存储在Spark Executor的内存中的(如果突然数据暴增,大量batch堆积,很容易出现内存溢出的问题),然后Spark Streaming启动的job会去处理那些数据。

然而,在默认的配置下,这种方式可能会因为底层的失败而丢失数据。如果要启用高可靠机制,让数据零丢失,就必须启用Spark Streaming的预写日志机制(Write Ahead Log,WAL)。该机制会同步地将接收到的Kafka数据写入分布式文件系统(比如HDFS)上的预写日志中。所以,即使底层节点出现了失败,也可以使用预写日志中的数据进行恢复。

需要注意的要点

Kafka中的topic的partition,与Spark中的RDD的partition是没有关系的。所以,在1、KafkaUtils.createStream()中,提高partition的数量,只会增加一个Receiver中,读取partition的线程的数量。不会增加Spark处理数据的并行度。

可以创建多个Kafka输入DStream,使用不同的consumer group和topic,来通过多个receiver并行接收数据。

如果基于容错的文件系统,比如HDFS,启用了预写日志机制,接收到的数据都会被复制一份到预写日志中。因此,在KafkaUtils.createStream()中,设置的持久化级别是StorageLevel.MEMORY_AND_DISK_SER。

二、基于Direct的方式

这种新的不基于Receiver的直接方式,是在Spark 1.3中引入的,从而能够确保更加健壮的机制。替代掉使用Receiver来接收数据后,这种方式会周期性地查询Kafka,来获得每个topic+partition的最新的offset,从而定义每个batch的offset的范围。当处理数据的job启动时,就会使用Kafka的简单consumer api来获取Kafka指定offset范围的数据。

优点如下: 

简化并行读取:如果要读取多个partition,不需要创建多个输入DStream然后对它们进行union操作。Spark会创建跟Kafka partition一样多的RDD partition,并且会并行从Kafka中读取数据。所以在Kafka partition和RDD partition之间,有一个一对一的映射关系。

高性能:如果要保证零数据丢失,在基于receiver的方式中,需要开启WAL机制。这种方式其实效率低下,因为数据实际上被复制了两份,Kafka自己本身就有高可靠的机制,会对数据复制一份,而这里又会复制一份到WAL中。而基于direct的方式,不依赖Receiver,不需要开启WAL机制,只要Kafka中作了数据的复制,那么就可以通过Kafka的副本进行恢复。

一次且仅一次的事务机制。

三、对比:

基于receiver的方式,是使用Kafka的高阶API来在ZooKeeper中保存消费过的offset的。这是消费Kafka数据的传统方式。这种方式配合着WAL机制可以保证数据零丢失的高可靠性,但是却无法保证数据被处理一次且仅一次,可能会处理两次。因为Spark和ZooKeeper之间可能是不同步的。

基于direct的方式,使用kafka的简单api,Spark Streaming自己就负责追踪消费的offset,并保存在checkpoint中。Spark自己一定是同步的,因此可以保证数据是消费一次且仅消费一次。

在实际生产环境中大都用Direct方式
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值