首先我们来看一下kafka的架构:
大致数据流程是kafka的生产者Producer生成数据,通过broker服务写到Topic A中的Partition 0分区中,这个时候数据已经存到磁盘中了,然后Consumer A通过消费把Topic A中的Partition 0中的数据消费出来,存到相关存储DB中。
上面我们看到kafka的架构流程,broker的选举和管理是通过zookeeper来实现,在不考虑kafka集群全部一次性挂掉的,网络全部出故障的情况下。我们来看下应用程序层面如何保证数据不丢失。
关于Producer:作为producer的client,我们从接受数据开始,然后传输数据到kafka中,如果网络不出问题,我们要保证kafka不丢数据的话,需要保证写入数据到kafka每个节点都能有成功的ack回复(acks = all (或-1)),当然如果我们考虑集群一次性挂掉,那确实还是解决不了。节点ack回复还需要配置每个节点的副本,replication.factor参数,这个值必须大于1,即要求每个partition必须有至少2个副本,min.insync.replicas参数,这个值必须大于1,这个是要求一个leader至少感知到有一个follower还跟自己保持联系。从上述的我们大概能了解,如果保证高可用的话,上面的三个关键性配置是必不可少的,当然集群的规模也是必要的,如果你才三个kafka节点,全部在同一个机房,那机房出问题,这种也是无法解决的。好了,这种的问题我就不扯了。从应用程序和服务的配置来说上述三个层面的配置对集群的可靠性来说是必不可少的。
关于Consumer:作为Consumer的client,我们从broker拿数据,我们如何保证数据不丢失呢?如果数据不丢失如何保证数据不重复消费呢?关于消费其实最重要的是offset的管理,默认offset的管理是Consumer从broker拿数据的时候拿出来的时候offset就会自动提交,我们需要设置enable.auto.commit=false,在消息处理完成之后再提交位移,这样我们能够保证数据肯定不会丢失,但是这个时候我们会造成数据可能被重复消费问题,这个时候我们可能要考虑引入第三方,从broker pull数据的时候,消费完的数据存一份到redis,保存一定的时间,下次再拿数据的时候如果发现redis保存的offset和kafka不一致,则先提交offset commit,然后从redis的最后一个offset 1开始消费数据即可。
下面我们整理下关于生成和消费所涉及到的保存数据完整的一些配置。
request.required.acks
代码语言:javascript复制0:这意味着生产者producer不等待来自broker同步完成的确认继续发送下一条(批)消息。此选项提供最低的延迟但最弱的耐久性保证(当服务器发生故障时某些数据会丢失,如leader已死,但producer并不知情,发出去的信息broker就收不到)。
1:这意味着producer在leader已成功收到的数据并得到确认后发送下一条message。此选项提供了更好的耐久性为客户等待服务器确认请求成功(被写入死亡leader但尚未复制将失去了唯一的消息)。
-1:这意味着producer在follower副本确认接收到数据后才算一次发送完成。此选项提供最好的耐久性,我们保证没有信息将丢失,只要至少一个同步副本保持存活
replication-factor
代码语言:javascript复制在创建topic时会通过replication-factor来创建副本的个数,它提高了kafka的高可用性,同时,它允许n-1台broker挂掉,设置好合理的副本因子对kafka整体性能是非常有帮助的,通常是3个,极限是5个,如果多了也会影响开销。
min.insync.replicas
代码语言:javascript复制分区ISR队列集合中最少有多少个副本,默认值是1
enable.auto.commit=false
代码语言:javascript复制由于上面的情况可知自动提交offset时,如果处理数据失败就会发生数据丢失的情况。那我们设置成手动提交。
欢迎大家交流~~~