kafka文件存储机制

一,kafka简介     

Kafka最初由Linkedin公司开发的分布式、分区的、多副本的、多订阅者的消息系统。它提供了类似于JMS的特性,但是在设计实现上完全不同,此外它并不是JMS规范的实现。kafka对消息保存是根据Topic进行归类,发送消息者称为Producer;消息接受者称为Consumer;此外kafka集群有多个kafka实例组成,每个实例(server)称为broker。无论是kafka集群,还是producer和consumer都依赖于zookeeper来保证系统可用性集群保存一些meta信息(kafka的0.8版本之后,producer不在依赖zookeeper保存meta信息,而是producer自己保存meta信息)。本文不打算对Apache Kafka的原理和实现进行介绍,而在编程的角度上介绍如何使用Apache Kafka。我们分别介绍如何编写Producer、Consumer以及Partitioner等。

二、producer以及consumer是如何知道该去哪个broker里传送以及消费对应的数据

        是因为kafka从0.8版本开始,kafka的producer开始不用从ZK获取broker的元信息。之前的版本是需要的。0.8版本后,producer可以指定一个或者多个broker的信息(ip:port),来获取kafka集群的元信息。(比如集群有50个broker,但是producer只需要指定至少1个就可以获取到整个broker的集群的活动的列表(但是最好多指定几个,否则这个broker连接不上了,就over了),每个broker,topic有多少partition,每个partition在哪个broker上,该信息会存储到broker的内存之中进行维护)。而consumer是通过连接ZK,发现kafka集群的元信息(broker的集群的活动的列表,每个broker,topic有多少partition,每个partition在哪个broker上)。从而找到了对应的数据位置。

    介于producer保存着kafka的元数据信息,系统会去刷新元数据信息的。(1、定期刷新元数据信息(通过producer的配置文件里设置);2、传送数据失败后,会去刷新broker元数据信息)

三,kafka存储文件

       1,在kafka集群中,每个broker(一个kafka实例称为一个broker)中有多个topic,topic数量可以自己设定。在每个topic中又有多个partition,每个partition为一个分区。kafka的分区有自己的命名的规则,它的命名规则为topic的名称+有序序号,这个序号从0开始依次增加。

      2,在每个partition中有可以分为多个segment file。当生产者往partition中存储数据时,内存中存不下了,就会往segment file里面存储。kafka默认每个segment file的大小是500M,在存储数据时,会先生成一个segment file,当这个segment file到500M之后,再生成第二个segment file 以此类推。每个segment file对应两个文件,分别是以.log结尾的数据文件和以.index结尾的索引文件。在服务器上,每个partition是一个文件夹,每个segment是一个文件。

      每个segment file也有自己的命名规则,每个名字有20个字符,不够用0填充。每个名字从0开始命名,下一个segment file文件的名字就是,上一个segment file中最后一条消息的索引值。在.index文件中,存储的是key-value格式的,key代表在.log中按顺序开始第条消息,value代表该消息的位置偏移。但是在.index中不是对每条消息都做记录,它是每隔一些消息记录一次,避免占用太多内存。即使消息不在index记录中,在已有的记录中查找,范围也大大缩小了。


四,consumer如何消费数据

       消费者需要先指定消费哪个topic。在kafka中各个partition中已经存储了数据。由于之前存储是按照顺序存储的,各个segment file文件命名也时有一定规则的,这种存储规则使得查找文件会很快速。

      1,假设需要查找offest=12345的消息,通过二分查找法可以很快速的定位到该文件所在的.index和.log文件。这一步就查找到该消息所在的segment file文件。

      2,在该segment file文件中查找该消息。通过.index索引文件,快速的查找到该消息在.log中的位置,查找文件就完成了。

五、producer如何发送数据

    producer需要指定数据到哪个topic,并且指定的分区,系统会自动均匀分配到各个broker里,而不会都存在一个或某几个broker里。那消息该发送到哪个broker上呢,一般有两种情况(可以自定义class去设置分区,在producer的实例,配置文件时,partitioner.class这个配置项指定对应的自己创建的分区类即可)。如下

Properties props = new Properties();

    props.put("metadata.broker.list", BROKER_LIST);

    props.put("serializer.class", StringEncoder.class.getName());

    props.put("partitioner.class", HashPartitioner.class.getName());

1、根据消息的key模与分区数,去指定该消息该到哪个分区。

2、根据消息发送的顺序,去指定该消息该到哪个分区。例如,第一条数据去topic-0,第二条数据去topic-1,以此类推。

producer还分为两种

    1同步producer

  消息发送过去之后,只有成功之后才会发送下一条消息。不成功的话,会retry,3次不成功会catch异常,出现异常时,可以忽略,也可以手动操作,或者把这条数据存储到另一个存储里,下次再处理。

   2异步producer

不是马上就发,会先存储在query,达到要求后,再把query发送个broker。如果query满了,刚要发送时,此时出现阻塞来不及发送,此时如果有新的数据进来,会选择把新的数据丢掉(这个是可以设置的,也可以设置为等待)。

六、过期日志的处理

   kafka作为一个消息中间件,是需要定期处理数据的,否则磁盘就爆了。

1、处理的机制

      1)根据数据的时间长短进行清理,例如数据在磁盘中超过多久会被清理(默认是168个小时) 

       2)根据文件大小的方式给进行清理,例如数据大小超过多大时,删除数据(大小是按照每个partition的大小来界定的)。

2、删除过期的日志的方式

直接删除segment文件。后台会周期性的扫描,当满足设定的条件的数据就执行删除。如果设置是按照大小的方式,删除segment是按照segment存在顺序进行删除,即先删除存在最久的那个segment。

七、几个重要的知识点

1、kafka里的数据只能追加和消费,不能进行修改,即不可变数据集。 

2、consumer还可以同过设置topic的黑白名单,去设置自己想消费以及不想消费的topic。                                                               

3、producer是通过partition判定消息该到哪个broker的。通过HashPartiton以及RoundRobinPartition等去判定数据key属于哪个partition,从而到对应的broker中(每条消息仅属于一个topic,每个topic的partition在不同的broker中是不同的)。

4、broker集群是会让每个topic的partition均匀分配在每个broker之中。                                                                                               

5、producer到broker是通过push的方式。consumer是通过pull的方式(1、使用pull可以让系统设计更为简单,producer不用去感知地下consumer的状态,代码设计上会简单许多。2、通过pull,consumer可以进行消息峰值的控制,避免数据量太大时候压垮cunsumer。宁愿消息暂时性延迟也不愿意consumer宕机。3、但是PULL模型可能造成消费者在没有消息的情况下盲等,这种情况下可以通过long polling机制缓解(当没有数据时,就等待,当然会有超时时间),而对于几乎每时每刻都有消息传递的流式系统,这种影响可以忽略。)。

你可能感兴趣的:(kafka文件存储机制)