延吉湖北乐清贵港襄阳宜春
投稿投诉
宜春榆林
滕州锦州
襄阳晋中
泰州云南
贵港许昌
娄底河南
乐清寿光
阜阳汉中
湖北漳州
海口陕西
延吉东营
河源海南

Prometheus时序数据库磁盘中的存储结构

2月14日 渡缘祠投稿
  Prometheus时序数据库磁盘中的存储结构前言
  之前的文章里,笔者详细描述了监控数据在Prometheus内存中的结构。而其在磁盘中的存储结构,也是非常有意思的,关于这部分内容,将在本篇文章进行阐述。
  磁盘目录结构
  首先我们来看Prometheus运行后,所形成的文件目录结构
  在笔者自己的机器上的具体结构如下:prometheusdata
  01EY0EH5JA3ABCB0PXHAPP999D(block)
  01EY0EH5JA3QCQB0PXHAPP999D(block)
  chunks
  000001
  000002
  。。。。。
  000021
  index
  meta。json
  tombstones
  wal
  chunkshead
  Block
  一个Block就是一个独立的小型数据库,其保存了一段时间内所有查询所用到的信息。包括标签索引符号表数据等等。Block的实质就是将一段时间里的内存数据组织成文件形式保存下来。
  最近的Block一般是存储了2小时的数据,而较为久远的Block则会通过compactor进行合并,一个Block可能存储了若干小时的信息。值得注意的是,合并操作只是减少了索引的大小(尤其是符号表的合并),而本身数据(chunks)的大小并没有任何改变。
  meta。json
  我们可以通过检查meta。json来得到当前Block的一些元信息。{
  ulid:01EY0EH5JA3QCQB0PXHAPP999D
  maxTimeminTime7200s2h
  minTime:1611664000000
  maxTime:1611671200000
  stats:{
  numSamples:1505855631,
  numSeries:12063563,
  numChunks:12063563
  }
  compaction:{
  level:1
  sources:〔
  01EY0EH5JA3QCQB0PXHAPP999D
  〕
  }
  version:1
  }
  其中的元信息非常清楚明了。这个Block记录了2个小时的数据。
  让我们再找一个比较陈旧的Block看下它的meta。json。ulid:01EXTEH5JA3QCQB0PXHAPP999D,
  maxTimemaxTime162h
  minTime:1610964800000,
  maxTime:1611548000000
  。。。。。。
  compaction:{
  level:5,
  sources:〔
  31个01EX。。。。。。
  〕
  },
  parents:〔
  {
  ulid:01EXTEH5JA3QCQB1PXHAPP999D
  。。。
  }
  {
  ulid:01EXTEH6JA3QCQB1PXHAPP999D
  。。。
  }
  {
  ulid:01EXTEH5JA31CQB1PXHAPP999D
  。。。
  }
  〕
  从中我们可以看到,该Block是由31个原始Block经历5次压缩而来。最后一次压缩的三个Blockulid记录在parents中。如下图所示:
  Chunks结构CUT文件切分
  所有的Chunk文件在磁盘上都不会大于512M,对应的源码为:func(wWriter)WriteChunks(chks。。。Meta)error{
  。。。。。。
  fori,chk:rangechks{
  cutNewBatch:(i!0)(batchSizeSegmentHeaderSizew。segmentSize)
  。。。。。。
  ifcutNewBatch{
  。。。。。。
  }
  。。。。。。
  }
  }
  当写入磁盘单个文件超过512M的时候,就会自动切分一个新的文件。
  一个Chunks文件包含了非常多的内存Chunk结构,如下图所示:
  图中也标出了,我们是怎么寻找对应Chunk的。通过将文件名(000001,前32位)以及(offset,后32位)编码到一个int类型的refId中,使得我们可以轻松的通过这个id获取到对应的chunk数据。
  chunks文件通过mmap去访问
  由于chunks文件大小基本固定(最大512M),所以我们很容易的可以通过mmap去访问对应的数据。直接将对应文件的读操作交给操作系统,既省心又省力。对应代码为:funcNewDirReader(dirstring,poolchunkenc。Pool)(Reader,error){
  。。。。。。
  for,fn:rangefiles{
  f,err:fileutil。OpenMmapFile(fn)
  。。。。。。
  }
  。。。。。。
  bsappend(bs,realByteSlice(f。Bytes))
  }
  通过sgmBytes:s。bs〔offset〕就直接能获取对应的数据
  index索引结构
  前面介绍完chunk文件,我们就可以开始阐述最复杂的索引结构了。
  寻址过程
  索引就是为了让我们快速的找到想要的内容,为了便于理解。笔者就通过一次数据的寻址来探究Prometheus的磁盘索引结构。考虑查询一个拥有系列三个标签
  ({name:httprequests}{job:apiserver}{instance:0})
  且时间为startend的所有序列数据
  我们先从选择Block开始,遍历所有Block的meta。json,找到具体的Block
  前文说了,通过Labels找数据是通过倒排索引。我们的倒排索引是保存在index文件里面的。那么怎么在这个单一文件里找到倒排索引的位置呢?这就引入了TOC(TableOfContent)
  TOC(TableOfContent)
  由于index文件一旦形成之后就不再会改变,所以Prometheus也依旧使用mmap来进行操作。采用mmap读取TOC非常容易:funcNewTOCFromByteSlice(bsByteSlice)(TOC,error){
  。。。。。。
  indexTOCLen68452
  b:bs。Range(bs。LenindexTOCLen,bs。Len)
  。。。。。。
  returnTOC{
  Symbols:d。Be64,
  Series:d。Be64,
  LabelIndices:d。Be64,
  LabelIndicesTable:d。Be64,
  Postings:d。Be64,
  PostingsTable:d。Be64,
  },nil
  }
  Postingoffsettable以及Posting倒排索引
  首先我们访问的是Postingoffsettable。由于倒排索引按照不同的LabelPair(keyvalue)会有非常多的条目。所以Posingoffsettable就是决定到底访问哪一条Posting索引。offset就是指的这一Posting条目在文件中的偏移。
  Series
  我们通过三条Postings倒排索引索引取交集得出{series1,Series2,Series3,Series4}
  {series1,Series2,Series3}
  {Series2,Series3}
  {Series2,Series3}
  也就是要读取Series2和Serie3中的数据,而Posting中的Ref(Series2)和Ref(Series3)即为这两Series在index文件中的偏移。
  Series以Delta的形式记录了chunkId以及该chunk包含的时间范围。这样就可以很容易过滤出我们需要的chunk,然后再按照chunk文件的访问,即可找到最终的原始数据。
  SymbolTable
  值得注意的是,为了尽量减少我们文件的大小,对于Label的Name和Value这些有限的数据,我们会按照字母序存在符号表中。由于是有序的,所以我们可以直接将符号表认为是一个
  string切片。然后通过切片的下标去获取对应的sting。考虑如下符号表:
  读取index文件时候,会将SymbolTable全部加载到内存中,并组织成symbolsstring这样的切片形式,这样一个Series中的所有标签值即可通过切片下标访问得到。
  LabelIndex以及LabelTable
  事实上,前面的介绍已经将一个普通数据寻址的过程全部讲完了。但是index文件中还包含label索引以及labelTable,这两个是用来记录一个Label下面所有可能的值而存在的。
  这样,在正则的时候就可以非常容易的找到我们需要哪些LabelPair。详情可以见前篇。
  事实上,真正的LabelIndex比图中要复杂一点。它设计成一条LabelIndex可以表示(多个标签组合)的所有数据。不过在Prometheus代码中只会采用存储一个标签对应所有值的形式。
  完整的index文件结构
  这里直接给出完整的index文件结构,摘自Prometheus中index。md文档。
  magic(0xBAAAD700)4bversion(1)1byte
  SymbolTable
  Series
  LabelIndex1
  。。。
  LabelIndexN
  Postings1
  。。。
  PostingsN
  LabelIndexTable
  PostingsTable
  TOC
  tombstones
  由于PrometheusBlock的数据一般在写完后就不会变动。如果要删除部分数据,就只能记录一下删除数据的范围,由下一次compactor组成新block的时候删除。而记录这些信息的文件即是tomstones。
  Prometheus入门书籍推荐
  总结
  Prometheus作为时序数据库,设计了各种文件结构来保存海量的监控数据,同时还兼顾了性能。只有彻底了解其存储结构,才能更好的指导我们应用它!
投诉 评论 转载

尿频尿急尿困难,先别怪肾虚,还有可能是尿路感染我们人体一天大约需要排出1500ml尿液,约一个大瓶可乐的量,排尿次数在46次左右。然而,总有一些人,因为各种各样的原因,出现了尿频、尿急、每次排尿还会有灼热感,刺痛感,……有种整容叫嫁日本人,林志玲刚结婚2年,如今却判若两人文章纯属原创,版权归本作者所有,欢迎个人转发分享人们对于婚姻的看法是存在很多差异的,有的人向往婚姻的相濡以沫,但也有人在婚姻中闹得不可开交。基于现实状况,不得不承认……孩子不听话脾气倔,作为家长的老是控制不住自己的情绪怎么办?家庭教育中最大的拦路虎就是家长认为自己改不了、控制不住、无法改变、很难改变自己,这是普遍现象!而我认为:解决家庭教育现存问题的最好方法是让家长掌握某种能够帮助自己,克服教……为什么不吃糖也会长蛀牙?如果给每天孩子刷牙,也很少吃糖,为什么还会出现龋齿呢?导致孩子蛀牙的真相究竟是什么呢?儿童的乳牙或恒牙都可以发生龋齿,病变的进行一般都很缓慢,先是牙釉质发生龋蚀,牙……大熊猫基地起名废,奇葩网友脑洞大开叫熊样或者是熊出没?人如其名,一个好的名字也是第一印象的重要的一部分。人类的父母会费尽心力地为孩子取一个好听的名字,而大熊猫的奶爸奶妈们也会费尽心力地为它们取一个好搞笑的名字。当然不是说所有……拉黑你的男人,就别再联系了人这一生,会遇见很多人的。有的人,即便给过你很多的惊喜,终究也只能陪你一阵子。对于这些人,当他在你身边的时候,要好好珍惜。一旦离开了,就应该各自安好,不再打扰。人的心,其实是很……女宝宝名字,属于洋气大方类型核心提示:女宝宝名字,属于洋气大方类型。给女孩取不同的名字带来的影响是不一样的,简单的名字更容易被人记住,有利于女孩子交朋友。给女孩子取一个大方的名字,容易体现出女孩的气质,给……给娃第一次带饭今天周三,照例是晚上的英语课,以前都是晚上有课就外面快餐吃一顿,吃了几次娃就不想吃了,惦记老母亲的肉夹馍了,好吧,今天给你安排上!饼胚是中午做好冻到冰箱里的,肉也是中午炖好的,……很多人觉得欧美剧就是爽,其实不是其实摄影技术本来就是电影艺术的一部分,就像运笔技术是绘画艺术的一部分,或者和声设计是音乐创作艺术的一部分。好的电影电视剧几乎每一个镜头都是参考美学理论拍的,从构图到光线设计再到……Prometheus时序数据库磁盘中的存储结构Prometheus时序数据库磁盘中的存储结构前言之前的文章里,笔者详细描述了监控数据在Prometheus内存中的结构。而其在磁盘中的存储结构,也是非常有意思的,关于这……汤姆猫拯救了我一转眼,大宝都一岁多了,可是说起来可笑,她一岁多了,我还没有真正的带过她一天。因为我当时是妊娠高血压,身体也亏了,小宝也有点收亏啦了,刨腹产生的她,她当时还在新生儿科待了十几天……情感咨询栗子姐每日情感问答(0710)【咨询】我的宝宝来之不易,真的是花了很多泪水来的,试管婴儿,曾经因为没有宝宝有过很多委屈,感情出现变动过,这个变动指向我老公,最后我的坚持,试管婴儿,吃药打针取卵,移植第一次失……
买了房的说后悔买房了?没买房的都天天为钱发愁没钱买房深圳地区家庭条件好,中考和高考压力大,越来越多的小留学生出国携五位伙伴共创生态,极氪开启智能纯电汽车未来式继秋天第一杯奶茶后,奶茶又喜登热搜!减肥的你该做这个决定了它是宝宝的天然助长剂!春天一定要经常给娃吃不说人话?对于一篇高考满分作文,我们真的有必要如此抵触吗立春后,多给孩子吃这6道家常蒸菜,清淡少油,孩子猛涨个子13次产检生下智残儿,患儿的父母可以作为原告起诉医院吗?剖腹产产后怎么快速恢复不落病,需要注意什么呢?说说我个人对生二胎三胎的看法吧红楼梦薛姨妈为什么一直赖在贾府不走?中考女儿喜欢易烊千玺,爸妈做法令人羡慕青春期不是父母之殇

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找七猫云易事利