Kafka基本知识一 Producer and Consumer

由于现在版本更新较快,很多理论的东西和之前也有很多不同之处,这里描述的基本知识以最新版0.11为基准。 使用消息队列我们最为关心的是消息队列如何发布消息,如何消费消息,以及消息的可靠保证,理解了这几个问题,那么对某个消息队列产品基本就了解了。

从发送消息,到消费消息,一共也就2个阶段,这里我们一个一个来谈,先说一下Producer:

当我们发送消息的时候如何认为就发送成功了? Kafka默认采用async的模式来发送,通过batch方式批量发送,利用buffer来提高效率,消息发送到了buffer就认为发送成功,然后返回ack,告诉producer发送成功了。 如果没有收到ack,那么Producer会retry,这里有一个参数retires来控制次数,只要在这个数字之内收到ack就表示发送成功了。不做深入剖析的话,感觉已经好像没啥问题了。实际上远不止于此,如果因为网络问题,超过了retry次数,很显然,这个消息你就丢了, 还有一种可能性,因为某种问题,没有返回ack,但实际上已经发送成功了,那么producer再次发送,这个时候消息又重复了。

那么如何保证消息exactly once 发送呢? 在0.11版本中已经实现了事务型发送,每个producer分配一个ID, 然后每个消息通过一个sequence id 来保证唯一,也就是说 producer再发送的时候,根据sequence id能够知道是否有重复消息,这样就保证了在发送阶段 exactly once . 

另外再提一点,因为kafka是分布式的,一个topic有一个leader,多个follower, 因此ack也有一个参数acks来控制,分辨为 0, 1 ,-1, all , 如果为0,就是不发送ack,producer发送出去就不管了,你收没收到和它没关系,如果你要求不高,acks=0是性能最好的,但是消息丢失肯定也存在,具体1,-1,ALL的含义,大家去看文档描述。


接下来再谈一下Cousumer:

通常消息会有2个流程,第一拿到消息,保存offset,处理消息,第二拿到消息,处理消息,保存offset,这2种都存在问题,第一种如果保存offset之后,服务器crash了,下次你再启动的时候会从保存的offset之后拿消息,很显然,你丢失了之前一条消息,第二种就是我处理完了消息,还没来得及保存,服务器crash了,这个时候又会重复消息一条消息。

那么如何保证consumer的exactly once 呢?  实际上来说官方文档的描述有点牵强,在kafka stream里,它能保证,因为采用事务性producer之后,再设置read_commited的consumer来达到exactly one,但是如果你和其他系统结合,并没有这么简单。比如我想把offset存储到HBASE, 那么即使你用了事务性producer,也无法保证consumer的offset.

0.9版本之前的kafka offset默认存储在zk,路径为: /consumers/group-id/offsets/xxxx , 之后的版本kafka有一个topic,__consumer_offset专门来管理consumer的offset。 为了继续融合之前版本,设置offset_storage来表示你要存储到ZK还是kafka,(实际上在0.9的版本我没找到offset_storage 这个参数),  


通过如下命令可以读取__consumer_offset的内容,首先建一个文件,名字随便给,我使用config,写入exclude.internal.topics=false, 

kafka-console-consumer.sh --topic __consumer_offsets --zookeeper datanode01.isesol.com:2181,datanode01.isesol.com:2181,datanode02.isesol.com:2181,datanode03.isesol.com:2181,datanode04.isesol.com:2181 --formatter "kafka.coordinator.GroupMetadataManager\$OffsetsMessageFormatter" --consumer.config config --from-beginning 

内容大致如下:

[test10,jlwang,0]::[OffsetMetadata[838,NO_METADATA],CommitTime 1500477787579,ExpirationTime 1500564187579]
[test10,jlwang,0]::[OffsetMetadata[838,NO_METADATA],CommitTime 1500477788526,ExpirationTime 1500564188526]
[test10,jlwang,1]::[OffsetMetadata[852,NO_METADATA],CommitTime 1500477788526,ExpirationTime 1500564188526]
[test10,jlwang,1]::[OffsetMetadata[852,NO_METADATA],CommitTime 1500477789506,ExpirationTime 1500564189506]
[test10,jlwang,0]::[OffsetMetadata[838,NO_METADATA],CommitTime 1500477789539,ExpirationTime 1500564189539]
[test10,jlwang,1]::[OffsetMetadata[852,NO_METADATA],CommitTime 1500477790551,ExpirationTime 1500564190551]
[test10,jlwang,0]::[OffsetMetadata[838,NO_METADATA],CommitTime 1500477790552,ExpirationTime 1500564190552]
[test10,jlwang,1]::[OffsetMetadata[852,NO_METADATA],CommitTime 1500477791506,ExpirationTime 1500564191506]

另外再浅浅的谈一下我对kafka的理解,kafka有2个天生的弊端,第一就是消息只在单个partition有顺序,多个partition没有顺序, 另外就是从上面介绍,其实要实现axactly once 还是有点麻烦的,这个对于要求比较高的系统, kafka 是不太适合使用的。

所以我个人理解是,只要你系统对消息要求排序,(虽然kafka单个partition是顺序的,但是很显然性能不咋地), 还有你对exactly once要求高,就用别的MQ吧,如果你是大量数据,对数据不是那么敏感,丢一条,多一条无所谓,那么考虑kafka,    Kafka会丢失数据吗? 原理上不会。数据写入leader之后,即使写入的仅仅是buffer, 如果你有复制,并设置了ack = 1甚至all ,保证此消息确实成功了,即使你的leader down了也无所谓。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tom_fans

谢谢打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值