Kafka是一个基于ZooKeeper的高吞吐量低延迟的分布式的发布与订阅消息系统,它可以实时处理大量消息数据以满足各种需求。比如基于Hadoop的批处理系统,低延迟的实时系统等。即便使用非常普通的硬件,Kafka每秒也可以处理数百万条消息,其延迟最低只有几毫秒。
那么Kafka到底是什么?简单来说,Kafka是消息中间件的一种。举个生产者与消费者的例子:
生产者生产鸡蛋,消费者消费鸡蛋。假设消费者消费鸡蛋的时候噎住了(系统宕机了),而生产者还在生产鸡蛋,那么新生产的鸡蛋就丢失了;再比如,生产者1秒钟生产100个鸡蛋(大交易量的情况),而消费者1秒钟只能消费50个鸡蛋,那过不了多长时间,消费者就吃不消了(消息堵塞,最终导致系统超时),导致鸡蛋又丢失了。这个时候我们放个篮子在生产者与消费者中间,生产者生产出来的鸡蛋都放到篮子里,消费者去篮子里拿鸡蛋,这样鸡蛋就不会丢失了,这个篮子就相当于“Kafka”。
上述例子中的鸡蛋则相当于Kafka中的消息(Message);篮子相当于存放消息的消息队列,也就是Kafka集群;当篮子满了,鸡蛋放不下了,这时再加几个篮子,就是Kafka集群扩容。
Kafka中的一些基本概念:
消息(Message)。Kafka的数据单元被称为消息。可以把消息看成是数据库里的一行数据或一条记录。为了提高效率,消息可以分组传输,每一组消息就是一个批次,分成批次传输可以减少网络开销。但是批次越大,单位时间内处理的消息就越大,因此要在吞吐量和时间延迟之间做出权衡。
服务器节点(Broker)。Kafka集群包含一个或多个服务器节点,一个独立的服务器节点被称为Broker。
主题(Topic)。每条发布到Kafka集群的消息都有一个类别,这个类别被称为主题。在物理上,不同主题的消息分开存储;在逻辑上,一个主题的消息虽然保存于一个或多个Broker上,但用户只需指定消息的主题即可生产或消费消息而不必关心消息存于何处。主题在逻辑上可以被认为是一个队列。每条消息都必须指定它的主题,可以简单理解为必须指明把这条消息放进哪个队列里。
分区(Partition)。为了使Kafka的吞吐率可以水平扩展,物理上把主题分成一个或多个分区。创建主题时可指定分区数量。每个分区对应于一个文件夹,该文件夹下存储该分区的数据和索引文件。
生产者(Producer)。负责发布消息到Kafka的Broker,实际上属于Broker的一种客户端。生产者负责选择哪些消息应该分配到哪个主题内的哪个分区。默认生产者会把消息均匀的分布到特定主题的所有分区上,但在某些情况下,生产者会将消息直接写到指定的分区。
消费者(Consumer)。从Kafka的Broker上读取消息的客户端。读取消息时需要指定读取的主题,通常消费者会订阅一个或多个主题,并按照消息生成的顺序读取他们。
Kafka架构
Kafka的消息传递流程如图所示。生产者将消息发送给Kafka集群,同时Kafka集群将消息转发给消费者。
一个典型的Kafka集群中包含若干生产者(数据可以是Web前端产生的页面内容或者服务器日志等)、若干Broker、若干消费者(可以是Hadoop集群、实时监控程序、数据仓库或其它服务)以及一个ZooKeeper集群。ZooKeeper用于管理和协调Broker。当Kafka系统中新增了Broker或者某个Broker故障失效时,ZooKeeper将通知生产者和消费者。生产者和消费者据此开始与其它Broker协调工作。
Kafka的集群架构如图所示。生产者使用Push模式将消息发送到Broker,而消费者使用Pull模式从Broker订阅并消费消息
主题与分区
Kafka通过主题对消息进行分类,一个主题可以分为多个分区,且每个分区可以存储于不同的Broker上,也就是说,一个主题可以横跨多个服务器。
如果你对HBase的集群架构比较了解,用HBase数据库做类比,可以将主题看做HBase数据库中的一张表,而分区则是将表数据拆分成了多个部分,即HRegion。不同的HRegion可以存储于不同的服务器上,而分区也是如此。
主题与分区的关系如图
分区中的每个记录都被分配了一个偏移量(offset),偏移量是一个连续递增的整数值,它唯一标识分区中的某个记录。而消费者只需保存该偏移量即可,当消费者客户端向Broker发起消息请求时需要携带偏移量。例如,消费者向Broker请求主题test的分区0中的偏移量从20开始的所有消息以及主题test的分区1中的偏移量从35开始的所有消。当消费者读取消息后,偏移量会线性递增。当然,消费者也可以按照任意顺序消费消息,比如读取已经消费过的历史消息(将偏移量重置到之前版本)。此外,消费者还可以指定从某个分区中一次最多返回多少条数据,防止一次返回数据太多而耗尽客户端的内存。
Kafka分区消息的读写如图
此外,对于已经发布的消息,无论这些消息是否被消费,Kafka都将会保留一段时间,具体的保留策略有两种:根据时间保留(例如7天)和根据消息大小保留(例如1G)。可以进行相关参数配置,选择具体策略。当消息数量达到配置的策略上限时,Kafka就会为节省磁盘空间而将旧消息删除。例如,设置消息保留两天,则两天内该消息可以随时被消费,但两天后该消息将被删除。Kafka的性能对数据大小不敏感,因此保留大量数据毫无压力。
每个主题也可以配置自己的保留策略,可以根据具体的业务进行设置。例如,用于跟踪用户活动的数据可能需要保留几天,而应用程序的度量指标可能只需要保留几个小时。
分区副本
在Kafka集群中,为了提高数据的可靠性,同一个分区可以复制多个副本分配到不同的Broker,这种方式类似于HDFS中的副本机制。如果其中一个Broker宕机,其它Broker可以接替宕机的Broker,不过生产者和消费者需要重新连接到新的Broker。Kafka分区的复制如图
分区副本
Kafka每个分区的副本都被分为两种类型:领导者副本和跟随者副本。领导者副本只有一个,其余的都是跟随者副本。所有生产者和消费者都向领导者副本发起请求,进行消息的写入与读取,而跟随者副本并不处理客户端的请求,它唯一的任务是从领导者副本复制消息,以保持与领导者副本数据及状态的一致。
如果领导者副本发生崩溃,会从其余的跟随者副本中选出一个作为新的领导者副本。领导者与跟随者在Kafka集群中的分布如图
消费者组
消费者组(Consumer Group)实际上就是一组消费者的集合。每个消费者属于一个特定的消费者组(可为每个消费者指定组名称,消费者通过组名称对自己进行标识,若不指定组名称则属于默认的组)。
传统消息处理有两种模式:队列模式和发布订阅模式。队列模式是指消费者可以从一台服务器读取消息,并且每个消息只被其中一个消费者消费;发布订阅模式是指消息通过广播方式发送给所有消费者。而Kafka提供了消费者组模式,能够同时具备这两种(队列和发布订阅)模式的特点。
Kafka规定,同一消费者组内不允许多个消费者消费同一分区的消息;而不同的消费者组,可以同时消费同一分区的消息。也就是说,分区与同一个消费者组中的消费者的对应关系是多对一而不允许一对多。消费者组与分区的关系如图
每条消息发送到主题后,只能发送给某个消费者组中的唯一一个消费者实例(可以是同一台服务器上的不同进程,也可以是不同服务器上的进程)。
显然,如果所有的消费者实例属于同一分组(有相同的分组名),该过程就是传统的队列模式,即同一消息只有一个消费者能得到;如果所有的消费者都不属于同一分组,该过程就是发布订阅模式,即同一消息每个消费者都能得到。
从消费者组与分区的角度来看,整个Kafka的架构如图
下一节我们进行Kafka集群部署演示,感谢继续关注
领取专属 10元无门槛券
私享最新 技术干货