首页 > 代码库 > kafka学习总结

kafka学习总结

kafka是一种分布式的,基于发布订阅的消息系统。具有以下几个方面的特性。

1.能够提供常数时间的消息持久化及访问性能。

2.高吞吐率。廉价的商用机器上能够达到每秒100k条的消息传输。

3.支持kafka server间的消息消息分区,分布式消费,分区内消息的顺序性。

4.支持水平扩展。

5.支持离线数据处理和实时数据处理。

kafka架构

kafka的拓扑结构:

1.producer:消息生产者。

2.consumer:消息消费者。

3.broker:kafka集群由一个或者多个服务器组成。服务器被称为broker。消息由producer发送到broker。consumer从borker中消费消息。

4.Toptic:消息主题。每条发送到kafka集群的消息都有一个Topic,物理上不同topic的消息分开存储 。逻辑上一个topic的消息保存于一个或多个broker上。

5.partition:消息分区。每个topic包括一个或多个partition

6.consumer group:每个consumer属于特定的group,可以为每个consumer指定group name,不指定,则属于默认的group。

  1. 技术分享

                                                          kafka拓扑结构图

 

从图中我么可以看出。kafka集群由若干producer,consumer grouper,broker,zookeeper组成。kafka通过zookeeper来管理集群的配置,以及在consumer发生变化进行reblance。

topic & partion

topic在逻辑上可以被理解为一个队列,消息必须指明它的topic,可以理解为消息必须指定放到哪一个队列中。为了提高kafka的吞吐率,物理上把topic分成一个或多个partion,每个partion物理上对应一个文件夹。该文件夹下存储该partition下的消息及索引文件。

若创建两个topic,topic1和topic2,每个topic对应有13个和19个分区,其中集群中共有8个结点,则集群中会创建32个文件夹。如下图所示:

技术分享

每个日志文件都是一个log entry序列,每个log entry序列包含一个四字节整形值(消息长度,1+4+n),一字节magic value,四字节的crc校验码,n字节的消息体长度组成。每条消息都有在当前partition下的唯一的64字节的offset。它指明了消息的的存储位置,磁盘上消息的存储格式如下:

message length : 4 bytes (value: 1+4+n)
"magic" value : 1 byte 
crc : 4 bytes 
payload : n bytes 
这个log entries并非由一个文件组成,而是分成多个segment,每个segment以该segment下的第一条消息的offset命名并以kafka为后缀。另外会有一个索引文件,他标明每个
segment下的log entry的offset的范围,如下图所示:
技术分享


kafka高吞吐率的一个很重要的保证就是消息会被顺序写到partition中。如下图所示:
技术分享


对于传统的消息系统,通常会删除已经消费过的消息,kafka会保存已经消费的消息。并且根据实际情况对已经消费的消息提供两种删除策略,分别是基于消息的消费时间以及partition文件的大小。
我们可以通过配置文件$KAFKA_HOME/config/server.properties,让Kafka删除一周前的数据,也可在Partition文件超过1GB时删除旧数据。配置如下所示:

# The minimum age of a log file to be eligible for deletion
log.retention.hours=168
# The maximum size of a log segment file. When this size is reached a new log segment will be created.
log.segment.bytes=1073741824
# The interval at which log segments are checked to see if they can be deleted according to the retention policies
log.retention.check.interval.ms=300000
# If log.cleaner.enable=true is set the cleaner will be enabled and individual logs can then be marked for log compaction.
log.cleaner.enable=false

对于consumer消费的消息,消息的offset由consumer来控制,对于kafka来说消息时无状态的。kafka也不保证一个消息只由consumer group的一个consumer来消费,
从而不需要锁机制,这也是kafka高吞吐率的一个重要保证。

push&pull

kafka采用push机制来推送消息到broker,pull机制来消费消息,push与pull机制各由优缺点。kafka采取pull机制消费消息可以简化broker的设计,push机制采取尽快的投递消息,
这样很可能导致consumer来不及处理消息从而导致网络拥塞或者拒绝服务,通过consumer自己来控制何时消费消息。即可批量消费又可逐条消费,能够选择不同的提交方式,从而实现不同传输语义。

消息递送的保证机制。
  • At most once 消息可能会丢,但绝不会重复传输
  • At least one 消息绝不会丢,但可能会重复传输
  • Exactly once 每条消息肯定会被传输一次且仅传输一次,很多时候这是用户所想要的。

当Producer向broker发送消息时,一旦这条消息被commit,因数replication的存在,它就不会丢。但是如果Producer发送数据给broker后,遇到网络问题而造成通信中断,那Producer就无法判断该条消息是否已经commit。虽然Kafka无法确定网络故障期间发生了什么,但是Producer可以生成一种类似于主键的东西,发生故障时幂等性的重试多次,这样就做到了Exactly once。截止到目前(Kafka 0.8.2版本,2015-03-04),这一Feature还并未实现,有希望在Kafka未来的版本中实现。(所以目前默认情况下一条消息从Producer到broker是确保了At least once,可通过设置Producer异步发送实现At most once)。

当Producer向broker发送消息时,一旦这条消息被commit,因数replication的存在,它就不会丢。但是如果Producer发送数据给broker后,遇到网络问题而造成通信中断,那Producer就无法判断该条消息是否已经commit。虽然Kafka无法确定网络故障期间发生了什么,但是Producer可以生成一种类似于主键的东西,发生故障时幂等性的重试多次,这样就做到了Exactly once。截止到目前(Kafka 0.8.2版本,2015-03-04),这一Feature还并未实现,有希望在Kafka未来的版本中实现。(所以目前默认情况下一条消息从Producer到broker是确保了At least once,可通过设置Producer异步发送实现At most once)。

  • 读完消息先commit再处理消息。这种模式下,如果Consumer在commit后还没来得及处理消息就crash了,下次重新开始工作后就无法读到刚刚已提交而未处理的消息,这就对应于At most once

  • 读完消息先处理再commit。这种模式下,如果在处理完消息之后commit之前Consumer crash了,下次重新开始工作时还会处理刚刚未commit的消息,实际上该消息已经被处理过了。这就对应于At least once。在很多使用场景下,消息都有一个主键,所以消息的处理往往具有幂等性,即多次处理这一条消息跟只处理一次是等效的,那就可以认为是Exactly once。(笔者认为这种说法比较牵强,毕竟它不是Kafka本身提供的机制,主键本身也并不能完全保证操作的幂等性。而且实际上我们说delivery guarantee 语义是讨论被处理多少次,而非处理结果怎样,因为处理方式多种多样,我们不应该把处理过程的特性——如是否幂等性,当成Kafka本身的Feature)

  • 如果一定要做到Exactly once,就需要协调offset和实际操作的输出。精典的做法是引入两阶段提交。如果能让offset和操作输入存在同一个地方,会更简洁和通用。这种方式可能更好,因为许多输出系统可能不支持两阶段提交。比如,Consumer拿到数据后可能把数据放到HDFS,如果把最新的offset和数据本身一起写到HDFS,那就可以保证数据的输出和offset的更新要么都完成,要么都不完成,间接实现Exactly once。(目前就high level API而言,offset是存于Zookeeper中的,无法存于HDFS,而low level API的offset是由自己去维护的,可以将之存于HDFS中)

总之,Kafka默认保证At least once,并且允许通过设置Producer异步提交来实现At most once。而Exactly once要求与外部存储系统协作,幸运的是Kafka提供的offset可以非常直接非常容易得使用这种方式。

 

 

 

kafka学习总结