一、 kafka是什么?
kafka:一个分布式流处理平台
1、 流处理平台特点
- 可以让你发布和订阅流式的记录。这一方面与消息队列或者企业消息系统类似。
- 可以储存流式的记录,并且有较好的容错性。
- 可以在流式记录产生时就进行处理。
2、 概念
- Kafka作为一个集群,运行在一台或者多台服务器上
- Kafka 通过 topic 对存储的流数据进行分类
- 每条记录中包含一个key,一个value和一个timestamp(时间戳)
3、核心API
-
Producer API
允许一个应用程序发布一串流式的数据到一个或者多个Kafka topic。 -
Consumer API
允许一个应用程序订阅一个或多个 topic ,并且对发布给他们的流式数据进行处理。 -
Streams API
允许一个应用程序作为一个_流处理器_,消费一个或者多个topic产生的输入流,然后生产一个输出流到一个或多个topic中去,在输入输出流中进行有效的转换。 -
Connector API
允许构建并运行可重用的生产者或者消费者,将Kafka topics连接到已存在的应用程序或者数据系统。比如,连接到一个关系型数据库,捕捉表(table)的所有变更内容。
二、什么是Topic?Partition?GroupId?offset?
Topic
Topic就是数据的主题,简单来理解就是存放数据地方的名字。每一个Topic都可以一个或者多个消费者。当订阅同一个主题之后,只要这个主题中有新数据写入,那么所有的消费者(不同消费组)就能够消费到这条消息。
Partition (以下所说均在同一消费组前提下)
Partition就是分区的意思,在数据库中我们有分库分表的概念,那么kafka也是类似的,我们将每个Topic进行分区,然后将数据分别写入不同的分区。如果我们在创建Topic的时候没有指定分区,那么默认是50个。
数据存入分区的原则:
- 发送的数据格式key-value形式,则按照key的hash值然后在和当前可用分区数进行模运算,得到的数字就是要存入的分区。
- 没有指定key,只有value情况下,则会在首次写入数据的时候生成一个随机数,然后和当前可用分区数进行模运算,得到的数字就是要写入的分区,同时,kafka服务端会记录,以后每次写数据就开始轮询写入每个分区,不在进行计算。
分区和消费者关系:
- 同一个分区只能被同一消费组中的一个消费者消费,具有绑定关系,一旦消费者订阅成功,其他消费者就无法消费该分区
- 如果有新的消费者加入或者旧的消费者挂掉,则会重新分配分区给消费者
- 一个分区只能分配给一个消费者(同组下),但是一个消费者可以消费多个分区。分配的原则是平局分配,多余出来的从第一个消费者开始轮询,例如有10个分区,三个消费者,那么三个消费者绑定分区情况是4-3-3模式。
分区可以动态新增,但是不能删除,因为原有分区已经存在数据,如果删除会丢失数据。
GroupId
groupId主要是用于Consumer配置上,表明当前消费者属于哪一个组,这个也很重要,应为我们知道,kafka每个Topic中的消息只能被一个消费组中的一个消费者消费,也就是说我有10消费者,都加的groupId都一样,那只能有一个人消费到这个消息,如果我们想这10消费者都能消费到这个消息,那么我们就需要把这10个消费者的groupId都设置不重复。这样相当于他们就属于不同的消费组,不同消费组没有关联。
offset
offset就是当前消费到数据的哪个地方了,下次消费就会从这地方开始接着消费,消费者每次提交的offset其实是offset+1。每个分区都有自己独立的offset(其实每个leader和follwer都对应有offset,感兴趣的可以了解下HW和LEO)
offset保存在哪?
- 在kafka服务端,有个
数字
.index的文件,这个文件中记录每个offset对应分区存放数据的位置。
怎么通过offset快速查找到数据位置?
- 首先会用采用二分法拿offset去找当前这个offset存在哪个.index 文件中(文件名就是记录的offset最大值),找到index文件后,然后直接计算当前offset在当前文件的位置(每条记录的offset数据大小都是相同的,所以不需要遍历,可直接计算出存放位置).
- 拿着找到的offset对应的位置信息去.log文件下找需要消费的数据(kafka数据是写到磁盘上的,后缀为.log)
三、重要的API参数说明
Producer API (生产者配置)
NAME | DESCRIPTION | TYPE | DEFAULT |
bootstrap.servers | 这是一个用于建立初始连接到kafka集群的"主机/端口对"配置列表。不论这个参数配置了哪些服务器来初始化连接,客户端都是会均衡地与集群中的所有服务器建立连接。—配置的服务器清单仅用于初始化连接,以便找到集群中的所有服务器。配置格式: | list | |
key.serializer | 关键字的序列化类,实现以下接口: | class | |
value.serializer | 值的序列化类,实现以下接口: | class | |
acks |
| string | 1 |
buffer.memory | Producer 用来缓冲等待被发送到服务器的记录的总字节数。如果记录发送的速度比发送到服务器的速度快, Producer 就会阻塞,如果阻塞的时间超过 | long | 33554432 |
batch.size | 当将多个记录被发送到同一个分区时, Producer 将尝试将记录组合到更少的请求中。这有助于提升客户端和服务器端的性能。这个配置控制一个批次的默认大小(以字节为单位)。当记录的大小超过了配置的字节数, Producer 将不再尝试往批次增加记录。发送到 broker 的请求会包含多个批次的数据,每个批次对应一个 partition 的可用数据小的 batch.size 将减少批处理,并且可能会降低吞吐量(如果 batch.size = 0的话将完全禁用批处理)。 很大的 batch.size 可能造成内存浪费,因为我们一般会在 batch.size 的基础上分配一部分缓存以应付额外的记录。 | int | 16384 |
linger.ms | producer 会将两个请求发送时间间隔内到达的记录合并到一个单独的批处理请求中。通常只有当记录到达的速度超过了发送的速度时才会出现这种情况。然而,在某些场景下,即使处于可接受的负载下,客户端也希望能减少请求的数量。这个设置是通过添加少量的人为延迟来实现的—即,与其立即发送记录, producer 将等待给定的延迟时间,以便将在等待过程中到达的其他记录能合并到本批次的处理中。这可以认为是与 TCP 中的 Nagle 算法类似。这个设置为批处理的延迟提供了上限:一旦我们接受到记录超过了分区的 batch.size ,Producer 会忽略这个参数,立刻发送数据。但是如果累积的字节数少于 batch.size ,那么我们将在指定的时间内“逗留”(linger),以等待更多的记录出现。这个设置默认为0(即没有延迟)。例如:如果设置 | long | 0 |
retries | 若设置大于0的值,则客户端会将发送失败的记录重新发送,尽管这些记录有可能是暂时性的错误。请注意,这种 retry 与客户端收到错误信息之后重新发送记录并无区别。允许 retries 并且没有设置 | int | 0 |
onsumer API(消费者配置)
NAME | DESCRIPTION | TYPE | DEFAULT |
bootstrap.servers | 用于建立与Kafka集群的初始连接的主机/端口对列表。 客户端将使用所有服务器,而与此处指定用于引导的服务器无关—该列表仅影响用于发现整套服务器的初始主机。 该列表的格式应为 | list | |
key.serializer | 关键字的序列化类,实现以下接口: | class | |
value.serializer | 值的序列化类,实现以下接口: | class | |
group.id | 标识此使用者所属的使用者组的唯一字符串。如果使用者通过使用subscribe(topic)或基于kafka的偏移管理策略来使用组管理功能,则需要此属性。 | string | |
auto.offset.reset | earliest: 自动重置偏移到最早的偏移 latest: 自动重置偏移量为最新偏移量 none: 如果未找到使用者组的先前偏移量,则向使用者抛出异常 anything else: 向使用者抛出异常。 | string | latest |
enable.auto.commit | 如果为真,使用者的偏移量将在后台定期提交。 | boolean | true |
max.poll.records | 在一次对poll()的调用中返回的最大记录数。 | int | 500 |
max.poll.interval.ms | 使用消费者组管理时,poll()调用之间的最大延迟。这就为使用者在获取更多记录之前空闲的时间设置了上限。如果在此超时过期之前未调用poll(),则认为使用者失败,组将重新平衡,以便将分区重新分配给另一个成员。 | int | 300000 |
receive.buffer.bytes | 读取数据时使用的TCP接收缓冲区(即RCVBUF)的大小。如果值为-1,则使用OS默认值。 | int | 65536 |
四、kafka吞吐率为什么这么高?(面试必问)
- 顺序读写;
- 零拷贝
- 文件分段
- 批量发送
- 数据压缩。