美文网首页
Kafka的存储特点

Kafka的存储特点

作者: 没去杜克 | 来源:发表于2017-12-02 23:35 被阅读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),和稀疏存储来达到高效性。

    相关文章

      网友评论

          本文标题:Kafka的存储特点

          本文链接:https://www.haomeiwen.com/subject/djpgbxtx.html