0


kafka基本原理及消费配置

一、概念理解
Kafka是一个分布式、支持分区的(partition)、多副本的(replica),基于zookeeper协调的分布式消息系统,它的最大的特性就是可以实时的处理大量数据。
1、Kafka的特性

  • 高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒
  • 可扩展性:kafka集群支持热扩展
  • 持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失
  • 容错性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败)
  • 高并发:支持数千个客户端同时读写 2、Kafka一些重要设计思想
  • Consumergroup:各个consumer可以组成一个组,每个消息只能被组中的一个consumer消费,如果一个消息可以被多个consumer消费的话,那么这些consumer必须在不同的组。
  • 消息状态:在Kafka中,消息的状态被保存在consumer中,broker不会关心哪个消息被消费了被谁消费了,只记录一个offset值(指向partition中下一个要被消费的消息位置),这就意味着如果consumer处理不好的话,broker上的一个消息可能会被消费多次。
  • 消息持久化:Kafka中会把消息持久化到本地文件系统中,并且保持极高的效率。
  • 消息有效期:Kafka会长久保留其中的消息,以便consumer可以多次消费,当然其中很多细节是可配置的。
  • 批量发送:Kafka支持以消息集合为单位进行批量发送,以提高push效率。
  • push-and-pull :Kafka中的Producer和consumer采用的是push-and-pull模式,即Producer只管向broker push消息,consumer只管从broker pull消息,两者对消息的生产和消费是异步的。
  • Kafka集群中broker之间的关系:不是主从关系,各个broker在集群中地位一样,我们可以随意的增加或删除任何一个broker节点。
  • 负载均衡方面: Kafka提供了一个 metadata API来管理broker之间的负载(对Kafka0.8.x而言,对于0.7.x主要靠zookeeper来实现负载均衡)
  • 分区机制partition:Kafka的broker端支持消息分区,Producer可以决定把消息发到哪个分区,在一个分区中消息的顺序就是Producer发送消息的顺序。 二、消息队列通信的模式 1、点对点模式

2、发布订阅模式
一个或多个生产者产生的消息能够被多个消费者同时消费的情况

三、Kafka的架构原理
上面简单的介绍了为什么需要消息队列以及消息队列通信的两种模式,下面主角介绍Kafka。Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据,具有高性能、持久化、多副本备份、横向扩展能力。。
1、基础架构与名词解释

  • Producer:Producer即生产者,消息的产生者,是消息的入口。
  • Broker:Broker是kafka实例,每个服务器上有一个或多个kafka的实例,我们姑且认为每个broker对应一台服务器。每个kafka集群内的broker都有一个不重复的编号,如图中的broker-0、broker-1等……
  • Topic:消息的主题,可以理解为消息的分类,kafka的数据就保存在topic。在每个broker上都可以创建多个topic。
  • Partition:Topic的分区,每个topic可以有多个分区,分区的作用是做负载,提高kafka的吞吐量。同一个topic在不同的分区的数据是不重复的,partition的表现形式就是一个一个的文件夹!
  • Replication:每一个分区都有多个副本,副本的作用是做备胎。当主分区(Leader)故障的时候会选择一个备胎(Follower)上位,成为Leader。在kafka中默认副本的最大数量是10个,且副本的数量不能大于Broker的数量,follower和leader绝对是在不同的机器,同一机器对同一个分区也只可能存放一个副本(包括自己)。
  • Message:每一条发送的消息主体。
  • Consumer:消费者,即消息的消费方,是消息的出口。
  • Consumer Group:我们可以将多个消费组组成一个消费者组,在kafka的设计中同一个分区的数据只能被消费者组中的某一个消费者消费。同一个消费者组的消费者可以消费同一个topic的不同分区的数据,这也是为了提高kafka的吞吐量!
  • Zookeeper:kafka集群依赖zookeeper来保存集群的的元信息,来保证系统的可用性。 2、工作流程分析 (1)发送数据 Producer在写入数据的时候永远的找leader,不会直接将数据写入follower,消息写入leader后,follower是主动的去leader进行同步的!producer采用push模式将数据发布到broker,每条消息追加到分区中,顺序写入磁盘,所以保证同一分区内的数据是有序的。

1.方便扩展:因为一个topic可以有多个partition,所以我们可以通过扩展机器去轻松的应对日益增长的数据量。
2.提高并发:以partition为读写单位,可以多个消费者同时消费数据,提高了消息的处理效率。
kafka如果某个topic有多个partition,producer又怎么知道该将数据发往哪个partition呢?kafka中有几个原则:
1.partition在写入的时候可以指定需要写入的partition,如果有指定,则写入对应的partition。
2.如果没有指定partition,但是设置了数据的key,则会根据key的值hash出一个partition。
3.如果既没指定partition,又没有设置key,则会轮询选出一个partition。
保证消息不丢失是一个消息队列中间件的基本保证,那producer在向kafka写入消息的时候,怎么保证消息不丢失呢?其实上面的写入流程图中有描述出来,那就是通过ACK应答机制!在生产者向队列写入数据的时候可以设置参数来确定是否确认kafka接收到数据,这个参数可设置的值为0、1、all。

  • 0代表producer往集群发送数据不需要等到集群的返回,不确保消息发送成功。安全性最低但是效率最高。
  • 1代表producer往集群发送数据只要leader应答就可以发送下一条,只确保leader发送成功。
  • all代表producer往集群发送数据需要所有的follower都完成从leader的同步才会发送下一条,确保leader发送成功和所有的副本都完成备份。安全性最高,但是效率最低。 最后要注意的是,如果往不存在的topic写数据,能不能写入成功呢?kafka会自动创建topic,分区和副本的数量根据默认配置都是1。 (2)保存数据 Producer将数据写入kafka后,集群就需要对数据进行保存了!kafka将数据保存在磁盘,可能在我们的一般的认知里,写入磁盘是比较耗时的操作,不适合这种高并发的组件。Kafka初始会单独开辟一块磁盘空间,顺序写入数据(效率比随机写入高)。 (1)Partition 结构 前面说过了每个topic都可以分为一个或多个partition,如果你觉得topic比较抽象,那partition就是比较具体的东西了!Partition在服务器上的表现形式就是一个一个的文件夹,每个partition的文件夹下面会有多组segment文件,每组segment文件又包含.index文件、.log文件、.timeindex文件(早期版本中没有)三个文件, log文件就实际是存储message的地方,而index和timeindex文件为索引文件,用于检索消息。 如上图,这个partition有三组segment文件,每个log文件的大小是一样的,但是存储的message数量是不一定相等的(每条的message大小不一致)。文件的命名是以该segment最小offset来命名的,如000.index存储offset为0~368795的消息,kafka就是利用分段+索引的方式来解决查找效率的问题。

(2)Message结构
上面说到log文件就实际是存储message的地方,我们在producer往kafka写入的也是一条一条的message,那存储在log中的message是什么样子的呢?消息主要包含消息体、消息大小、offset、压缩类型……等等!我们重点需要知道的是下面三个:

  • offset:offset是一个占8byte的有序id号,它可以唯一确定每条消息在parition内的位置!
  • 消息大小:消息大小占用4byte,用于描述消息的大小。
  • 消息体:消息体存放的是实际的消息数据(被压缩过),占用的空间根据具体的消息而不一样。 (3)存储策略 无论消息是否被消费,kafka都会保存所有的消息。那对于旧数据有什么删除策略呢?
  • 基于时间,默认配置是168小时(7天)。
  • 基于大小,默认配置是1073741824。 需要注意的是,kafka读取特定消息的时间复杂度是O(1),所以这里删除过期的文件并不会提高kafka的性能! (3)消费数据 消息存储在log文件后,消费者就可以进行消费了。在讲消息队列通信的两种模式的时候讲到过点对点模式和发布订阅模式。Kafka采用的是发布订阅模式,消费者主动的去kafka集群拉取消息,与producer相同的是,消费者在拉取消息的时候也是找leader去拉取。 多个消费者可以组成一个消费者组(consumer group),每个消费者组都有一个组id!同一个消费组者的消费者可以消费同一topic下不同分区的数据,但是不会组内多个消费者消费同一分区的数据 图示是消费者组内的消费者小于partition数量的情况,所以会出现某个消费者消费多个partition数据的情况,消费的速度也就不及只处理一个partition的消费者的处理速度!如果是消费者组的消费者多于partition的数量,那会不会出现多个消费者消费同一个partition的数据呢?上面已经提到过不会出现这种情况!多出来的消费者不消费任何partition的数据。所以在实际的应用中,建议消费者组的consumer的数量与partition的数量一致!

在保存数据的小节里面,我们聊到了partition划分为多组segment,每个segment又包含.log、.index、.timeindex文件,存放的每条message包含offset、消息大小、消息体……我们多次提到segment和offset,查找消息的时候是怎么利用segment+offset配合查找的呢?假如现在需要查找一个offset为368801的message是什么样的过程呢?我们先看看下面的图:

1.先找到offset的368801message所在的segment文件(利用二分法查找),这里找到的就是在第二个segment文件。
2.打开找到的segment中的.index文件(也就是368796.index文件,该文件起始偏移量为368796+1,我们要查找的offset为368801的message在该index内的偏移量为368796+5=368801,所以这里要查找的相对offset为5)。由于该文件采用的是稀疏索引的方式存储着相对offset及对应message物理偏移量的关系,所以直接找相对offset为5的索引找不到,这里同样利用二分法查找相对offset小于或者等于指定的相对offset的索引条目中最大的那个相对offset,所以找到的是相对offset为4的这个索引。
3.根据找到的相对offset为4的索引确定message存储的物理偏移位置为256。打开数据文件,从位置为256的那个地方开始顺序扫描直到找到offset为368801的那条Message。
这套机制是建立在offset为有序的基础上,利用segment+有序offset+稀疏索引+二分查找+顺序查找等多种手段来高效的查找数据!至此,消费者就能拿到需要处理的数据进行处理了。那每个消费者消费到的offset已经直接维护在kafk集群的__consumer_offsets这个topic中,key是group.id+topic+分区号,value就是当前offset的值。
四、消费者配置

消费者实例<=partion数量
3.1 offset
Offset,消息位移,它表示分区中每条消息的位置信息,是一个单调递增且不变的值。换句话说,offset可以用来唯一的标识分区中每一条记录,消费者消费完一条消息记录之后,需要提交offset来告诉Kafka Broker自己消费到哪里了。
(1)自动提交:
Kafka为了使我们能够专注于自己的业务逻辑,提供了自动提交offset的功能,这也是默认配置项。

我们需要关注以下两个配置参数:

  • enable.auto.commit:是否开启自动提交offset功能,默认是true
  • auto.commit.interval.ms:自动提交offset的时间间隔,默认是5s 自动提交可能存在消息重复消费或丢失 一个典型的自动提交的边界场景是分区再均衡场景。假设我们采用默认 5 秒的自动提交时间间隔,在本分区最近一次提交后 3 秒发生了故障,再均衡之后,新的消费者从本分区的消费位点开始读取并处理消息。由于消费位点是故障前 3 秒前自动提交的,在这 3 秒之间读取的消息及其影响的消费位点没有被提交,因此这些数据将被重复处理。 自动提交的配置下,每一次 poll 调用都会提交上一次 poll 移动到的消费位点,在调用消费者的 close 方法时也会触发自动提交。通常来说,自动提交的消费位点总是不大于消费者实际处理的消息。但是,如果在轮询时拉取到一批消息,并在处理完所有消息之前抛出异常,就有可能导致自动提交时按照这批消息处理过的假设进行提交,从而导致部分消息被跳过,不被处理的情形 (2)手动提交 虽然自动提交offset带来了很大的便利,但是在消息的可靠性上不太容易掌控,因此Kafka也提供了手动提交offset这个功能。

(3)指定offset消费方式
Kafka针对offset的消费方式提供了三种类型:earliest | latest | none,默认是latest,即从最新的offset开始消费。
(1)earliest:自动将偏移量 重置为最早的,–fromfromfrom。
(2)latest(默认值):自动将偏移量重置为最新偏移量。
(3)none :如果未找到消费者组的先前偏移量,则向抛出异常。

3.2 session 超时和心跳监测
session.timeout.ms:consumer 的 session 超时时间,默认 10s。超过这个时间将会认为 consumer 挂了。将 reblance (重新平衡)消费者。
heartbeat.interval.ms:心跳监测时间,默认值 3s。consumer 每 3s发送一次心跳给协调者(broker)。
3.3 拉取大消息
消费过程是由客户端主动去服务端拉取消息的,在拉取大消息时,需要注意控制拉取速度,注意修改配置:
max.poll.records:默认值:500。如果单条消息超过1 MB,建议设置为1。
fetch.max.bytes:设置比单条消息的大小略大一点。
max.partition.fetch.bytes:设置比单条消息的大小略大一点。
3.4 提高消费速度
(1)可以考虑给Kafka增加Topic的分区数,并同步增加消费者Consumer的实例数

(2)增加并发消费线程
concurrency: 并发线程数,表示一个消费者实例启动的Kafka消费者线程的数量,这多个线程可以并行消费来自一个或多个分区的消息
(3)提高每批次拉取的数量

标签: kafka 分布式

本文转载自: https://blog.csdn.net/xie_peng_cheng/article/details/136929026
版权归原作者 myco.xie 所有, 如有侵权,请联系我们删除。

“kafka基本原理及消费配置”的评论:

还没有评论