一、写入数据
1、顺序写入
2、Memory Mapped Files
二、读取数据
1、基于sendfile实现Zero Copy
2、批量压缩
kafka的消息是保存在磁盘上的,由于磁盘寻址,会导致在磁盘上进行的读写性能降低,但是kafka规避了这一缺陷,普通的服务器kafka也可以支撑每秒百万的数据量
一、写入数据
kafka把收集到的消息写入硬盘之中,但是不会丢失数据。为了优化速度,kafka采用了两个技术,顺序写入和MMFile
1、顺序写入
磁盘分为顺序读写和随机读写,顺序读写磁盘的速度基本与读写内存持平
因为硬盘是机械结构,每次读写都会有 寻址 -> 写入 两个操作,其中“寻址”是一个“机械动作”,最为耗时,所以采用顺序读写,可以减少寻址这一操作的耗时。
Linux对于磁盘的读写也有一定的优化,比如 read-ahead,write-behind,磁盘缓存等。如果在内存中做这些操作,一个是Java对象的内存开销很大,另一个是随着堆内存数据增多,Java的GC时间会变得很长,使用磁盘操作有一下几个好处:
1、顺序写入磁盘读写速度超过内存随机读写
2、顺序写入JVM的GC效率低,内存占用大。使用磁盘可以避免这一问题
3、顺序写入系统冷启动后,磁盘缓存依然可以用
kafka采用文件追加的方式写入数据,会将收到的数据插入文件的末尾,kafka的每个partition都是一个文件,但是这种追加的方式有一个缺陷——没办法删除数据。
所以kafka提供了两种策略来删除数据
1、基于时间
2、基于partition文件大小
2、Memory Mapped Files
虽然kafka是顺序写入硬盘,但是硬盘的访问速度还是不可能追得上内存,所以kafka的数据并不是实时的写入硬盘,它充分利用了现代操作系统分页存储,利用内存来提高IO效率。
Memory Mapped Files(即mmap)又被叫做 内存映射文件,在64位操作系统中一般可以表示20G的数据文件,它的工作原理是直接利用操作系统的Page来实现文件到物理内存的直接映射。
完成映射之后,操作系统会在适当的时候,将你对物理内存进行的操作同步到磁盘上
通过mmap,进程像读写硬盘一样读写内存(虚拟内存),因此不必关心内存大小。
使用这种方式可以让IO获得很大的提升,省去了从用户空间到内核空间复制的开销(调用文件的read,会先把数据复制放到内核空间的内存中,然后拷贝到用户空间的内存中),但是这样也有一个很明显的缺陷——不可靠,写入mmap的数据并没有真正的写到磁盘,操作系统会在程序主动调用flush的时候才把数据真正的写到磁盘。
kafka提供了一个参数——producer.type来控制是不是主动flush,如果卡kafka写入到mmap之后就立即flush然后再返回producer,叫同步(sync);写入mmap立即返回producer不调用flush,叫异步(async)
二、读取数据
1、基于sendfile实现Zero Copy
传统模式下,需要对一个文件进行传输的时候,具体流程细节如下:
1、调用read函数,文件数据被copy到内核缓冲区
2、read函数返回,文件数据从内核缓冲区copy到用户缓冲区
3、调用write函数,将文件从用户缓冲区copy到内核与socket相关的缓冲区
4、数据从socket缓冲区copy到相关协议引擎
以上是传统的read/write方式进行网络文件传输,在整个过程中,数据经历了4次copy操作
硬盘 -> 内核buffer -> 用户buffer -> socket相关缓冲区 -> 引擎协议
而sendfile系统调用则提供了一种减少多次copy,提升文件传输性能的方法
在内核2.1版本中引入了sendfile系统,以简化网络上和两个本地文件之间的数据传输。sendfile的引入不仅减少了数据复制,还减少了上下文切换
sendfile(socket, file, len);
运行流程如下:
1、sendfile系统调用,文件数据被copy到内核缓冲区
2、内核缓冲区copy到socket相关缓冲区
3、socket相关缓冲区copy到协议引擎
内核版本2.1引进的sendfile减少了内核缓冲区到用户缓冲区,再由用户缓冲区到socket相关缓冲区的文件copy,而在内核2.4版本之后,文件描述符结果改变,sendfile实现了更简单的方式,再减少了一次copy操作
2、批量压缩
很多情况下,系统的瓶颈不是CPU或者磁盘,而是网络IO,对于需要在广域网的数据中心之间发送消息的数据流水线更是如此,进行数据压缩会消耗少量的CPU资源,但是对于kafka而言,网络IO更需要考虑
1、如果每个消息都压缩,那压缩率相对很低,所以kafka使用了批量压缩,即多条消息一起压缩而不是单独压缩
2、kafka允许使用递归的消息集合,批量的消息可以通过压缩的形式传输并且在日志中也可以保存压缩格式,直到被消费者解压缩
3、kafka支持多种压缩协议,包括Gzip和Snappy协议