0%

kafka基础

kafka简介

Apache Kafka 是一个分布式发布 - 订阅消息系统和一个强大的消息队列中间件,可以处理大量的数据。 Kafka使用文件存储消息并且会将消息保留在磁盘上,同时在群集内复制以防止数据丢失。 Kafka 构建在 ZooKeeper 同步服务之上。 它与 Apache Storm 和 Spark 非常好地集成,用于实时流式数据分析。

kafka内相关术语:

  • 生产者和消费者:消息的发送者叫producer,消息的使用者和接受者叫consumer,生产者将数据保存到kafka集群中,消费者从中获取消息进行业务的处理。
  • broker:kafka集群中有很多台服务器,其中每一台服务器都可以存储消息,将每台服务器称为一个kafka实例,也叫做broker。
  • 主题(topic):一个topic表示同一类消息,相当于对消息进行分类,每个producer将消息发送到kafka中,都需要指定消息的topic是哪个,也就是指明这个消息属于哪一类。
  • 分区(partition):每个topic都可以分成多个partition,每个partition在kafka中其实就是一个文件,任何发布到此partition的消息都会被直接追加到log文件的尾部。为什么对topic进行分区呢:最根本的原因就是kafka基于文件进行存储,当文件内容大到一定程度时,很容易达到单个磁盘的上线,因此,采用分区的办法,一个分区对应一个文件,这样就可以将数据分别存储到不同的服务器上,另外这样可以做负载均衡,容纳更多的消费者。生产者将消息发送到kafka中时,可以不指定partition,由kafka来决定的分配到那个partition,也可以自己指定partition
  • 偏移量(offset):一个分区对应一个磁盘上的文件,而消息在文件中的位置就称为offset,offset是一个long型数字,它可以唯一标记一条消息。由于kafka并没有提供其他额外的索引机制来存储offset,kafka中文件只能顺序地读写,所以在kafka中几乎不允许对消息进行随机读写

综上,总结一下kafka有几个要点:

  • kafka 是一个基于发布-订阅的分布式消息系统(消息队列)
  • kafak 的消息数据保存在磁盘,每个 partition 对应磁盘上的一个文件,消息写入就是简单的文件追加,文件可以在集群内复制备份以防丢失
  • 即使消息被消费,kafka 也不会立即删除该消息,可以通过配置使得过一段时间后自动删除以释放磁盘空间
  • kafka依赖分布式协调服务Zookeeper,适合离线/在线信息的消费,与storm和saprk等实时流式数据分析常常结合使用

kafka基本原理

分布式和分区

kafka的分布式和分区总结来说就是:一个topic对应的多个partition分散地存储在集群中的多个broker上,存储的方式是一个partition对应一个文件,每个broker负责存储在自己机器上的partition中的消息读写。

副本

kafka可以配置partition需要备份的个数(replicas),每个partition会被备份到多台机器上,以提高可用性,备份的数量可以通过配置文件指定。

kakfa对同一partition的多个备份的管理和调度策略是:在每个partition的所有备份中选举一个最为“leader”,由leader负责处理消息的读写,其他partition作为follower只需要简单地与leader进行同步数据即可。如果原来的leader失效,会重新选举其他的folloer来成为新的leader。

至于如果选取leader,这正是Zookeeper所擅长的,kafka使用ZK在broker中选出一个Controller,用于partition分配和Leader选举。

另外,作为leader的服务器承担了该分区所有的读写请求,因此其压力是比较大的,而且,有多少个partition就意味着会有多少个leader,,kafka会将leader分散到不同的broker上,确保整体的负载均衡。

ISR

ISR的全称是in-sync replica,翻译过来就是与leader保持同步的replica集合。虽然kafka可以为一个partition配置N个replica,但是这不意味着该partition可以容忍N-1个replica失效而不丢失数据。

Kafka为partition动态维护一个replica集合。该集合中的所有replica保存的消息日志都与leader replica保持同步状态。只有这个集合中的replica才能被选举为leader,也只有该集合中所有replica都接收到了同一条消息,kafka才会将该消息置于“已提交”状态,即认为这条消息发送成功。

正常情况下,partition的所有replica(含leader replica)都应该与leader replica保持同步,即所有replica都在ISR中。因为各种各样的原因,一小部分replica开始落后于leader replica的进度。当滞后到一定程度时,Kafka会将这些replica“踢”出ISR。相反地,当这些replica重新“追上”了leader的进度时,那么Kafka会将它们加回到ISR中。这一切都是自动维护的,不需要用户进行人工干预,因而在保证了消息交付语义的同时还简化了用户的操作成本。

数据生产流程

对于生产者要写入一条记录,可以指定四个参数,分别是topic,partition, key和value,其中topic和value是必须指定的,而key和partition是可选的。

对于一条记录,先对其进行序列化,然后按照topic和partition,放进对应的发送队列中,如果partition没有指定,那么会根据以下情况来决定发送到哪个partition:

  • key有指定,按照key进行hash,相同的key去同一个partition。
  • key没有指定,Round-Robin来选partition。

producer将会和topic下所有partition leader保持socket连接,消息由producer直接通过socket发送到broker。其中partition leader的位置(ip : port)注册在zookeeper中,producer作为zookeeper client,以及注册了watch用来监听partition leader的变更事件,因此,可以准确的知道谁是当前的leader

另外,producer端采用异步发送:将多条消息暂且在客户端中buffer起来,并将它们批量的发送到broker,小数据IO太多,会拖慢整体的网络延迟,批量延迟发送提升了网络效率。

数据消费过程

对于消费者,不是以单独的形式存在的,每一个消费者都属于一个consumer group,可为每个Consumer指定group name,若不指定group name则属于默认的group,一个consumer group包含多个consumer。特别需要注意的是:订阅Topic是以一个消费组来订阅的,发送到topic的消息,只会被订阅了此topic的每个group中的一个consumer消费。一个topic可以被多个组订阅。

具体来说,是根据partition来分的,一个partition,只能被消费组里的一个消费者消费,但是可以同时被多个消费组消费,消费组里的每个消费者是关联到一个partition的,因此有这样的说法,对于同一个topic,同一个group中不能有多于partition个数的consumer,否则将会存在一些consumer无法得到消息。

在kafka,consumer采用pull方式获取消息,即consumer在和broker建立连接后,主动去pull消息,这样consumer可以根据自己的消费能去适当的获取消息并处理,且可以控制消费消息的进度。

另外partition中不存在消息状态的控制,也没有消息确认机制。当消息被consumer接收之后,需要保存Offset记录消费到哪,以前保存在ZK中,由于ZK的写性能不好,在0.10版本后,kafka把这个offset的保存从ZK中剥离,保存在一个名叫”consumeroffsets topic”的topic中。