kafka 系列 (三) kafka怎么完成数据的高速读写?---kafka四大优化读写性能奠定消息中间件的统治地位

写在前面: 我是「nicedays」,一枚喜爱做特效,听音乐,分享技术大数据开发猿。这名字是来自world order乐队的一首HAVE A NICE DAY。如今,走到现在很多坎坷和不顺,如今终于明白nice day是需要自己赋予的。
白驹过隙,时光荏苒,珍惜当下~~
写博客一方面是对自己学习的一点点总结及记录,另一方面则是希望能够帮助更多对大数据感兴趣的朋友。如果你也对 大数据与机器学习感兴趣,可以关注我的动态 https://blog.csdn.net/qq_35050438,让我们一起挖掘数据与人工智能的价值~

kafka怎么完成数据高速读写?

kafka会把收到的消息都写入到硬盘中,他绝对不会丢失数据,为了优化写入速度kafka采用了两个技术,顺序写入和MMFile(Memory Mapped File)

一:顺序写入:

Kafka选择顺序写入磁盘:

有人一看到写入磁盘,就认为一定比内存慢,其实不然

  • 磁盘顺序写入速度是超过内存的随机读写的
  • 写入磁盘同时避免了JVM的GC效率低,内存占用大
  • 系统冷启动后,磁盘缓存依然可用。

如何顺序写入?

在kafka每个partition都是一个文件,收到消息后kafka会把数据插入到文件末尾

在这里插入图片描述

这个办法无法删除数据,所以kafka本身会把所有数据保留下来,

所以每个consumer对每个topic都有一个offset来表示读取到了第几条数据。

二:zero-copy

零拷贝不是指0次复制,而是指0次调用CPU消耗资源

零拷贝技术基于DMA实现(Direct Memory Access),也就是让硬件跳过CPU调度,直接访问主内存。

前提:kafka主要对数据的操作为读和写,不对数据修改

在这里插入图片描述

因此先以read读操作为例:

  • 当我们作为应用程序读取read()操作数据时,底层会采用一次DMA技术读取磁盘文件存储到内核空间的读取缓存区,供应用程序读取。
  • 可读取缓存区属于内核空间,所以我们应用程序利用cpu进行一次上下文切换(用户态-> 内核态->用户态),获取读取内核空间缓存区的数据,将readbuffer数据读取到用户缓存区,回到用户程序后然后继续操纵数据。发生了2次copy,一次cpu调用

再以send写操作为例:

  • 我们最终目的是将文件发送到另外一个服务里,所以需要调用socket进行通信传输,此时我们们应用程序再次利用cpu进行一次上下文切换(用户态-> 内核态->用户态),将用户态缓冲区的文件数据,copy到内核空间的socket buffer里,socket再通过DMA技术将数据从目标套接字相关的缓存区传到相关的协议引擎进行发送。应用程序执行完回到用户态,发生了2次copy,一次cpu调用

零拷贝优化实现0次调用cpu

上述进行了2次cpu调用,我们发现其实不对数据本身进行修改的话,一切都可以在内核空间操作,不需要通过用户空间也能完成read+send

此时的优化需要底层网络接口支持收集操作

  • 在linux2.4及后版本,socketbuffer描述符做了相应调整,使DMA自带收集功能,对于用户来说,调用两个方法合并成transferTo()方法,且内部的流程已然改变。

在这里插入图片描述

  • transferTo()方法英发DMA将文件内容复制到内核读取缓冲区
  • 将数据位置和长度信息的描述符追加到socket buffer,避免了内容整体copy,DMA 引擎直接把数据从内核缓冲区传到协议引擎,全程都是DMA参与,从而消除CPU参与的数据复制消耗

以kafka为例,如果有100个消费者消费一份数据,在普通的数据传输方式下,复制次数一共是100*4 = 400次,cpu调用次数一共是100*2 = 200次;而使用了零拷贝技术之后,复制次数一共是100+1 = 101次(1次数据从磁盘到内核读取缓冲区,100次发送给100个消费者消费),cpu调用次数一共是0次。极大的提高了数据读写效率。

三:Memory Mapped Files

即便是顺序写入硬盘,硬盘的访问速度还是不可能追上内存。所以Kafka的数据并 不是实时的写入硬盘 ,它充分利用了现代操作系统 分页存储 来利用内存提高I/O效率。

Memory Mapped Files(后面简称mmap)也被翻译成 内存映射文件 ,在64位操作系统中一般可以表示20G的数据文件,它的工作原理是直接利用操作系统的Page来实现文件到物理内存的直接映射。完成映射之后你对物理内存的操作会被同步到硬盘上(操作系统在适当的时候)。

通过mmap,进程像读写硬盘一样读写内存(当然是虚拟机内存),也不必关心内存的大小有虚拟内存为我们兜底。

使用这种方式可以获取很大的I/O提升, 省去了用户空间到内核空间 复制的开销(调用文件的read会把数据先放到内核空间的内存中,然后再复制到用户空间的内存中。)也有一个很明显的缺陷——不可靠, 写到mmap中的数据并没有被真正的写到硬盘,操作系统会在程序主动调用flush的时候才把数据真正的写到硬盘。 Kafka提供了一个参数——producer.type来控制是不是主动flush,如果Kafka写入到mmap之后就立即flush然后再返回Producer叫 同步 (sync);写入mmap之后立即返回Producer不调用flush叫 异步 (async)。

四:批量压缩

在很多情况下,系统的瓶颈不是CPU或磁盘,而是网络IO,对于需要在广域网上的数据中心之间发送消息的数据流水线尤其如此。进行数据压缩会消耗少量的CPU资源,不过对于kafka而言,网络IO更应该需要考虑。

  • 如果每个消息都压缩,但是压缩率相对很低,所以Kafka使用了批量压缩,即将多个消息一起压缩而不是单个消息压缩
  • Kafka允许使用递归的消息集合,批量的消息可以通过压缩的形式传输并且在日志中也可以保持压缩格式,直到被消费者解压缩
  • Kafka支持多种压缩协议,包括Gzip和Snappy压缩协议

总结:

  • mmap优化了I/O速度
  • 顺序写入优化了写入速度
  • 批量压缩优化网络I/O速率
  • 零拷贝优化了cpu执行效率,减少了copy次数

猜你喜欢

转载自blog.csdn.net/qq_35050438/article/details/108070805