既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
异步发送模式
异步发送模式「async」,在调用 send() 方法的时候指定一个 callback 函数,当 Broker 接收到返回的时候,该 callback 函数会被触发执行,通过回调函数能够对异常情况进行处理,当调用了回调函数时,只有回调函数执行完毕生产者才会结束,否则一直会阻塞。
以上三种方式各有各的特点,具体还要看业务的应用场景适合哪一种:
1)**场景1:**如果业务只是关心消息的吞吐量,且允许少量消息发送失败,也不关注消息的发送顺序的话,那么可以使用发后即忘发送「fire-and-forget」的方式,配合参数 acks = 0,这样生产者并不需要等待服务器的响应,以网络能支持的最大速度发送消息。
2)场景2:如果业务要求消息必须是按顺序发送的话,且数据只能落在一个 Partition 上,那么可以使用同步发送「sync」的方式,并结合参数来设置 retries 的值让消息发送失败时可以进行多次重试「retries > 0」,再结合参数设置「acks=all & max_in_flight_requests_per_connection=1」,可以控制生产者在收到服务器成功响应之前只能发送1条消息,在消息发送成功后立即进行 flush, 从而达到控制消息顺序发送。
3)**场景3:**如果业务需要知道消息是否发送成功,但对消息的顺序并不关心的话,那么可以用「异步async + 回调 callback 函数」的方式来发送消息,并配合参数 retries=0,待发送失败时将失败的消息记录到日志文件中进行后续处理。
32.Kafka 为什么要设计分区?
其实这个问题说来很简单, 假如不进行分区的话就如同 MySQL 单表存储一样,发消息就会被集中存储,这样会导致某台 Kafka 服务器存储 Topic 消息过多,如果在写消息压力很大的情况下,最终会导致这台 Kafka 服务器吞吐量出现瓶颈, 因此 Kafka 设计了分区的概念,同时也带来了「负载均衡」、「横向扩展」的能力,如下图所示:。
1)**负载均衡:**发送消息时可以根据分区的数量进行数据均匀分布,使其落在不同的分区上, 这样可以提高并发写性能;同时消费的时候多个订阅者可以从一个或者多个分区中同时消费数据,以支撑海量数据处理能力,提高读消息性能。
2)**横向扩展:**可以将一个 Topic 分成了多个 Partition,将不同的 Partition 尽可能的部署在不同的物理节点上,这样扩展起来非常方便,另外一个消费者可以消费多个分区中的数据,但是这样还是不能够充分的发挥横向扩展,这时候消费者组就出现了,我们用消费者组,来消费整个的 Topic,一个消费者消费 Topic 中的一个分区。
33.Kafka 如何合理设置分区数,越多越好吗?
一、Kafka 如何合理设置分区数
首先我们要了解在 Partition 级别上达到负载均衡是实现高吞吐量的关键,合适的 Partition 数量可以达到并行读写和负载均衡的目的,需要根据每个分区的生产者和消费者的目标吞吐量进行估计。
此时我们可以遵循一定的步骤来计算确定分区数:
1)首先根据某个 Topic 当前接收的数据量等经验来确定分区的初始值。
2)然后针对这个 Topic,进行测试 Producer 端吞吐量和 Consumer 端的吞吐量。
3)测试的结果, 假设此时他们的值分别是 Tp「Producer 端吞吐量」、Tc「负Consumer 端吞吐量」,总的目标吞吐量是 Tt, 单位是 MB/s, 那么结果 numPartition = Tt / max (Tp, Tc)。
4)**特殊说明:**测试 Tp 通常是很容易的,因为它的逻辑非常简单,就是直接发送消息到 Kafka 就好了。而测试 Tc 通常与应用消费消息后进行其他什么处理有关,相对复杂一些。
二、分区设置越多越好吗?
首先 Kafka 高吞吐量的原因之一就是通过 Partition 将 Topic 中的消息均衡保存到 Kafka 集群中不同的 Broker 中。
「理论上说,如果一个 Topic 分区越多,整个集群所能达到的吞吐量就越大」。但是,实际生产中 Kafka Topic 的分区数真的配置越多越好吗?很显然不是!分区数过多会有什么弊端和问题呢,我们可以从下面4个方向进行深度分析:
**
**
01
使用内存方面分析
1)**Broker端:**有很多组件都在内存中维护了分区级别的缓存,比如 Controller,FetcherManager 等,因此分区数越多,这类缓存的成本就越大。
2)**Producer端:**比如参数 batch.size,默认是16KB。它会为每个分区缓存消息,在数据积累到一定大小或者足够的时间时,累积的消息将会从缓存中移除并发往Broker 节点。这个功能是为了提高性能而设计,但是随着分区数增多,这部分缓存所需的内存占用也会更多。
3)**Consumer端:**消费者数跟分区数是直接挂钩的,在消费消息时的内存占用、以及为达到更高的吞吐性能需要开启的 Consumer 数也会随着分区数增加而增加。
02
消耗文件句柄方面分析
在 Kafka 的 Broker 中,每个 Partition 都会对应磁盘文件系统中一个目录。在 Kafka 的日志文件目录中,每个日志数据段都会分配三个文件,两个索引文件和一个数据文件。每个 Broker 会为每个日志段文件打开两个 index 文件句柄和一个 log 数据文件句柄。因此,随着 Partition 的增多,所需要保持打开状态的文件句柄数也就越多,最终可能超过底层操作系统配置的文件句柄数量限制。
**
03
端到端的延迟方面分析
首先我们得先了解 Kafka 端对端延迟是什么? Producer 端发布消息到 Consumer 端接收消息所需要的时间,即 Consumer 端接收消息的时间减去 Producer 端发布消息的时间。
在 Kafka 中只对「已提交的消息做最大限度的持久化保证不丢失」,因此 Kafka 只有在消息提交之后,才会将消息暴露给消费者。此时如果分区越多那么副本之间需要同步的数据就会越多,假如消息需要在所有 ISR 副本集合列表同步复制完成之后才能进行暴露。因此 ISR 副本集合间复制数据所花时间将是 kafka 端对端延迟的最主要部分。
此时我们可以通过加大 kafka 集群来进行缓解。比如,我们将 100 个分区 Leader 放到一个 Broker 节点和放到 10 个 Broker 节点,它们之间的延迟是不一样的。如在 10 个 Broker 节点的集群中,每个 Broker 节点平均只需要处理 10 个分区的数据复制。此时端对端的延迟将会变成原来的十分之一。
**因此根据实战经验,如果你特别关心消息延迟问题的话,此时限制每个 Broker 节点的 Partition 数量是一个非常不错的主意:**对于 N 个 Broker 节点和复制副本因子「replication-factor」为 F 的 Kafka 集群,那么整个 Kafka 集群的 Partition 数量最好不超过 「100 * N * F」 个,即单个 Broker 节点 Partition 的 Leader 数量不超过100。
**
04
高可用性方面分析
**
我们知道 Kafka 是通过多副本复制技术来实现集群的高可用和稳定性的。每个 Partition 都会有多个数据副本,每个副本分别存在于不同的 Broker 上。所有的数据副本中,其中一个数据副本为 Leader,其他的数据副本为 Follower。
**在Kafka集群内部,所有的数据副本采用自动化的方式管理且会确保所有副本之间的数据是保持同步状态的。**当 Broker 发生故障时,对于 Leader 副本所在 Broker 的所有 Partition 将会变得暂不可用。Kafka 将自动在其它副本中选择出一个 Leader,用于接收客户端的请求。这个过程由 Kafka Controller 节点 Broker 自动选举完成。
正常情况下,当一个 Broker 在有计划地停止服务时候,那么 Controller 会在服务停止之前,将该 Broker上 的所有 Leader 副本一个个地移走。对于单个 Leader 副本的移动速度非常快,从客户层面看,有计划的服务停服只会导致系统很短时间窗口不可用。
但是,当 Broker 不是正常停止服务时「kill -9 强杀方式」,系统的不可用时间窗口将会与受影响的 Partition 数量有关。如果此时发生宕机的 Broker 是 Controller 节点时, 这时 Controller 节点故障恢复会自动的进行,但是新的 Controller 节点需要从 Zookeeper 中读取每一个 Partition 的元数据信息用于初始化数据。假设一个 Kafka 集群存在10000个 Partition,从 Zookeeper 中恢复元数据时每个 Partition 大约花费2ms,则 Controller 恢复将会增加约20秒的不可用时间窗口。
**
总之,通常情况下 Kafka 集群中越多的 Partition 会带来越高的吞吐量。但是,如果 Kafka 集群中 Partition 总量过大或者单个 Broker 节点 Partition 过多,都可能会对系统的可用性和消息延迟带来潜在的负面影响,需要引起我们的重视。
34.Kafka 副本有哪两种,作用是什么?
在 Kafka 中,为实现「数据备份」的功能,保证集群中的某个节点发生故障时,该节点上的 Partition 数据不丢失,且 Kafka 仍然能够继续工作,为此 Kafka 提供了副本机制,一个 Topic 的每个 Partition 都有若干个副本,一个 Leader 副本和若干个 Follower 副本。
1)Leader 主副本负责对外提供读写数据服务。
2)Follower 从副本只负责和 Leader 副本保持数据同步,并不对外提供任何服务。
35.Kafka 读写数据这么快是如何做到的?
1.Kafka本身是分布式集群,可以采用分区技术,并行度高
2.Kafka读数据采用稀疏索引,可以快速定位要消费的数据
3.顺序写磁盘:Kafka的producer生产数据,要写入到log文件中,写的过程是一直追加到文件末端,为顺序写。
4.PageCache页缓存:Kafka重度依赖底层操作系统提供的PageCache功能。当上层有写操作时,操作系统只是将数据写入PageCache。当读操作发生时,先从PageCache中查找,如果找不到,再去磁盘中读取。实际上PageCache是把尽可能多的空闲内存都当做了磁盘缓存来使用。
5.零拷贝技术
**
kafka 为了解决内核态和用户态数据不必要 Copy 这个问题, 在读取数据的时候就引入了「零拷贝技术」。即让操作系统的 os cache 中的数据直接发送到网卡后传出给下游的消费者,中间跳过了两次拷贝数据的步骤,从而减少拷贝的 CPU 开销, 减少用户态内核态的上下文切换次数, 从而优化数据传输的性能, 而Socket缓存中仅仅会拷贝一个描述符过去,不会拷贝数据到Socket缓存,如下图所示:
在 Kafka 中主要有以下两个地方使用到了「零拷贝技术」:
1)基于 mmap 机制实现的索引文件:首先索引文件都是基于 MappedByBuffer 实现,即让用户态和内核态来共享内核态的数据缓冲区,此时数据不需要 Copy 到用户态空间。虽然 mmap 避免了不必要的 Copy,但是在不同操作系统下, 其创建和销毁成功是不一样的,不一定都能保证高性能。所以在 Kafka 中只有索引文件使用了 mmap。
2)**基于sendfile 机制实现的日志文件读写:**在 Kafka 传输层接口中有个 TransportLayer 接口,它的实现类中有使用了 Java FileChannel 中 transferTo 方法。该方法底层就是使用 sendfile 实现的零拷贝机制, 目前只是在 I/O 通道是普通的 PLAINTEXT 的时候才会使用到零拷贝机制。
04
6.消息批量发送
Kafka 在发送消息的时候并不是一条条的发送的,而是会把多条消息合并成一个批次Batch 进行处理发送,消费消息也是同样,一次拉取一批次的消息进行消费。如下图所示:
05
7.数据压缩
在 Kafka 中三个端都使用了优化后的压缩算法,压缩有助于提高吞吐量, 降低延迟并提高磁盘利用率。Kafka 底层支持多种压缩算法: lz4, snappy, gzip**, 从Kafka 2.1.0 开始新增了 ZStandard 算法, 该算法是 Facebook 开源的压缩算法, 能提供超高的压缩比。
在 Kafka 中, 压缩可能会发生在两个地方: 生产者端和Broker端。一句话总结下压缩和解压缩, 即 Producer 端压缩, Broker 端保持, Consumer 端解压缩,这样可以节省大量的网络和磁盘开销。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!