Kafka的数据存储

目录

一、基本概念

二、存储位置及格式

1、存储位置

2、分区与存储方式的关系

三、操作演示

1、创建一个主题

2、查看数据目录中的效果

3、向此主题写入大批量数据

4、查看segment file

(1)查看log文件

(2)查看index文件

(3)查看timeindex文件

四、数据存储原理分析

1、说明

2、数据文件建立索引原理

3、数据消费查询原理

4、segment file中索引文件与数据文件的对应关系

5、Kafka高效文件存储设计特点


一、基本概念

1、Broker:消息中间件处理结点,一个Kafka节点就是一个broker,多个broker可以组成一个Kafka集群;

2、Topic:一类消息,Kafka集群能够同时负责多个topic的分发;

3、Partition:topic物理上的分组,一个topic可以分为多个partition,每个partition是一个有序的队;

4、Segment:每个partition又由多个segment file组成;

5、offset:每个partition都由一系列有序的、不可变的消息组成,这些消息被连续的追加到partition中。partition中的每个消息都有一个连续的序列号叫做offset,用于partition唯一标识一条消息;

6、message:这个算是kafka文件中最小的存储单位,即是 a commit log。

二、存储位置及格式

1、存储位置

kafka数据的存储位置,在config/server.properties中的log.dirs中配置;

本次演示kafka的日志存储配置为:log.dirs=/tmp/kafka-logs

2、分区与存储方式的关系

partition是以文件的形式存储在文件系统中,比如,创建了一个名为kafkaData的topic,有4个partition,那么在Kafka的数据目录中(由配置文件中的log.dirs指定的)中就有这样4个目录: kafkaData-0, kafkaData-1,kafkaData-2,kafkaData-3,其命名规则为<topic_name>-<partition_id>,里面存储的分别就是这4个partition的数据。

每个数据目录的子目录都有xx.indexxx.log xx.timeindex三个文件组成

三、操作演示

1、创建一个主题

创建一个带有4个分区,2个副本的topic(kafkaData)

[root@master bin]# ./kafka-topics.sh --create --zookeeper master:2181,slaves1:2181,slaves2:2181 --replication-factor 2 --partitions 4 --topic kafkaData 
Created topic "kafkaData".

2、查看数据目录中的效果

[root@master kafka-logs]# ls /tmp/kafka-logs/

kafkaData-0
kafkaData-1

[root@slaves1 bin]# ls /tmp/kafka-logs/

kafkaData-1
kafkaData-2
kafkaData-3

[root@slaves2 bin]# ls /tmp/kafka-logs/

kafkaData-0
kafkaData-2
kafkaData-3

由上可以看出kafka的第一个分区kafka-0的两个副本分别在master、slaves2两个节点上;其他同理;

命令查看

[root@master bin]# ./kafka-topics.sh --describe --zookeeper master:2181,slaves1:2181,slaves2:2181 --topic kafkaData
Topic:kafkaData	PartitionCount:4	ReplicationFactor:2	Configs:
	Topic: kafkaData	Partition: 0	Leader: 2	Replicas: 2,0	Isr: 2,0
	Topic: kafkaData	Partition: 1	Leader: 0	Replicas: 0,1	Isr: 0,1
	Topic: kafkaData	Partition: 2	Leader: 1	Replicas: 1,2	Isr: 1,2
	Topic: kafkaData	Partition: 3	Leader: 2	Replicas: 2,1	Isr: 2,1

Leader:指定主分区的broker id;
Replicas: 副本在那些机器上;
Isr:可以做为主分区的broker id;

3、向此主题写入大批量数据

此步骤省略;

4、查看segment file

以kafkaData-0为例:

使用kafka安装bin目录下的kafka-run-class.sh分别查看这些文件的内容:

(1)查看log文件

[root@master bin]# ./kafka-run-class.sh  kafka.tools.DumpLogSegments --files /tmp/kafka-logs/kafkaData-0/00000000000000000000.log  --print-data-log
...
offset: 7211 position: 448934 CreateTime: 1587632825139 isvalid: true payloadsize: 29 magic: 1 compresscodec: NONE crc: 995429819 payload: 阳光小区,11,1587632825139
offset: 7212 position: 448997 CreateTime: 1587632825139 isvalid: true payloadsize: 28 magic: 1 compresscodec: NONE crc: 2299568067 payload: 单身小区,5,1587632825139
offset: 7213 position: 449059 CreateTime: 1587632825139 isvalid: true payloadsize: 29 magic: 1 compresscodec: NONE crc: 2772987037 payload: 花花小区,12,1587632825139
offset: 7214 position: 449122 CreateTime: 1587632825139 isvalid: true payloadsize: 28 magic: 1 compresscodec: NONE crc: 2369864650 payload: 阳光小区,6,1587632825139
offset: 7215 position: 449184 CreateTime: 1587632825139 isvalid: true payloadsize: 28 magic: 1 compresscodec: NONE crc: 820724779 payload: 单身小区,4,1587632825139
...

payload:为消息体

(2)查看index文件

[root@master bin]# ./kafka-run-class.sh  kafka.tools.DumpLogSegments --files /tmp/kafka-logs/kafkaData-0/00000000000000000000.index  --print-data-log
...
offset: 1269114 position: 79002134
offset: 1269231 position: 79009410
offset: 1269316 position: 79014708
offset: 1269456 position: 79023419
offset: 1269715 position: 79039540
offset: 1269838 position: 79047192
offset: 1269933 position: 79053095
offset: 1270083 position: 79062430
...

(3)查看timeindex文件

[root@master bin]# ./kafka-run-class.sh  kafka.tools.DumpLogSegments --files /tmp/kafka-logs/kafkaData-0/00000000000000000000.timeindex  --print-data-log
...
timestamp: 1587632824453 offset: 1867
timestamp: 1587632824473 offset: 1975
timestamp: 1587632824507 offset: 1987
timestamp: 1587632824658 offset: 2657
timestamp: 1587632824759 offset: 3057
timestamp: 1587632824810 offset: 3468
...

注意:

segment file 组成:由2部分组成,分别为index file和data file,这两个文件是一一对应的,后缀”.index”和”.log”分别表示索引文件和数据文件;

segment file 命名规则:partition的第一个segment从0开始,后续每个segment文件名为上一个segment文件最后一条消息的offset,ofsset的数值最大为64位(long类型),20位数字字符长度,没有数字用0填充。

四、数据存储原理分析

1、说明

(1)在生产环境中,kafkaData-0下不会只存在一个index、log、timeindex文件;而是像这样:

(2)、我们将index文件称为索引文件,里面存储着大量元数据;log文件称为数据文件,里面存储着大量消息;

2、数据文件建立索引原理

数据文件分段使得可以在一个较小的数据文件中查找对应offset的Message了,但是这依然需要顺序扫描才能找到对应offset的Message。为了进一步提高查找的效率,Kafka为每个分段后的数据文件建立了索引文件,文件名与数据文件的名字是一样的,只是文件扩展名为.index。
索引文件中包含若干个索引条目,每个条目表示数据文件中一条Message的索引。索引包含两个部分(均为4个字节的数字),分别为相对offset和position。

相对offset:因为数据文件分段以后,每个数据文件的起始offset不为0,相对offset表示这条Message相对于其所属数据文件中最小的offset的大小。举例,分段后的一个数据文件的offset是从20开始,那么offset为25的Message在index文件中的相对offset就是25-20 = 5。存储相对offset可以减小索引文件占用的空间。
position,表示该条Message在数据文件中的绝对位置。只要打开文件并移动文件指针到这个position就可以读取对应的Message了。

3、数据消费查询原理

注意:Messagexxxx抽象表示某条消息具体内容;.log的第二列和.index的第一列表示数据文件中的绝对位置,也就是打开文件并移动文件指针需要指定的地方;

如果我们想要读取offset=368776的message(如图),步骤如下:

(1)查找segment file
00000000000000000000.index表示最开始的文件,起始偏移量(offset)为0.第二个文件00000000000000368769.index的消息量起始偏移量为368770 = 368769 + 1.同样,第三个文件00000000000000737337.index的起始偏移量为737338=737337 + 1,其他后续文件依次类推,以起始偏移量命名并排序这些文件,只要根据offset 二分查找文件列表,就可以快速定位到具体文件。
当offset=368776时定位到00000000000000368769.index|log

(2)通过segment file查找message
通过第一步定位到segment file,当offset=368776时,依次定位到00000000000000368769.index的元数据物理位置和00000000000000368769.log的物理偏移地址,然后再通过00000000000000368769.log顺序查找直到offset=368776为止。

4、segment file中索引文件与数据文件的对应关系

segment的索引文件中存储着大量的元数据,数据文件中存储着大量消息,索引文件中的元数据指向对应数据文件中的message的物理偏移地址。以索引文件中的6,1407为例,在数据文件中表示第6个message(在全局partition表示第368775个message),以及该消息的物理偏移地址为1407。

5、Kafka高效文件存储设计特点

(1)Kafka把topic中一个parition大文件分成多个小文件段,通过多个小文件段,就容易定期清除或删除已经消费完文件,减少磁盘占用。

(2)通过索引信息可以快速定位message和确定response的最大大小。

(3)通过index元数据全部映射到memory,可以避免segment file的IO磁盘操作。

(4)通过索引文件稀疏存储,可以大幅降低index文件元数据占用空间大小。

欢迎加入【大数据技术】社区

  • 30
    点赞
  • 101
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
以下是一个简单的示例代码,通过Flink将Kafka数据存入HBase: ``` import org.apache.flink.api.common.functions.MapFunction import org.apache.flink.api.common.serialization.SimpleStringSchema import org.apache.flink.streaming.api.scala._ import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer import org.apache.flink.streaming.connectors.kafka.FlinkKafkaProducer import org.apache.flink.streaming.connectors.hbase.* import org.apache.hadoop.hbase.client.Put import org.apache.hadoop.hbase.util.Bytes object KafkaToHBase { def main(args: Array[String]): Unit = { val env = StreamExecutionEnvironment.getExecutionEnvironment val kafkaProps = new Properties() kafkaProps.setProperty("bootstrap.servers", "localhost:9092") kafkaProps.setProperty("group.id", "test") val kafkaConsumer = new FlinkKafkaConsumer[String]("topic", new SimpleStringSchema(), kafkaProps) val hbaseProps = new Properties() hbaseProps.setProperty("zookeeper.quorum", "localhost:2181") hbaseProps.setProperty("zookeeper.znode.parent", "/hbase-unsecure") hbaseProps.setProperty("write.buffer.max.size", "20971520") // 20 MB val hbaseOutputFormat = new HBaseOutputFormat(new org.apache.hadoop.hbase.client.ConnectionConfiguration(hbaseProps)) val stream = env .addSource(kafkaConsumer) .map(new MapFunction[String, Put] { val cfBytes = Bytes.toBytes("cf") override def map(value: String): Put = { val rowkey = "some row key" val put = new Put(Bytes.toBytes(rowkey)) put.addColumn(cfBytes, Bytes.toBytes("data"), Bytes.toBytes(value)) put } }) .output(hbaseOutputFormat) env.execute("Kafka to HBase") } } ``` 需要注意的点: 1. 在HBaseOutputFormat实例化时需要传入一个org.apache.hadoop.hbase.client.ConnectionConfiguration对象,用于与HBase进行连接。 2. 在map函数中将Kafka数据转化为HBase Put对象时需要指定一个rowkey。这个rowkey可以按照需要进行设计,例如可以设置成Kafka数据的某个字段。 3. 在map函数中将Kafka数据转化为HBase Put对象时需要指定column family和column qualifier以及对应的value。这里使用了一个名为“cf”的column family和一个名为“data”的column qualifier。如果需要根据业务需要进行更改。 4. HBaseOutputFormat默认是批量写入模式,需要在HBase配置文件中指定write ahead log的大小,以及每次写入的缓冲区大小等。如果需要进行实时写入,则需要将批量写入模式关闭。可以通过在HBase连接配置中设置"HBASE_CLIENT_OPERATION_TIMEOUT"来达到此目的。单位是毫秒,设置为0表示禁用批处理模式。 5. 在实际使用时需要根据实际情况进行调整。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郝少

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值