producer生产端如何保证
ack确认机制
acks=0
表示生产者将只要信息发送,就认为发送成功了。即服务器未接收到该消息也会认为是成功。
acks=1(默认)
生产者发送消息,只要分区leader写入成功,即返回发送成功的信息。当leader挂掉,其他副本未来得及同步的数据会丢失。
acks=-1(或all)
生产者发送信息,该topic所有ISR中的副本[注:此副本数是会变化的]都写入成功,才返回发送成功的信息。
retries配置
kafka错误分为可恢复与不可恢复两种情况。
可恢复:
当出现网络异常等情况时,会产生错误信息,当配置项中retries大于0, 这种错误会进行重试发送,只要重试成功,则进行了自我恢复。
不可恢复:
当发送的数据超出了默认配置,如发送大信息的时候,数据大小超过了单次请求的最大值(max.request.size),则会产生异常,此类错误不会重试。此时则会丢失数据。需要程序将此类错误信息发送的数据自行备份,避免丢失。
应用方案
1、acks=0
允许数据偶尔丢失,或丢失少量数据影响甚微又追求高吞吐。
2、acks=-1且 retries 的值要大于 0
不允许数据丢失。
3、acks=1,retries 视个人情况设定。
其他情况。
consumer消费端如何保证
配置
auto.offset.reset = earliest(最早) /latest(最晚)
消费的起始位置,earliest表示当一个新加入的消费组消费消息时,从该topic每个分区中存在数据的最小offset开始消费。latest表示从该消费组只消费加入后新接收到的数据,不会消费加入之前的数据。
enable.auto.commit = true(默认)/false
是否开启自动提交
auto.commit.interval.ms
自动提交间隔时间,当enable.auto.commit 为true才生效。
应用方案
自动提交–>丢数据
当一批数据假设10条,处理到5条的时候,自动提交了offset,在处理第6条的时候发生异常,再次去拉数据的时候,就会从11开始消费,则丢失了6-10的数据。
自动提交–>重复消费
当一批数据假设10条,处理到5条的时候,还未提交offset,在处理第6条的时候发生异常,再次去拉数据的时候,就会从0开始消费,则会重复处理1-5条的数据
注:每次处理一条也可能出现以上情况。
手动提交,按条提交–>exactly-once
每处理完一条就提交offset,不会丢数据,但效率极低。
手动提交,按分区处理提交–>exactly-once
对批量的数据按分区遍历处理,记录该分区号及消费的偏移量,当出现异常时,则将该分区消费的便宜量提交到kafka中。后续再次消费时,会从提交的偏移量开始消费,确保数据消费不重复不丢失。
手动提交,统一提交
-
at-least-once
当拉取一批数据正常消费完全则提交offset,假如10条数据,消费到第6条出现异常,则重新拉取消费,因为未提交offset,则会重新消费本批数据。
-
exactly-once
在上条情况之上,由程序实现幂等功能,如为每条数据添加一个unique key,将unique key保存到redis中,处理数据前先对unique key进行判断,若不存在则处理,若存在则不处理。
broker端如何保证
配置
-
replication-factor=2
表示每个分区有多少份数据,用来提高数据的可用性。运行时运行n-1台机器挂掉。
-
min.insync.replicas = 2
表示ISR队列集合中最少有多少个副本,默认值是1 。ack为-1时,生产者需要确保数据写多少份才返回成功。假设replication-factor=3,min.insync.replicas = 2,则ack=-1时,正常情况是replication-factor=3,ISR=3,生产者可正常写入数据,当异常原因(如网络抖动)导致ISR由3变为2时,此时生产者仍可正常写入数据。若replication-factor=3,min.insync.replicas = 3,则当ISR由3变为2时,则此时生产者写入数据将失败。
-
unclean.leander.election.enable = false
是否允许从ISR队列中选举leader。默认false。当设置为true且ack=1时,则当原leader数据写到10,而一个副本同步到8,一个副本同步到9,此时leader挂掉,重新在副本中选择leader,当同步到8副本的当选leader,则丢失第9,10条数据,反正,则丢失第10条数据。
应用方案
建议在实际使用中min.insync.replica=replication-factor/2 +1 ,unclean.leader.election.enable =false