当前位置: 首页 > 科技观察

九张图带你看懂Kafka

时间:2023-03-12 08:51:20 科技观察

现在,每个公司的互联网系统都使用Kafka。Kafka似乎是解决分布式和提高系统吞吐量的最佳松耦合解决方案之一。我大约6年前开始使用Kafka。当时,我在Aerohive工作。为了解决企业wifi设备带来的大量日志,传统的消息系统RabbitMQ和ActiveMQ已经不堪重负。这时,Kafka诞生了(2012年),并提供了一个完美的解决方案。要点:解释消息队列及其好处解释Kafka中的组件(代理、生产者、消费者、消费者组)解释为什么Kafka如此之快什么是消息系统?在认识Kafka之前,如果你不知道MessageQueue是什么,你需要补充一下。如果您已经知道,可以跳到下一段。>现代分布式系统如上所述,MessageQueue是一个在两个系统之间传输和存储消息的中间件。它的门面有以下优点:解耦:双方的处理都可以独立扩展或修改,只要保证双方遵守相同的接口约束即可。冗余:消息队列保留数据直到处理完成,避免数据丢失的风险。在很多消息队列采用的“插入-获取-删除”范式中,在从队列中移除消息之前,您的处理系统需要明确指示该消息已被处理,以确保您的数据安全保存。用完了。可伸缩性:由于消息队列解耦了您的处理,因此只需添加额外的处理即可轻松增加消息排队和处理的频率。灵活性和峰值容量:应用程序需要在流量急剧增加的情况下继续运行,但这种流量突发并不常见。毫无疑问,为了应对高峰流量而投入资源是一种巨大的浪费。使用消息队列可以让关键组件承受突然的访问压力,而不会因为意外的过载请求而完全崩溃。可恢复性:当系统的某个部分发生故障时,不会影响整个系统。消息队列降低了进程间的耦合度,即使处理消息的进程挂了,系统恢复后仍然可以继续处理加入队列的消息。顺序保证:在大多数用例中,处理数据的顺序至关重要。大多数消息队列最初都是排序的,这保证了数据将按特定顺序处理。(Kafka保证消息在分区中的顺序)缓冲:帮助控制和优化数据流经系统的速度,解决生产和消费消息的处理速度不一致的问题。异步通信:很多时候,用户不希望或不需要立即处理消息。消息队列提供了一种异步处理机制,允许用户将消息放入队列,但速度不快。将所需数量的消息放入队列并在需要时处理它们。同时我觉得最大的缺点就是复杂,它的优点完全可以忽略不计。卡夫卡是如何工作的?对于Kafka来说,从单机来看,它包括生产者、消费者和经纪人。生产者负责向broker发送消息固定topicsbroker维护一组topic,管理topic中的partitionsconsumer负责从broker中相应的topic中提取消息>Kafka组件如图所示,不同的producer可以将消息发送给多个分区在多个主题上,消费者也可以从不同的主题中消费。生产者和消费者是完全隔离的。在这个设计中,充分体现了解耦、灵活性和峰值处理能力、顺序保证和异步通信。Kafka在分布式环境中是如何工作的?1.集群多个broker和replicas。replica,partitionreplica,保证partition的高可用leader,replica,roleinproducers和consumers只与leader交互,follower中的一个角色,replica复制leader中的数据。Kafka如何保证冗余、可恢复和高可用?即使某些节点发生故障,复制也可以提供高可用性:生产者可以继续发布消息,消费者可以继续接收消息。有两种方案可确保强大且一致的数据复制:主备复制和基于仲裁的复制。这两种方案都需要选举领导者,其他人充当追随者。所有写操作都发送给领导者,然后领导者向追随者发送消息。基于Quorum的复制可以使用Raft、Paxos等算法,比如Zookeeper、GoogleSpanner等。在2n+1个节点的情况下,最多可以容忍n个节点故障。基于主库的复制以及对其他主库和备份的写操作只有成功接收到消息才能成功。对于n个节点,最多可以容忍n-1个节点故障,比如微软的PacificaA。两种方法都有优点和缺点。基于仲裁的延迟可能比主备份更好,因为基于仲裁的方法只需要一些节点才能成功写入返回。在节点数量相同的情况下,基于主备的复制可以容忍更多的节点故障,并且只要一个节点处于活动状态就可以工作。在两个节点的情况下,主备份可以提供容错,而基于仲裁的方法至少需要三个节点。Kafka采用的是第二种方式,主从模式,主要是基于容错,在双节点的情况下也能提供高可用。如果节点慢了怎么办?首先,它很少发生。如果发生这种情况,您可以设置一个超时参数来处理这种情况。Kafka的复制在分区上工作。例如,在上图中,有四个代理、一个主题和两个分区。复制因子是三。producer发送消息时,会选择一个分区,比如topic1-part1分区,将消息发送给这个分区的leader,broker2,broker3拉取消息,消息拉取后,slave发送ack给主人,这次主人只提交了这条日志。在这个过程中,producer有两种选择:一种是等待所有的replicas都被fetch成功,然后producerdisk收到success响应。另一种是等待leader写入成功,得到成功响应。第一种,可以保证异常情况下消息不会丢失,但是延迟会降低。后者的延迟得到了很大的改善,但是一旦出现异常,slave将无法在leader挂掉之前拉取到最新的消息。在这种情况下,消息可能会丢失。2.Customerbase消费者用消费者组名称标记自己,发布到主题的每条记录将传递给每个订阅消费者组中的一个消费者实例。消费者实例可以在不同的进程中或在不同的机器上。如果所有消费者实例都具有相同的消费者组,则记录将在消费者实例之间有效地平衡。如果所有的消费者实例都有不同的消费者组,那么每条记录都会被广播给所有的消费者进程,形成一个正式的文档。简而言之,消费者组是Kafka生态系统中真正的消费者。3.Controller上图是2015年KafkaController的设计,Controller和ZK共同构建了Kafka的高层架构,主要完成以下任务:管理broker和consumer的动态加入和离开。触发负载均衡。当broker或consumer加入或离开时,会触发负载均衡算法,以在consumergroup中的多个consumer之间对订阅进行负载均衡。维护每个分区的消费关系和消费信息。为什么卡夫卡这么快?Kafka中有一个过程,大量的网络数据持久化到磁盘(生产者到代理),磁盘文件通过网络发送(代理到消费者)。这个过程的性能直接影响到Kafka的整体吞吐量。1.零拷贝上图左边是传统的四拷贝和四次上下文切换。首先通过系统调用将文件数据读入内核态缓冲区(DMA拷贝)然后应用程序将内存态缓冲区数据读入用户态缓冲区(CPU拷贝)接下来用户程序通过socket发送数据读取当时的用户态缓冲区数据。Copytokernelstatebuffer(CPUcopy)最后通过DMAcopy将数据复制到NICbuffer。同时伴随着四个上下文切换。上图右侧,Kafka使用Linux2.4+内核的sendfile系统调用来实现零拷贝。数据通过DMA复制到内核状态缓冲区。直接通过DMA复制到网卡缓冲区,不需要CPU复制。因为sendfile调用完成了整个文件读取网络的传输,整个过程只有两次上下文切换,所以性能大大提升。.准确的说,Kafka的数据传输是通过TransportLayer完成的,其子类PlaintextTransportLayer通过JavaNIO的FileChannel的transferTo和transferFrom方法实现了零拷贝。2.顺序访问>比较上图可以看出,即使是顺序读取磁盘,顺序访问的巨大优势也优于基于内存的随机访问。Kafka中的每条消息都是附加的,中间没有写入或删除消息,以确保对磁盘的顺序访问。即使是顺序读写,小IO操作太多也会造成磁盘瓶颈,这时候就变成了随机读写。Kafka的策略是聚合消息并分批发送,以尽量减少磁盘访问。因此,Kafka主题和分区的数量不宜过多。通常,在64个主题/分区之后,Kafka的性能会急剧下降。3.SegmentlogKafka使用这个topic来管理消息。每个topic包含多个section,每个section对应一个逻辑日志,由多个section组成。每个段中存储多条消息。它的逻辑位置决定了消息ID,即消息ID可以直接定位到消息的存储位置,从而避免了ID到位置的额外映射。每个section对应内存中的一个index,记录每个section中第一条消息的偏移量。发布者发送给特定主题的消息将被平均分配到多个部分(随机或根据用户指定的回调函数),代理接收发布的消息并将消息添加到相应部分的最后一个部分。当Segment上的消息数量达到配置值或者消息发布时间超过阈值时,Segment上的消息会被刷盘,只有刷盘的消息订阅者才能订阅消息。一旦段达到一定大小,将不再向该段写入数据,代理将创建一个新段。这种分区划分和索引设计,不仅提高了数据读取的效率,也提高了数据操作的并行性。4.高性能BrokerKafka在Broker中的设计也是它如此之快的原因之一。首先,客户端发送的所有请求都会发送给接受者。代理中默认会有三个线程。这三个线程称为处理器。接收方不会对客户端的请求做任何处理,直接封装。将socketChannels发送给这些处理器,形成一个队列。发送的方式是轮询,即发送给第一个处理器,然后发送给第二个、第三个,再返回给第一个处理器。当消费者线程使用这些socketChannels时,它会获取request请求,数据会伴随这些request请求。默认情况下,线程池中有八个线程。这些线程用于处理请求和解析请求。如果请求是写入请求,则将其写入磁盘。如果读取,则返回结果。处理程序将从响应中读取响应数据并将其返回给客户端。这就是Kafka的三层网络架构。所以如果我们需要对Kafka进行增强调优,增加处理器,增加线程池中的处理线程,是可以达到效果的。请求和响应实际上是一种缓存效果,因为处理器生成请求的速度太快,并且没有足够的线程来及时处理请求。小结希望这篇文章对大家对Kafka的认识和初步了解有所帮助,它有哪些组件,为什么能达到如此高的性能。Kafka在现代高并发系统架构中起着至关重要的作用,并且还在快速发展,比如流媒体。本文仅从概念和简单的设计原则上对Kafka进行说明。仅仅掌握它是不够的。如果需要更深入的分析,请参考官方文档。谢谢阅读!