本系列主要讲解kafka基本设计和原理分析,分以下内容:html
本节讨论Kafka如何确保消息在producer和consumer之间传输。有如下三种可能的传输保障(delivery guarantee):算法
Kafka的消息传输保障机制很是直观。当producer向broker发送消息时,一旦这条消息被commit,因为副本机制(replication)的存在,它就不会丢失。可是若是producer发送数据给broker后,遇到的网络问题而形成通讯中断,那producer就没法判断该条消息是否已经提交(commit)。虽然Kafka没法肯定网络故障期间发生了什么,可是producer能够retry屡次,确保消息已经正确传输到broker中,因此目前Kafka实现的是at least once。编程
consumer从broker中读取消息后,能够选择commit,该操做会在Zookeeper中存下该consumer在该partition下读取的消息的offset。该consumer下一次再读该partition时会从下一条开始读取。如未commit,下一次读取的开始位置会跟上一次commit以后的开始位置相同。固然也能够将consumer设置为autocommit,即consumer一旦读取到数据当即自动commit。若是只讨论这一读取消息的过程,那Kafka是确保了exactly once, 可是若是因为前面producer与broker之间的某种缘由致使消息的重复,那么这里就是at least once。缓存
考虑这样一种状况,当consumer读完消息以后先commit再处理消息,在这种模式下,若是consumer在commit后还没来得及处理消息就crash了,下次从新开始工做后就没法读到刚刚已提交而未处理的消息,这就对应于at most once了。安全
读完消息先处理再commit。这种模式下,若是处理完了消息在commit以前consumer crash了,下次从新开始工做时还会处理刚刚未commit的消息,实际上该消息已经被处理过了,这就对应于at least once。网络
要作到exactly once就须要引入消息去重机制。并发
如上一节所述,Kafka在producer端和consumer端都会出现消息的重复,这就须要去重处理。分布式
Kafka文档中说起GUID(Globally Unique Identifier)的概念,经过客户端生成算法获得每一个消息的unique id,同时可映射至broker上存储的地址,即经过GUID即可查询提取消息内容,也便于发送方的幂等性保证,须要在broker上提供此去重处理模块,目前版本尚不支持。高并发
针对GUID, 若是从客户端的角度去重,那么须要引入集中式缓存,必然会增长依赖复杂度,另外缓存的大小难以界定。性能
不仅是Kafka, 相似RabbitMQ以及RocketMQ这类商业级中间件也只保障at least once, 且也没法从自身去进行消息去重。因此咱们建议业务方根据自身的业务特色进行去重,好比业务消息自己具有幂等性,或者借助Redis等其余产品进行去重处理。
Kafka提供了很高的数据冗余弹性,对于须要数据高可靠性的场景,咱们能够增长数据冗余备份数(replication.factor),调高最小写入副本数的个数(min.insync.replicas)等等,可是这样会影响性能。反之,性能提升而可靠性则下降,用户须要自身业务特性在彼此之间作一些权衡性选择。
要保证数据写入到Kafka是安全的,高可靠的,须要以下的配置:
replication.factor
>=3,即副本数至少是3个;2<=min.insync.replicas
<=replication.factor
unclean.leader.election.enable=false
request.required.acks=-1
(all),producer.type=sync
关于做者
爱编程、爱钻研、爱分享、爱生活
关注分布式、高并发、数据挖掘
如需捐赠,请扫码