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

Kafka是如何做到高并发几十万写的?

时间:2023-03-11 22:18:24 科技观察

文章开头有很多当下比较流行的MQ,因为我们公司在技术选型上选择了使用Kafka,所以整理了一篇关于Kafka的入门知识。通过技术选型,我们对比了业界主流的MQ。Kakfa最大的优势就是高吞吐量。Kafka是一种高吞吐、低延迟、高并发、高性能的消息中间件,广泛应用于大数据领域。一个配置良好的Kafka集群甚至可以达到每秒几十万甚至上百万的超高并发写入。那么Kafka是如何做到如此高的吞吐量和性能的呢?入门之后,我们来深入了解一下Kafka的架构设计原则。掌握了这些原则,就会在网络面试中占得先机。持久化Kafka对消息的存储和缓存依赖于文件系统,每次接收到数据都会写入磁盘。人们对“磁盘速度慢”的普遍印象,让人怀疑持久化架构能否提供强大的性能。事实上,磁盘比人们预期的要慢和快得多,这取决于人们如何使用它们。一个设计得当的磁盘结构通常可以和网络一样快。通过上图的对比,我们可以看出顺序磁盘访问在某些情况下实际上比随机内存访问要快。事实上,Kafka就是利用这个优势实现了高性能的磁盘写入。参见:http://kafka.apachecn。org/documentation.html#persistencepagecache技术+磁盘顺序写入Kafka为了保证磁盘写入性能,Kafka首先基于操作系统的pagecache实现文件写入。操作系统本身有一层缓存,叫做pagecache,是内存中的缓存。我们也可以称之为oscache,意思是操作系统自己管理的缓存。写磁盘文件时,可以直接写入os缓存,也就是只写入内存,然后由操作系统决定什么时候把os缓存中的数据刷新到磁盘。通过上图所示的方法可以大大提高磁盘文件的写入性能。其实这个方法相当于是写内存,并不是按照写磁盘的顺序。另外,还有一个非常关键的点。Kafka按磁盘顺序写入数据。它是写入磁盘,即只将数据追加到文件末尾(append),而不是在文件中随机位置修改数据。对于普通的机械硬盘,如果乱写,性能确实极低,这就涉及到磁盘寻址的问题。但是如果只是追加文件末尾来顺序写入数据,那么这种磁盘顺序写入的性能基本可以和写内存本身的性能相近。总结一下:Kafka是基于页缓存技术+磁盘顺序写入技术来实现写入数据的超高性能。所以,保证每秒写入几万甚至几十万条数据的核心点就是尽可能提高每一次数据写入的性能,让单位时间和吞吐量下写入更多的数据可以改进。.说完零拷贝技术(zero-copy),再来说说消费。大家应该都知道,我们经常从kafka消费数据,所以在消费的时候,我们其实需要从kafka的磁盘文件中读取一段数据,发送给下游的消费者,如下图所示:如果kafka在上面这个方法从磁盘读取数据并将其发送给下游消费者。大致过程是:首先检查要读取的数据是否在os缓存中,如果不在,则从磁盘文件中读取数据放入os缓存中,然后从操作系统的os缓存中复制数据到应用进程的缓存,然后在操作系统层面将数据从应用进程的缓存中复制到socket缓存中,最后从socket缓存中提取数据发送到网卡,最后发送整个过程出到下游消费者的过程如下图所示:从上图可以看出,整个过程中有两个不必要的副本,一个是从操作系统的缓存到应用进程的缓存,和然后从应用程序的缓存中将其复制回操作系统的Socket缓存中。而且,为了执行这两个副本,中间发生了几次上下文切换。一会儿是应用程序在执行,一会儿是上下文切换到操作系统执行。所以这种方式读取数据是比较耗性能的。为了解决这个问题,Kafka在读取数据的时候引入了零拷贝技术。也就是说直接将操作系统缓存中的数据发送给网卡再传输给下游的消费者,跳过了中间复制数据的两步,只会在Socket中复制一个描述符缓存,并且不会进行复制。数据到套接字缓存。让我们来体验一下这个微妙的过程。有了零拷贝技术,就不需要先将os缓存中的数据拷贝到应用缓存中,再从应用缓存中拷贝数据到Socket缓存中。两个副本都被省略,所以称为零副本。Socket缓存只是将数据描述符复制过去,然后数据直接从os缓存中发送到网卡。这个过程大大提高了数据消费时读取文件数据的性能。而且你会注意到,从磁盘读取数据的时候,你会先查看os缓存内存中是否有。如果是这样的话,读取的数据实际上是直接从内存中读取的。如果Kafka集群调优好,会发现大量数据直接写入os缓存,读取数据时再从os缓存中读取。相当于Kafka完全基于内存提供数据写入和读取,所以整体性能会非常高。总结通过研究Kafka的优秀设计,了解了Kafka底层页面缓存技术的使用,磁盘顺序写入的思想,以及零拷贝技术的使用,使得Kafka能够有如此高的性能,实现了上百个每秒数千条数据。吞吐量。名词解释吞吐量(TPS):吞吐量是指网络、设备、端口、虚电路或其他设施在单位时间内成功传输的数据数(以比特、字节、数据包等为单位)