kafka中丢数据可能性探讨和kafka为什么高吞吐量
2019/2/22 星期五
在kafka中为什么高吞吐量是他的优点 见下4点优点
1、创建一个topic时,同时可以指定分区数目,分区数越多,其吞吐量也越大,但是需要的资源也越多,同时也会导致更高的不可用性,kafka在接收到生产者发送的消息之后,会根据均衡策略将消息存储到不同的分区中。因为每条消息都被append到该Partition中,属于顺序写磁盘,因此效率非常高(经验证,顺序写磁盘效率比随机写内存还要高,这是Kafka高吞吐率的一个很重要的保证)。
2、我们知道在kafaf中的数据不会一直保存着,一般默认是存储2周时间,2周时间之后会删除数据,当然这些可以通关参数去调整,
因此Kafka提供两种策略删除旧数据。一是基于时间,二是基于Partition文件大小。例如可以通过配置$KAFKA_HOME/config/server.properties,让Kafka删除一周前的数据,也可在Partition文件超过1GB时删除旧数据,
log.retention.hours=168
log.segment.bytes=1073741824
log.retention.check.interval.ms=300000
log.cleaner.enable=false
那既然删除数据和kafka的性能无关,怎么删除数据就磁盘策略以及具体的需求有关。
offset由Consumer控制,因为offet由Consumer控制,所以Kafka broker是无状态的,它不需要标记哪些消息被哪些消费过,也不需要通过broker去保证同一个Consumer Group只有一个Consumer能消费某一条消息,因此也就不需要锁机制,这也为Kafka的高吞吐率提供了有力保障。
3、有了Partition后,不同的消息可以并行写入不同broker的不同Partition里,极大的提高了吞吐率。
4、使用consumer high level api时,同一个topic的一条消息只能被同一个consumer group内的一个consumer消费,但多个consumer group可以同时消费这一个消息。
如何保证消息的可靠性传输? //kafka丢数据的可能性
https://blog.csdn.net/qq_36236890/article/details/81174504 //此链接非常的重要
kafka有几种故障的转移 //参考链接为 https://www.cnblogs.com/qingyunzong/p/9004593.html
有这么几种可能的delivery guarantee:
At most once 消息可能会丢,但绝不会重复传输
At least one 消息绝不会丢,但可能会重复传输
Exactly once 每条消息肯定会被传输一次且仅传输一次,很多时候这是用户所想要的。
丢数据可能性1
当Producer向broker发送消息时,一旦这条消息被commit,因数replication的存在,它就不会丢。但是如果Producer发送数据给broker后,遇到网络问题而造成通信中断,那Producer就无法判断该条消息是否已经commit。虽然Kafka无法确定网络故障期间发生了什么,但是Producer可以生成一种类似于主键的东西,发生故障时幂等性的重试多次,这样就做到了Exactly once。
//这一步是Producer生产者到kafka broker过程会出现的消息丢失的可能性和解决方法
丢数据可能性2
接下来讨论的是消息从broker到Consumer的delivery guarantee语义。(仅针对Kafka consumer high level API)。Consumer在从broker读取消息后,可以选择commit,该操作会在Zookeeper中保存该Consumer在该Partition中读取的消息的offset。该Consumer下一次再读该Partition时会从下一条开始读取。
如未commit,下一次读取的开始位置会跟上一次commit之后的开始位置相同。当然可以将Consumer设置为autocommit//自动提交,即Consumer一旦读到数据立即自动commit。如果只讨论这一读取消息的过程,那Kafka是确保了Exactly once。
但实际使用中应用程序并非在Consumer读取完数据就结束了,而是要进行进一步处理,而数据处理与commit的顺序在很大程度上决定了消息从broker和consumer的delivery guarantee semantic(交付保证语义)。
//这一步是Consumer消费者到kafka broker过程会出现的消息丢失的可能性和解决方法
Kafka默认保证At least once//消息绝不会丢,但可能会重复传输,并且允许通过设置Producer异步提交来实现At most once。而Exactly once要求与外部存储系统协作,幸运的是Kafka提供的offset可以非常直接非常容易得使用这种方式。
生产者传递消息到broker过程
1、Producer在发布消息到某个Partition时,先通过ZooKeeper找到该Partition的Leader,然后无论该Topic的Replication Factor为多少,Producer只将该消息发送到该Partition的Leader。
2、Leader会将该消息写入其本地Log。
3、每个Follower都从Leader pull数据。这种方式上,Follower存储的数据顺序与Leader保持一致。
4、Follower在收到该消息并写入其Log后,向Leader发送ACK。
5、一旦Leader收到了ISR中的所有Replica的ACK,该消息就被认为已经commit了,
6、Leader将增加HW并且向Producer发送ACK。
提示:
为了提高性能,每个Follower在接收到数据后就立马向Leader发送ACK,而非等到数据写入Log中。
注意:
因此,对于已经commit的消息,Kafka只能保证它被存于多个Replica的内存中,而不能保证它们被持久化到磁盘中,也就不能完全保证异常发生后该条消息一定能被Consumer消费。Consumer读消息也是从Leader读取,只有被commit过的消息才会暴露给Consumer。 //这里就有可能存在丢数据的可能性 丢数据可能性3
什么是producer的同步模式和异步模式?
同步模式
如果Producer使用同步模式则Producer会在尝试重新发送message.send.max.retries(默认值为3)次后抛出Exception,用户可以选择停止发送后续数据也可选择继续选择发送。而前者会造成数据的阻塞,后者会造成本应发往该Broker的数据的丢失。
异步模式
如果Producer使用异步模式,则Producer会尝试重新发送message.send.max.retries(默认值为3)次后记录该异常并继续发送后续数据,这会造成数据丢失并且用户只能通过日志发现该问题。同时,Kafka的Producer并未对异步模式提供callback接口。
提示:
kafka是非同步和非异步之间的一种模式(replication)策略,同步模式和异步模式都有很大的可能出现数据丢失。
同步:都完成了才可以结束;异步:丢失数据用户不知道,只能通过日志记录
Kafka的高可靠性的保障来源于其健壮的副本(replication)策略。
参考链接:https://www.cnblogs.com/qingyunzong/p/9004703.html
Leader会跟踪与其保持同步的Replica列表,该列表称为ISR(即in-sync Replica)。
Kafka的复制机制既不是完全的同步复制,也不是单纯的异步复制。
而Kafka的这种使用ISR的方式则很好的均衡了确保数据不丢失以及吞吐率。Follower可以批量的从Leader复制数据,这样极大的提高复制性能(批量写磁盘),极大减少了Follower与Leader的差距。 //批量复制数据方式,防止数据丢失1
一条消息只有被ISR里的所有Follower都从Leader复制过去才会被认为已提交。这样就避免了部分数据被写进了Leader,还没来得及被任何Follower复制就宕机了,而造成数据丢失(Consumer无法消费这些数据)。 //防止数据丢失2
zookeeper在kafka中会记录哪些信息
1、记录broker信息 比如有哪些kafka节点
2、记录了topic的partitions分区信息,poartitions的leader
3、controller注册信息
4、controller_epoch信息
[zk: 192.168.0.151(CONNECTED) 39] get /kafkagroup/controller_epoch
1 //此值为一个数字,kafka集群中第一个broker第一次启动时为1,以后只要集群中center controller中央控制器所在broker变更或挂掉,就会重新选举新的center controller,每次center controller变更controller_epoch值就会 + 1;
cZxid = 0x1500000049
ctime = Sun Jan 27 16:33:22 CST 2019
mZxid = 0x1500000049
mtime = Sun Jan 27 16:33:22 CST 2019
pZxid = 0x1500000049
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 1
numChildren = 0
5、[zk: 192.168.0.151(CONNECTED) 41] ls /kafkagroup/admin/delete_topics
6、会记录消费者和消费组信息consumers consumers group
如何保证kafka消费topic的时候,数据完全有序的,也就是不同partition之间也是有序的。
1、我们知道当前paritition内部的顺序,但是我们不能比较来自不同的两个partition的顺序,这是没有意义的。partition中的数据是有序的,不同partition间的数据丢失了数据的顺序。如果topic有多个partition,消费数据时就不能保证数据的顺序。在需要严格保证消息的消费顺序的场景下,需要将partition数目设为1。
2、对于每一个写入kafka中的数据,他们会随机的写入到当前topic中的某一个partition内,有一个例外,你提供一个key给当前的数据,这个时候,你就可以用当前的key去控制当前数据应该传入到哪个partition中。
kafka默认是消费者可以分组(Consumer Group),比如有两个消费者组A 和B,共同消费一个topic:order_info,A 和B所消费的消息不会重复
比如order_info 中有100 个消息,每个消息有一个id,编号从0-99,那么,如果A组消费0-49 号,B 组就消费50-99 号
//生产环境中也可以让多个consumer共同消费同一个topic中的数据?需要设置调整
实现方法一:代码段可以实现
使用Consumer high level API时,同一Topic的一条消息只能被同一个Consumer Group内的一个Consumer消费,但多个Consumer Group可同时消费这一消息。
实现方法二:我们可以这样,把A B两个消费者分为2个不同的组,不同的消费组可以消费同一个topic的数据。