建设部特种作业证网站查询,建设工程包括什么工程,义乌电子商务有限公司,如何再腾讯云服务器做网站kafka的log存储解析——topic的分区partition分段segment以及索引等
引言Kafka中的Message是以topic为基本单位组织的#xff0c;不同的topic之间是相互独立的。每个topic又可以分成几个不同的partition(每个topic有几个partition是在创建topic时指定
的)#xff0c;每个…kafka的log存储解析——topic的分区partition分段segment以及索引等
引言Kafka中的Message是以topic为基本单位组织的不同的topic之间是相互独立的。每个topic又可以分成几个不同的partition(每个topic有几个partition是在创建topic时指定
的)每个partition存储一部分Message。借用官方的一张图可以直观地看到topic和partition的关系。
partition是以文件的形式存储在文件系统中比如创建了一个名为page_visits的topic其有5个partition那么在Kafka的数据目录中(由配置文件中的log.dirs指定的)中就有这
样5个目录: page_visits-0 page_visits-1page_visits-2page_visits-3page_visits-4其命名规则为topic_name-partition_id里面存储的分别就是这5个partition的
数据。
接下来本文将分析partition目录中的文件的存储格式和相关的代码所在的位置。
Partition中的每条Message由offset来表示它在这个partition中的偏移量这个offset不是该Message在partition数据文件中的实际存储位置而是逻辑上一个值它唯一确定了
partition中的一条Message。因此可以认为offset是partition中Message的id。partition中的每条Message包含了以下三个属性
其中offset为long型MessageSize为int32表示data有多大data为message的具体内容。它的格式和Kafka通讯协议中介绍的MessageSet格式是一致。
Partition的数据文件则包含了若干条上述格式的Message按offset由小到大排列在一起。它的实现类为FileMessageSet类图如下
它的主要方法如下
我们来思考一下如果一个partition只有一个数据文件会怎么样
那Kafka是如何解决查找效率的的问题呢有两大法宝1) 分段 2) 索引。
Kafka解决查询效率的手段之一是将数据文件分段比如有100条Message它们的offset是从0到99。假设将数据文件分成5段第一段为0-19第二段为20-39以此类推每
段放在一个单独的数据文件里面数据文件以该段中最小的offset命名。这样在查找指定offset的Message的时候用二分查找就可以定位到该Message在哪个段中。
数据文件分段使得可以在一个较小的数据文件中查找对应offset的Message了但是这依然需要顺序扫描才能找到对应offset的Message。为了进一步提高查找的效率Kafka为
每个分段后的数据文件建立了索引文件文件名与数据文件的名字是一样的只是文件扩展名为.index。
索引文件中包含若干个索引条目每个条目表示数据文件中一条Message的索引。索引包含两个部分均为4个字节的数字分别为相对offset和position。
index文件中并没有为数据文件中的每条Message建立索引而是采用了稀疏存储的方式每隔一定字节的数据建立一条索引。这样避免了索引文件占用过多的空间从而可以将
索引文件保留在内存中。但缺点是没有建立索引的Message也不能一次定位到其在数据文件的位置从而需要做一次顺序扫描但是这次顺序扫描的范围就很小了。
Partition的数据文件
offset
MessageSize
data
append: 把给定的ByteBufferMessageSet中的Message写入到这个数据文件中。
searchFor: 从指定的startingPosition开始搜索找到第一个Message其offset是大于或者等于指定的offset并返回其在文件中的位置Position。它的实现方式是从
startingPosition开始读取12个字节分别是当前MessageSet的offset和size。如果当前offset小于指定的offset那么将position向后移动LogOverHeadMessageSize其
中LogOverHead为offsetmessagesize为12个字节。
read准确名字应该是slice它截取其中一部分返回一个新的FileMessageSet。它不保证截取的位置数据的完整性。
sizeInBytes: 表示这个FileMessageSet占有了多少字节的空间。
truncateTo: 把这个文件截断这个方法不保证截断位置的Message的完整性。
readInto: 从指定的相对位置开始把文件的内容读取到对应的ByteBuffer中。
1. 新数据是添加在文件末尾调用FileMessageSet的append方法不论文件数据文件有多大这个操作永远都是O(1)的。
2. 查找某个offset的Message调用FileMessageSet的searchFor方法是顺序查找的。因此如果数据文件很大的话查找的效率就低。
数据文件的分段
为数据文件建索引
相对offset因为数据文件分段以后每个数据文件的起始offset不为0相对offset表示这条Message相对于其所属数据文件中最小的offset的大小。举例分段后的一个数
据文件的offset是从20开始那么offset为25的Message在index文件中的相对offset就是25-20 5。存储相对offset可以减小索引文件占用的空间。
position表示该条Message在数据文件中的绝对位置。只要打开文件并移动文件指针到这个position就可以读取对应的Message了。在Kafka中索引文件的实现类为OffsetIndex它的类图如下
主要的方法有
我们以几张图来总结一下Message是如何在Kafka中存储的以及如何查找指定offset的Message的。
Message是按照topic来组织每个topic可以分成多个的partition比如有5个partition的名为为page_visits的topic的目录结构为
partition是分段的每个段叫LogSegment包括了一个数据文件和一个索引文件下图是某个partition目录下的文件
可以看到这个partition有4个LogSegment。
借用博主lizhitao博客上的一张图来展示是如何查找Message的。
比如要查找绝对offset为7的Message
这套机制是建立在offset是有序的。索引文件被映射到内存中所以查找的速度还是很快的。
append方法添加一对offset和position到index文件中这里的offset将会被转成相对的offset。
lookup, 用二分查找的方式去查找小于或等于给定offset的最大的那个offset
小结
1. 首先是用二分查找确定它是在哪个LogSegment中自然是在第一个Segment中。
2. 打开这个Segment的index文件也是用二分查找找到offset小于或者等于指定offset的索引条目中最大的那个offset。自然offset为6的那个索引是我们要找的通过索引文
件我们知道offset为6的Message在数据文件中的位置为9807。
3. 打开数据文件从位置为9807的那个地方开始顺序扫描直到找到offset为7的那条Message。一句话Kafka的Message存储采用了分区(partition)分段(LogSegment)和稀疏索引这几个手段来达到了高效性。
Kafka 将消息以 topic 为单位进行归纳
将向 Kafka topic 发布消息的程序成为 producers.
将预订 topics 并消费消息的程序成为 consumer.
Kafka 以集群的方式运行可以由一个或多个服务组成每个服务叫做一个 broker.
producers 通过网络将消息发送到 Kafka 集群集群向消费者提供消息
数据传输的事务定义通常有以下三种级别 1最多一次: 消息不会被重复发送最多被传输一次但也有可能一次不传输 2最少一次: 消息不会被漏发送最少被传输一次但也有可能被重复传输. 3精确的一次Exactly once:不会漏传输也不会重复传输,每个消息都传输被一次而且仅仅被传输一次这是大家所期望的 1节点必须可以维护和 ZooKeeper 的连接Zookeeper 通过心跳机制检查每个节点的连接 2如果节点是个 follower,他必须能及时的同步 leader 的写操作延时不能太久
producer 直接将数据发送到 broker 的 leader(主节点)不需要在多个节点进行分发为了帮助 producer 做到这点所有的 Kafka 节点都可以及时的告知:哪些节点是活动的
目标topic 目标分区的 leader 在哪。这样 producer 就可以直接将消息发送到目的地了
Kafaconsumer 消费消息时向 broker 发出fetch请求去消费特定分区的消息consumer 指定消息在日志中的偏移量offset就可以消费从这个位置开始的消息
customer 拥有了 offset 的控制权可以向后回滚去重新消费之前的消息这是很有意义的
Kafka 最初考虑的问题是customer 应该从 brokes 拉取消息还是 brokers 将消息推送到
consumer也就是 pull 还 push。在这方面Kafka 遵循了一种大部分消息系统共同的传统的设计producer 将消息推送到 brokerconsumer 从 broker 拉取消息
一些消息系统比如 Scribe 和 ApacheFlume 采用了 push 模式将消息推送到下游的 consumer。这样做有好处也有坏处由 broker 决定消息推送的速率对于不同消费速率的
consumer 就不太好处理了。消息系统都致力于让 consumer 以最大的速率最快速的消费消息但不幸的是push 模式下当 broker 推送的速率远大于 consumer 消费的速率
时 consumer 恐怕就要崩溃了。最终 Kafka 还是选取了传统的 pull 模式
Pull 模式的另外一个好处是 consumer 可以自主决定是否批量的从 broker 拉取数据。Push 模式必须在不知道下游 consumer 消费能力和消费策略的情况下决定是立即推送每条
消息还是缓存之后批量推送。如果为了避免 consumer 崩溃而采用较低的推送速率将可能导致一次只推送较少的消息而造成浪费。Pull 模式下consumer 就可以根据自己的
消费能力去决定这些策略
Pull 有个缺点是如果 broker 没有可供消费的消息将导致 consumer 不断在循环中轮询
直到新消息到 t 达。为了避免这点Kafka 有个参数可以让 consumer 阻塞知道新消息到达
(当然也可以阻塞知道消息的数量达到某个特定的量这样就可以批量发
消息由一个固定长度的头部和可变长度的字节数组组成。头部包含了一个版本号和 CRC32
校验码。
·消息长度: 4 bytes (value: 14n)
·版本号: 1 byte
·CRC 校验码: 4 bytes
·具体的消息: n bytes
(1).Kafka 把 topic 中一个 parition 大文件分成多个小文件段通过多个小文件段就容易定期清除或删除已经消费完文件减少磁盘占用。
(2).通过索引信息可以快速定位 message 和确定 response 的最大大小。
(3).通过 index 元数据全部映射到 memory可以避免 segment file 的 IO 磁盘操作。(4).通过索引文件稀疏存储可以大幅降低 index 文件元数据占用空间大小。
(1).Kafka 持久化日志这些日志可以被重复读取和无限期保留
(2).Kafka 是一个分布式系统它以集群的方式运行可以灵活伸缩在内部通过复制数据提升容错能力和高可用性
(3).Kafka 支持实时的流式处理