Kafka的存储特点

2017-12-02  本文已影响0人  没去杜克

MessageQuene是干嘛的?
简单来说就是用来分发消息用的。它的出现并非为了提高性能,加速消息传输。
消息队列提供了数据上的冗余,但它不是一种缓存。
如果只是为了加速传输,直接把producer和consumer结合一起,中间放一个全内存的quene,不用网络传输,没有持久化,那岂不是更快。
也并非只是消息的存放源,如果只是存放消息,也许用数据库和redis会更快。
对MessageQuene最好的诠释:"fire and forget"(来自active mq文档),中文叫解耦。
它有效实现了producer和consumer的解耦,降低了系统的复杂性。
生产者只需要关系自己的生产工作,不需要关心自己生产的东西被谁消费,如何消费。它应该简单地把东西生产好,往仓库一放(fire),然后就不用管了(forget)。后面的如何交付消费者,是否丢失消息之类的不用再管。
负责与消费者打交道,交付的可靠性问题,这个由MessageQuene来处理。消息队列就是一个接盘手。

kafka存储特点:
与传统的JMS不一样,它不是为了实现JMS而设计,它追求分布式,高可用和并发性能而生。
kafka集群会保存所有发布的消息,无论是否确认被消费者接收了。所有的这些都会作为log保存起来,好几天才会删,
最神奇的是:完全不会因为这种持久化而导致性能变差。
这跟kafka的log存储方式有关系,数据文件(.index)配合索引文件(.log)的形式来查询,所以每次都是通过offset对消息进行读取。基本都只需要恒定次数的寻址就可以完成。

image.png

上图中,左边为index文件,其中存储的是k-v格式的键值对,key是消息在对应log文件的position(如1,3,6,8...)
这些序号并不是连续的,这种方式叫稀疏存储,并没有为每条消息都在index文件中建立索引,
而是每隔一定字节的数据建立索引。这样是为了避免索引文件占用过多的空间,从而可以把索引文件保存在内存中(通过nmap直接内存操作,时间换空间)。
缺点就是:没有建立索引的message不能一次定位,需要进行一次顺序扫描,只是这次的范围会很小。
例如:index文件元数据3,497,3代表在log文件顺序第3条(全局partiton为第368772条消息),497为消息的物理偏移位置(内存的地址)。

Segment file是什么?
生产者生产的消息按照分组策略被发送到broker的partition的时候,这些消息在内存放不下会存放到磁盘的文件中,物理上,partition包含多个segment。每个segment的消息数量不一定相等,这样的特性方便segment file被快速删除,它的生命周期由服务端配置决定。
partition在磁盘就是一个目录,目录名=topic名+序号。在这个目录下,有两类文件:1,log后缀的文件 2,index后缀的文件。
每一个log文件和index文件相对应,这一对文件就是segment file,也就是一个段。
log文件存放数据的,就是消息。
index文件是索引文件,存放相关metadata。
index文件存放大量的元数据,而log文件则存储大量的消息。元数据是指向对应的log文件中消息的物理偏移地址(如消费到第18条,offset=10,在第二个文件,指向地址=8)。
image.png

上图为Segment文件的命名规则。第2个命名:多个0+(offset=368769),即上一个文件最后一条消息的序号。offset是消息在partition唯一标识,可以认为是增量序列索引。
这样命名的好处是显而易见的!
假如一个消费者消费到了第368770消息(offset=368770),要继续消费,怎么做?
1,从所有log文件找出对应的文件,第368770条消息位于00000000000000368769.log这个文件中,这一步采用的就是常见的“二分法查找”,比较快速定位到所在文件。
2.然后再根据当前segment的最小offset值取得差值(368770-368769),就是它在.log的相对位置,再去读取即可

如何保证消息消费的有序性呢?
答案:没办法。
因为消息会被分组到不同的broker,大多数情况下都没法做到全局的有序性。保证有序性的前提是,有且只有一个partition。
那怎么去分布式,负载均衡?所以kafka消息的全局有序,其实是个伪命题。我们只能保证当前的partition的有序性。
针对一个topic里面的数据,只能做到partition内部的有序。
kafka极少进行进行大量的读磁盘操作,主要定期进行写磁盘操作,此操作的效率很高。这跟kafka的读写设计息息相关
kafka读写消息特点:
写:
消息从java heap转入page cache(ram)
由异步线程刷盘(flush),消息从ram刷入磁盘(rom)
读:
先查找page cache,有的话直接socket发送出去
没有找到则会进行磁盘I/O操作,从磁盘加载消息到page cache,然后直接socket发送出去。
kafka高效文件存储的设计特点:
topic中一个parition大文件分若干segment file小文件,很容易定期清除已经消费完的文件。减少磁盘占用。
通过索引可快速定位msg。
通过index元数据全部映射memory,可以避免segment  file的IO磁盘操作。
通过索引文件稀疏存储,大幅降低索引文件占用磁盘空间的大小。

总之,kafka的消息存储采用分区(partition),分段(Segment),和稀疏存储来达到高效性。

上一篇下一篇

猜你喜欢

热点阅读