kafka本地存储3-LogSegment
来源:互联网 发布:ecshop多用户商城源码 编辑:程序博客网 时间:2024/06/08 08:23
LogSegment
classLogSegment(vallog: FileMessageSet,
valindex: OffsetIndex,
val baseOffset: Long, //这个Segment存储的消息的partition起始的消息偏移量
val indexIntervalBytes: Int,
val rollJitterMs: Long,
val baseOffset: Long, //这个Segment存储的消息的partition起始的消息偏移量
val indexIntervalBytes: Int,
val rollJitterMs: Long,
time: Time)
//LogSegment.rollJitterMs字段说明
//如果这个segment即将写满,就开始创建新的segment进行回滚,并返回需要写入的segment
//segment.size这个LogSegment已经写入的消息占用的字节大小
//1.目前的segment空闲字节不足,segment.size > config.segmentSize - messagesSize
//2.按照时间间隔进行回滚
//3.segment索引文件满,segment.index.isFull
//config.segmentMs是段对象存活的时间@param segmentMs
//为避免config.segmentMs后segment同时进行回滚,用@param segmentJitterMs 来错开进行回滚
//roll,进行回滚操作
//1.取出segments.lastEntry的segment,把索引文件缩小到当前存储的索引个数的长度
//2.创建LogSegment
//3.添加到成员变量this.segments
//key为这个Segment存储的消息的partition起始的消息偏移量
//value为LogSegment
//4.flush
//1).把this.recoveryPoint到newOffset的partition的绝对偏移量的segment列表,来逐个flush
//segment.flush就是把index和log文件进行flush
//2).用参数newOffset来设置this.recoveryPoint
//如果这个segment即将写满,就开始创建新的segment进行回滚,并返回需要写入的segment
//segment.size这个LogSegment已经写入的消息占用的字节大小
//1.目前的segment空闲字节不足,segment.size > config.segmentSize - messagesSize
//2.按照时间间隔进行回滚
//3.segment索引文件满,segment.index.isFull
//config.segmentMs是段对象存活的时间@param segmentMs
//为避免config.segmentMs后segment同时进行回滚,用@param segmentJitterMs 来错开进行回滚
//roll,进行回滚操作
//1.取出segments.lastEntry的segment,把索引文件缩小到当前存储的索引个数的长度
//2.创建LogSegment
//3.添加到成员变量this.segments
//key为这个Segment存储的消息的partition起始的消息偏移量
//value为LogSegment
//4.flush
//1).把this.recoveryPoint到newOffset的partition的绝对偏移量的segment列表,来逐个flush
//segment.flush就是把index和log文件进行flush
//2).用参数newOffset来设置this.recoveryPoint
//3).this.lastflushedTime设置当前时间time.milliseconds
//LogSegment.created创建这个LogSegment记录的时间戳
var created = time.milliseconds
//this.bytesSinceLastIndexEntry记录写入的字节数,如果字节数超过成员indexIntervalBytes,就开始写入到索引中
private var bytesSinceLastIndexEntry= 0
//把消息集合写入到log中,如果bytesSinceLastIndexEntry字节超过indexIntervalBytes,
//就先把下一条的绝对offset和在这个seg的物理字节偏移写入索引中
def append(offset: Long, messages: ByteBufferMessageSet)
//从startingFilePosition查找绝对offset的OffsetPosition信息
//先从索引中找一定的范围,之后再从log中具体的字节位置
//@参数offset 是在partition的绝对消息偏移量
//offset是在partition中的消息绝对位移
//position是partition中片段segment的物理的字节偏移量
//先从索引中找一定的范围,之后再从log中具体的字节位置
//@参数offset 是在partition的绝对消息偏移量
//offset是在partition中的消息绝对位移
//position是partition中片段segment的物理的字节偏移量
//case class OffsetPosition(val offset: Long,val position: Int)
private[log]def translateOffset(offset: Long, startingFilePosition: Int = 0): OffsetPosition
//从startOffset开始读,两个maxOffset和maxSize参数为从段中读取数据的上限
//读取到偏移量maxOffset,或者读取段中maxSize字节的内容
//@参数startOffset 是在partition的绝对消息偏移量
//从startOffset转化为字节位置信息
//如果绝对maxOffset不为空,就把maxOffset转化为对应的结尾字节偏移位置
//如果绝对maxOffset为空,就把maxSize当作结尾字节位置
//读取到偏移量maxOffset,或者读取段中maxSize字节的内容
//@参数startOffset 是在partition的绝对消息偏移量
//从startOffset转化为字节位置信息
//如果绝对maxOffset不为空,就把maxOffset转化为对应的结尾字节偏移位置
//如果绝对maxOffset为空,就把maxSize当作结尾字节位置
//之后返回FetchDataInfo(offsetMetadata, log.read(startPosition.position, length))
def read(startOffset: Long, maxOffset: Option[Long], maxSize: Int): FetchDataInfo
//重建索引
//把该段存储字节长度调整为参数maxMessageSize,索引也会一起调整
//在遍历log.iterator时,如果超过maxMessageSize,就会抛异常
//把该段存储字节长度调整为参数maxMessageSize,索引也会一起调整
//在遍历log.iterator时,如果超过maxMessageSize,就会抛异常
//在抛异常时读取的位置就是要截取的后一个消息
//返回truncated = log.sizeInBytes - validBytes
//validBytes表示重建索引时成功遍历message时的字节数综合
//validBytes表示重建索引时成功遍历message时的字节数综合
//truncated不为0,表示在重建索引过程中出现异常
def recover(maxMessageSize: Int): Int
//先截断到offset,之后从参数offset的位置开始写入消息
def truncateTo(offset: Long): Int
//得到改seg要写入的下一个位置的partition绝对偏移
//取出索引中存储最后一个索引信息的绝对partition消息偏移值,组成FetchDataInfo
//从FetchDataInfo.messageSet.lastOption 来得到最后一个消息,
//取出索引中存储最后一个索引信息的绝对partition消息偏移值,组成FetchDataInfo
//从FetchDataInfo.messageSet.lastOption 来得到最后一个消息,
//MessageAndOffset.nextOffset为下一个要写入的partition的绝对消息偏移
def nextOffset(): Long
OffsetIndex
每个partition由多个segment组成,每个segment对应一个OffsetIndex
OffsetIndex(@volatilevarfile: File,valbaseOffset: Long,valmaxIndexSize: Int = -1)
baseOffset为该segment在partition上的绝对消息偏移量
maxIndexSize是这个索引文件的最大字节数,索引文件的每个结构都是8字节,需要把文件长度进行8字节对齐
OffsetIndex的每个结构占用8字节
前4个字节为在segment中的消息相对偏移量
后4字节为在这个segment中的物理字节偏移量
OffsetIndex作用
查询给定的partition的绝对消息偏移量在segment的物理字节偏移量时,需要先从OffsetIndex查到大概在segment的物理字节偏移位置
之后在根据这个位置在segment进行向后查找,找到在segment具体的物理字节偏移值
1.targetOffset是partition的绝对偏移量,转化成segment对应的OffsetIndex的相对偏移值,relOffset= targetOffset - OffsetIndex.baseOffset
2.在OffsetIndex找到不大于relOffset的8字节结构
3.创建OffsetPosition对象,OffsetPosition(baseOffset+ relativeOffset(idx,slot), physical(idx,slot))
4.通过physical字节偏移,在segment中向后查找,直到找到对应的targetOffset所在的消息为止
Log
//recoveryPoint 是一个消息偏移量,表示要从这个偏移量所在的段segment开始到最新段segment进行索引重建
//如果参数dir的父目录下有.kafka_cleanshutdown后缀的文件,就不进行索引重建
//如果参数dir的父目录下有.kafka_cleanshutdown后缀的文件,就不进行索引重建
//每次append后this.recoveryPoint = activeSegment.nextOffset
classLog(valdir: File,
@volatilevarconfig: LogConfig,
@volatilevarrecoveryPoint: Long =0L,
scheduler: Scheduler,
@volatilevarrecoveryPoint: Long =0L,
scheduler: Scheduler,
time: Time = SystemTime)
//key为这个Segment存储的消息的partition起始的消息偏移量
//value为LogSegment
valsegments: ConcurrentNavigableMap[java.lang.Long, LogSegment] =new ConcurrentSkipListMap[java.lang.Long, LogSegment]
loadSegments()
//1.读取参数dir中的segment信息,.deleted或.cleaned后缀,直接删除,删除掉index的swap文件,把log的swap文件改名为log文件
//2.如果只存在index文件,没有对应的log文件,那删除掉这个index
//3.根据文件,创建LogSegment,.log文件的文件名是这个segment的在partition的绝对的消息偏移,如果没有index文件,就重建索引
//4.设置到成员变量字典中segments.put(start, segment)
//如果目录中没有文件,就segments.put(0L, new LogSegment
//2.如果只存在index文件,没有对应的log文件,那删除掉这个index
//3.根据文件,创建LogSegment,.log文件的文件名是这个segment的在partition的绝对的消息偏移,如果没有index文件,就重建索引
//4.设置到成员变量字典中segments.put(start, segment)
//如果目录中没有文件,就segments.put(0L, new LogSegment
//目录中有文件,取出绝对消息偏移量在this.recoveryPoint到Long.MaxValue的partiton范围的Segment列表
//对这个列表进行重建索引
//如果重建索引有异常,就利用定时器删除异常之后的segment列表
//5.遍历segments字典,验证索引的有效性
//1).索引记录的lastOffset要大于该segment的baseOffset
//2).索引文件长度必须能被8整除
//如果重建索引有异常,就利用定时器删除异常之后的segment列表
//5.遍历segments字典,验证索引的有效性
//1).索引记录的lastOffset要大于该segment的baseOffset
//2).索引文件长度必须能被8整除
private def loadSegments()
//LogOffsetMetadata(messageOffset,segmentBaseOffset,relativePositionInSegment)
//@参数messageOffset 是在partition的绝对消息偏移量
//@参数messageOffset 是在partition的绝对消息偏移量
//@参数segmentBaseOffset 是在这个seg中的起始绝对偏移量
//@relativePositionInSegment 是在seg中的物理字节偏移量
//activeSegment.nextOffset()解释
//得到改seg要写入的下一个位置的partition绝对偏移
//取出索引中存储最后一个索引信息的绝对partition消息偏移值,组成FetchDataInfo
//从FetchDataInfo.messageSet.lastOption 来得到最后一个消息,
//MessageAndOffset.nextOffset为下一个要写入的partition的绝对消息偏移
var nextOffsetMetadata = new LogOffsetMetadata(activeSegment.nextOffset(), activeSegment.baseOffset, activeSegment.size.toInt)
//更新成员变量this.nextOffsetMetadata
//LogOffsetMetadata(messageOffset, activeSegment.baseOffset, activeSegment.size.toInt)
//@参数messageOffset 是在partition的绝对消息偏移量
//@参数segmentBaseOffset 是在这个seg中的起始绝对偏移量
//@relativePositionInSegment 是在seg中的物理字节偏移量
private def updateLogEndOffset(messageOffset: Long) {
nextOffsetMetadata =newLogOffsetMetadata(messageOffset, activeSegment.baseOffset, activeSegment.size.toInt)
//LogOffsetMetadata(messageOffset, activeSegment.baseOffset, activeSegment.size.toInt)
//@参数messageOffset 是在partition的绝对消息偏移量
//@参数segmentBaseOffset 是在这个seg中的起始绝对偏移量
//@relativePositionInSegment 是在seg中的物理字节偏移量
private def updateLogEndOffset(messageOffset: Long) {
nextOffsetMetadata =newLogOffsetMetadata(messageOffset, activeSegment.baseOffset, activeSegment.size.toInt)
}
append
defappend(messages: ByteBufferMessageSet, assignOffsets: Boolean =true): LogAppendInfo
//@参数messages,需要添加的集合ByteBufferMessageSet
//@参数assignOffsets.是否使用参数messages的offset来添加消息,如果不是,就使用log.nextOffsetMetadata.messageOffset递增来添加消息
//class LogAppendInfo(var firstOffset: Long,var lastOffset: Long, codec: CompressionCodec,
//shallowCount: Int, validBytes: Int, offsetsMonotonic: Boolean)
//通过分析消息集合ByteBufferMessageSet得到如下信息,1)验证单个消息不能超过config.maxMessageSize,2)验证Crc校验码
//之后创建LogAppendInfo,并返回该对象
//firstOffset在这个消息集合中的第一个消息的partition绝对偏移量
//lastOffset在这个消息集合中的最后一个消息的partition绝对偏移量
//codec是这个集合的压缩类型
//shallowMessageCount 是集合中消息个数
//validBytesCount是集合中消息总字节大小
//monotonic 是这个偏移量是否是自增的, false表示offset不是自增的
//shallowCount: Int, validBytes: Int, offsetsMonotonic: Boolean)
//通过分析消息集合ByteBufferMessageSet得到如下信息,1)验证单个消息不能超过config.maxMessageSize,2)验证Crc校验码
//之后创建LogAppendInfo,并返回该对象
//firstOffset在这个消息集合中的第一个消息的partition绝对偏移量
//lastOffset在这个消息集合中的最后一个消息的partition绝对偏移量
//codec是这个集合的压缩类型
//shallowMessageCount 是集合中消息个数
//validBytesCount是集合中消息总字节大小
//monotonic 是这个偏移量是否是自增的, false表示offset不是自增的
//messageSize > config.maxMessageSize
//LogAppendInfo.validBytes 不等于 messages.sizeInBytes
//buffer.limit(LogAppendInfo.validBytes)之后用这个buff创建ByteBufferMessageSet
//参数assignOffsets为true, 重置该set中的消息位置的值 validMessages.assignOffsets(offset,appendInfo.codec)
//如果消息的大小超过config.maxMessageSize,就抛异常MessageSizeTooLargeException
//消息集合的总大小超过配置的config.segmentSize,抛异常MessageSetSizeTooLargeException
//如果这个segment即将写满,就开始创建新的segment进行回滚,并返回需要写入的segment
//segment.size这个LogSegment已经写入的消息占用的字节大小
//1.目前的segment空闲字节不足,segment.size > config.segmentSize - messagesSize
//2.按照时间间隔进行回滚
//3.segment索引文件满,segment.index.isFull
//config.segmentMs是段对象存活的时间@param segmentMs
//为避免config.segmentMs后segment同时进行回滚,用@param segmentJitterMs 来错开进行回滚
//roll,进行回滚操作
//1.取出segments.lastEntry的segment,把索引文件缩小到当前存储的索引个数的长度
//2.创建LogSegment
//3.添加到成员变量this.segments
//key为这个Segment存储的消息的partition起始的消息偏移量
//value为LogSegment
//4.flush
//1).把this.recoveryPoint到newOffset的partition的绝对偏移量的segment列表,来逐个flush
//segment.flush就是把index和log文件进行flush
//2).用参数newOffset来设置this.recoveryPoint
//segment.size这个LogSegment已经写入的消息占用的字节大小
//1.目前的segment空闲字节不足,segment.size > config.segmentSize - messagesSize
//2.按照时间间隔进行回滚
//3.segment索引文件满,segment.index.isFull
//config.segmentMs是段对象存活的时间@param segmentMs
//为避免config.segmentMs后segment同时进行回滚,用@param segmentJitterMs 来错开进行回滚
//roll,进行回滚操作
//1.取出segments.lastEntry的segment,把索引文件缩小到当前存储的索引个数的长度
//2.创建LogSegment
//3.添加到成员变量this.segments
//key为这个Segment存储的消息的partition起始的消息偏移量
//value为LogSegment
//4.flush
//1).把this.recoveryPoint到newOffset的partition的绝对偏移量的segment列表,来逐个flush
//segment.flush就是把index和log文件进行flush
//2).用参数newOffset来设置this.recoveryPoint
//3).this.lastflushedTime设置当前时间time.milliseconds
//把消息集合写入到log中,如果bytesSinceLastIndexEntry字节超过indexIntervalBytes,
//就先把下一条的绝对offset和在这个seg的物理字节偏移写入索引中
//更新成员变量this.nextOffsetMetadata
//LogOffsetMetadata(messageOffset, activeSegment.baseOffset, activeSegment.size.toInt)
//@参数messageOffset 是在partition的绝对消息偏移量
//@参数segmentBaseOffset 是在这个seg中的起始绝对偏移量
//LogOffsetMetadata(messageOffset, activeSegment.baseOffset, activeSegment.size.toInt)
//@参数messageOffset 是在partition的绝对消息偏移量
//@参数segmentBaseOffset 是在这个seg中的起始绝对偏移量
//@relativePositionInSegment 是在seg中的物理字节偏移量
//nextOffsetMetadata = new LogOffsetMetadata(messageOffset, activeSegment.baseOffset, activeSegment.size.toInt)
//上次flush到新写入的消息的个数 unflushedMessages() = this.logEndOffset - this.recoveryPoint
//unflushedMessages >= config.flushInterval
//进行flush时,写入的消息个数的阈值
//Log.logEndOffset: Long = nextOffsetMetadata.messageOffset
//使用参数nextOffsetMetadata.messageOffset,进行flush
//1.把this.recoveryPoint到offset的partition的绝对偏移量的segment列表,来逐个flush
//segment.flush就是把index和log文件进行flush
//2.用参数offset来设置this.recoveryPoint
//unflushedMessages >= config.flushInterval
//进行flush时,写入的消息个数的阈值
//Log.logEndOffset: Long = nextOffsetMetadata.messageOffset
//使用参数nextOffsetMetadata.messageOffset,进行flush
//1.把this.recoveryPoint到offset的partition的绝对偏移量的segment列表,来逐个flush
//segment.flush就是把index和log文件进行flush
//2.用参数offset来设置this.recoveryPoint
//3.this.lastflushedTime设置当前时间time.milliseconds
read
defread(startOffset: Long, maxLength: Int, maxOffset: Option[Long] = None): FetchDataInfo
next= nextOffsetMetadata.messageOffset
//从参数segments得到小于参数startOffset的最大的key值
//Log.segments类型Map[java.lang.Long, LogSegment]
var entry = segments.floorEntry(startOffset)
startOffset >next|| entry == null 超过范围,抛异常OffsetOutOfRangeException
//从startOffset开始读消息集合,两个maxOffset和maxSize参数为从段中读取数据的上限
//如果读不出来,就从segments向后一个key来继续读,直到读取的信息fetchInfo不为空位置
valfetchInfo= entry.getValue.read(startOffset, maxOffset, maxLength)
//FetchDataInfo(fetchOffset: LogOffsetMetadata, messageSet: MessageSet)
//LogOffsetMetadata(messageOffset,segmentBaseOffset,relativePositionInSegment)
//@参数messageOffset 是在partition的绝对消息偏移量
//@参数segmentBaseOffset 是在这个seg中的起始绝对偏移量
//@relativePositionInSegment 是在seg中的物理字节偏移量
返回类型FetchDataInfo(fetchOffset: LogOffsetMetadata, messageSet: MessageSet)
0 0
- kafka本地存储3-LogSegment
- kafka本地存储2-message
- kafka本地存储4-LogCleaner
- kafka本地存储5-LogManager
- kafka本地存储1-配置说明
- LogSegment分析
- 3、Kafka的message存储数据结构
- kafka本地搭建流程
- 本地存储
- 本地存储
- 本地存储
- 本地存储
- 本地存储
- 本地存储
- 本地存储
- 本地存储
- 本地存储
- 本地存储
- xcode 常见的快捷方式组合
- Android 使用ViewPager实现左右循环滑动图片和显示当前页码
- HDU-4932-Miaomiao's Geometry【暴力枚举】
- DOM和SAX解析器的比较和选择
- Android 仿IOS3D时间选择器城市选择器
- kafka本地存储3-LogSegment
- 安装oracle gateways
- 文章标题
- 单例
- tableViewCell的选中状态的还原
- 123
- HDOJ 2053 Switch Game
- managedQuery 和 getContentResolver().query的区别
- 数字图像处理 调整对比度的几种方法