本文共 1686 字,大约阅读时间需要 5 分钟。
消息队列在多种场景中,都有使用,比如异步处理、应用解耦、流量削锋和消息通讯。在日志处理中,利用Kafka可以解决大量日志传输、缓存等问题。
结合实际,本文重点谈谈Kafka是通过什么机制来实现快速读写。
随机存取一般使用RAM作为数据存储,但当数据量极大时,对应成本相当大。Kafka使用文件系统进行存储和读取,主要问题是磁盘要比RAM慢,而磁盘慢的一个重要原因是磁盘寻道时间要大于数据读取时间。针对磁盘存储,如果能将寻道时间优化,数据读写会大幅接近RAM存储。因此,Kafka使用顺序I/O,避免了磁盘寻道时间消耗。
图1 Kafka顺序I/O
在数据文件存储上,Kafka为数据文件进行了分段存储,并且为每个文件单独建立了索引。
每段数据为一单独的文件,称为log文件,文件命名为这段message中的最小offset,这样在查找某个offset对应messag时,通过二分法就可以定位到哪个段文件了。
索引文件主要存储了相对offset和绝对position。由于索引文件和log文件一一对应,文件名为该段下的最小offset,因此为了降低存储消耗,索引中的offset使用了相对方式。最终读取某个message时,只要打开log文件,并移动指针到绝对position时,就能读取对应message。实际索引文件建立采取了稀疏存储的方式,这样没有建立索引的message就不能一次定位到其在数据文件的位置,从而需要做一次顺序扫描,但是这次顺序扫描的范围就很小了。另外,索引文件使用内存映射文件。
图2 Kafka段、索引存储
数据传输过程中的序列化与反序列化是影响性能的一个主要因素,使用二进制数据格式,可以使数据传输更快。Kafka通过2种方式解决:
图3 非0拷贝
第1点不难理解,重点来说明0拷贝。数据从文件到socket,经历:
概况起来,如下:
如果使用相同的标准化的二进制数据格式,那么没必要进行内核空间到用户空间的拷贝,操作系统可直接在内核空间从页缓存写到socket缓存。
图4 0拷贝
可详细阅读:
许多现代数据库的持久化存储采用树作为数据结构,比如MongoDB使用了B树,Cassandra使用LSM树。这些数据结构的时间复杂度是O(logN)。
对于需要执行大量读写操作的消息系统,使用树会导致大量的随机I/O,如上文所言,这样会导致磁盘大量的寻道,这对性能而言,并不是一件好事。
Kafka使用队列来作为数据存储结构,时间复杂度为O(1)。
图5 Kakfa某Topic拆分
批处理数据和压缩:支持Lz4,Snappy,Gzip等数据压缩,降低网络传输流量
水平伸缩:Kafka的一个topic可以支持上千个分区,分布在不同服务器上,这样可以处理更大的负载
性能优化的结果,主要通过单次事件处理耗时和每秒吞吐量来衡量。
Producer重点参数
batch.size:批量发送的基本单位,默认为16384字节
linger.ms:给定延迟之后开始发送,默认为0ms,可以将此设置为5ms
Broker:主要是负载均衡相关的参数,建议某topic的一个partition对应一个物理存储
Consumer:比如在同一消费群组中,为每个分区添加一个消费者。另外,replica.high.watermark.checkpoint.interval.ms参数也会影响吞吐量
转载地址:http://xdmti.baihongyu.com/