消息保存或缓存在磁盘上,一般认为磁盘读写数据是会降低性能,因为寻址会消耗时间,实际Kafka特性之一是高吞吐率。
Kafka轻松支持普通服务器每秒百万级写入请求,超过了大部分的消息中间件,在日志处理等海量数据场景广泛应用。
基准测试参考:Apache Kafka基准测试:每秒写入2百万(在三台廉价机器上)
一、写入数据
优化写入速度用两个技术:顺序写入 和 MMFile 。
1.1 顺序写入
Linux对磁盘读写优化:read-ahead和write-behind,磁盘缓存等。内存做这些操作,JAVA对象内存开销大,堆内存数据增多,GC时间长,磁盘好处:
(1)顺序读写速度超过内存随机读写:每次读写都寻址(“机械动作”最耗时)
(2)JVM的GC效率低,内存占用大。磁盘可避免
(3)系统冷启动后,磁盘缓存依然可用
每个Partition都是一个文件 ,收到消息后Kafka会把数据插入到文件末尾(虚框部分)。
缺陷:不能删除数据 ,每个消费者(Consumer)对每个Topic都有一个offset表示 读到第几条数据
Consumer1有两个offset分别对应Partition0、Partition1(假设每一个Topic一个Partition);Consumer2有一个offset对应Partition2。offset是由客户端SDK负责保存,Kafka的Broker完全无视这个东西的存在;一般情况下SDK会把它保存到zookeeper里面。(所以需要给Consumer提供zookeeper的地址)。
解决:Kakfa删除数据策略:(1)基于时间,(2)基于partition文件大小(配置文档看具体配置)。
1.2 Memory Mapped Files(mmap内存映射文件)
出现原因:顺序写入硬盘,硬盘访问速度还是不可能追上内存。Kafka不是实时写入硬盘 ,利用了操作系统 分页存储(用内存提高I/O效率) 。
工作原理:操作系统Page实现文件到物理内存的直接映射。对物理内存的操作会同步到硬盘(操作系统适当时)。64位操作系统中可表示20G数据文件
用途:进程像读写硬盘一样读写内存(当然是虚拟机内存),不必关心内存大小,虚拟内存兜底。
好处:I/O提升, 省去用户空间到内核空间 复制开销(调用文件的read会把数据先放到内核空间的内存中,然后再复制到用户空间的内存中。)
缺点:不可靠, 写到mmap中的数据,没被真正写到硬盘,操作系统会在程序主动调用flush的时候才把数据真正写到硬盘。
Kafka提供了参数producer.type来控制是不是主动flush,如果Kafka写入到mmap之后就立即flush然后再返回Producer叫 同步 (sync);写入mmap之后立即返回Producer不调用flush叫 异步 (async)。
二、读取数据
基于sendfile实现Zero Copy,sendfile系统调用减少多次copy,提升文件传输性能
2.1 传统模式文件传输流程(read/write方式):
1.文件数据被copy到内核缓冲区(调read函数),2.然后到用户缓冲区(read函数返回),3.再到内核与socket相关缓冲区(write函数调用)
4.相关协议引擎
四次copy操作:硬盘—>内核buf—>用户buf—>socket相关缓冲区—>协议引擎
2.2 简化网络上和两个本地文件之间的数据传输
引入sendfile系统调用,减少数据复制、上下文切换。
(1)sendfile(socket, file, len)运行流程: 减少到user缓冲区
1.文件数据被copy至内核缓冲区(sendfile系统调用),2.至内核中socket相关缓冲区,3.协议引擎
(2)优点:1)2.1linux内核引进sendfile:减少内核缓冲区到user缓冲区,再到socket相关缓冲区文件copy 2)2.4后,文件描述符结果被改变:仅将记录数据位置和长度数据存 socket缓存。实际数据由DMA模块直接发送到协议引擎,减少一次copy。(4次,变2次,变1次)
(3)在apache,nginx,lighttpd等web服务器当中,都有一项sendfile相关的配置,提升文件传输性能。
Kafka把所有的消息都存放在一个个文件中,当消费者需要数据的时候Kafka直接把文件发送给消费者,配合mmap作为文件读写方式,直接把它传给sendfile。
三、批量压缩
系统瓶颈是网络IO,不是CPU或磁盘,数据压缩消耗CPU资源少,
批量压缩,多个消息一起压,如每个消息都压缩,压缩率低,
Kafka用递归消息集合,传输并保持压缩格式(在日志中),直到被消费者解压缩
Kafka支持多种压缩协议(Gzip和Snappy压缩协议)
总结
Kafka速度秘诀:
(1)读取数据时配合sendfile直接暴力输出
(2)写入数据:顺序写入,单个Partion是末尾添加所以速度最优。
(3)批量压缩把所有消息变成一个批量文件,合理减少网络IO损耗,通过mmap提高I/O速度。
https://www.cnblogs.com/binyue/p/10308754.html