1.背景

  1. 目前IoTDB主要的功能是针对时间序列的数据存储,分析,无法进行数据采集。
  2. Prometheus 提供的是一整套监控体系。(Prometheus允许用户使用他们的数据库,而不仅仅是普罗米修斯数据库来存储时间序列数据库。)
    1. 服务核心组件,通过pull metrics从Exporter拉取和存储监控数据,并提供一套灵活的查询语言(PromQL)
    2. pushgateway:类似于一个中转站,Prometheus Server只会通过pull方式拉取数据但是某些节点因为某些原因只能通过Push方式推送数据,这个时候就需要pushgateway了,它负责的是接收push来的数据并暴露给Prometheus Server,以待其拉取。
    3. Exporters/Jobs:负责收集目标对象(host,container...)的性能数据,并通过HTTP接口供Prometheus Server获取
    4. Service Discovery:服务发现,Prometheus支持多种服务发现机制:文件,DNS,Consul,Kubernetes,OpenStack,EC2等等,基于服务发现的过程并不复杂,通过第三方提供的接口,Prometheus查询到需要监控的Target列表,然后轮询这些Target获取监控数据。
    5. Alertmanager:从Prometheus Server端接收到alerts后,会进行去除重复数据,分组,并路由到对方的接收方式,发出警报,常见的接收方式有电子邮件,pagerduty等

2.目标

IoTDB集成Prometheus,实现IoTDB针对时间序列的数据采集。完善IoTDB的功能。

可以看到,Prometheus向IoTDB中写入数据通过中间件,Prometheus读取IoTDB的数据也通过中间件,中间件的主要作用是将Prometheus格式的数据和IoTDB所需格式的数据相互转换。

  1. IoTDB-Prometheus:实现Prometheus和IoTDB之间的模式映射将Prometheus的metric {label1="label1_value",label2="label2_value"}映射到时序
  2. 对正确性和性能的测试,不仅要集成Prometheus,也要知道在繁重的负载下是否可以很好的工作,例如:以非常高的频率生成数据
    1. 性能测试:Avalanche Code: https://github.com/open-fresh/avalanche
      支持通过Prometheus remote_write API接受数据的服务的负载测试,进行性能测试,
    2. 正确性测试:Prombench,Code: https://github.com/ncabatoff/prombench
      向Prometheus插入数据,然后查询Prometheus,将我们认为发送的内容与我们希望存储的内容进行比较。进行正确性测试

3.设计(前提:IoTDB Go Client)

3.1 配置Prometheus 远程存储

在Prometheus配置文件中配置远程存储的地址(由IoTDB-Prometheus提供)

eg:

3.2 IoTDB-Prometheus(接收Prometheus传输过来的数据/查询IoTDB中数据) 

IoTDB-Prometheus为外部go服务,使用go语言编译器编译生成可执行文件

  1. 前提

    1. Golang编译器

    2. 包含go-client的IoTDB

  2. Prometheus读取和写入远程存储都是通过HTTP协议,将数据以snappy方式压缩到协议缓冲区中

  3. IoTDB-Prometheus获取传输过来的数据,进行解压缩,反序列化,转化为IoTDB的数据格式(需要实现的)

  4. 调用go-client和IoTDB服务端进行数据交互(需要实现的)

3.3 将Prometheus的数据格式转成成IoTDB的数据格式

3.3.1问题

  1. 问题:Prometheus中label顺序不敏感,而在IoTDB中是敏感的

    1. Prometheus的时序构成

      1. metric name

      2. label key

      3. label value

    2. IoTDB的时序构成:

      1. storage group

      2. path(time series ID)

      3. measurement

    3. 在Prometheus中,使用一个metric和label的集合代表一条时间序列,label的顺序不影响

      eg:'host = server1, data_center = DC1` 和 `data_center = DC1, host = server1`相等。

    4. 在IoTDB中

      1. 一个path由多个部分组成,比如`root.sg1.DC1.server1` 由一个存储组 `root.sg1`和两个节点`DC1` 和`server1`构成

      2. 节点的顺序是需要考虑的,`root.sg1.DC1.server1` 和 `root.sg1.server1.DC1` 是两条不同的时序。

  2. 关键点:需要记录每个label对应的顺序,确保Prometheus中label顺序不同的同一条时序对应到IoTDB中也是一条时序

  3. 需要解决的事情

    1. 怎样映射label key和它对应的order
    2. 在不知道所有的label key的情况下,怎么维护他们之间的顺序

3.3.2 解决方案

  1. 主要思想:
    1. 内存中Map <Metric, Map <Label Key, Order> > table结构维护label之间的顺序
    2. Prometheus中时序根据label顺序对应到IoTDB
  2. 实例
    1. 添加时序
      1.  Prometheus时序: 

        (1)country{state=A,city=B,town=C}

        (2)country{tem=D}

        (3))country{state=A,city=B,town=C,tem=D}  

      2. 假设存储组数量为5,则("country").hashCode() % 5为2,对应的存储组为sg2,测点为country
      3.  (1)对应的记录label顺序的table为

        metric_name 
        label_key 
        order 
        country
        state
        0
        country
        city
        1
        country
        town
        2

         (2)对应的记录label顺序的table为 

        metric_name 
        label_key 
        order 
        country
        state
        0
        country
        city
        1
        country
        town
        2
        country
        tem3

        (3)对应的记录label顺序的table为

        metric_name 
        label_key 
        order 
        country
        state
        0
        country
        city
        1
        country
        town
        2
        country
        tem3
      4. (1)对应IoTDB时序为root.sg2.country .A.B.C.

        (2)对应IoTDB时序为root.sg2.country.ph.ph.ph.D

        (3)对应IoTDB时序为root.sg2.country.A.B.C.D

      5. 为了重启时候对table的恢复,在IoTDB中记录数据

        root.LABEL_INFO.metric_name
        root.LABEL_INFO.label_name
        root.LABEL_INFO.label_order
        country 
        state 
        0
        country
        city
        1
        country
        town
        2
        country
        tem3
    2. 查询数据
      1. 查询数据:查询country中city=B的数据,city的order为1,country中order的最大值为3

        1. 对应到IoTDB中的查询为

          select * from root.sg0.country.*.B
  3. 设计
    1. 允许用户设置IoTDB中SG的数量,例如,`SG_NUMBER`=5。可以是`iotdb-engine.properties`中的参数.然后得到5个sg,比如“sg0,sg1,…,sg4”。

    2. metric

      1. 认为是IoTDB中的一个measurement

      2. 可以通过hash决定metric会对应到哪个存储组,eg Metric.hashcode() % SG_NUMBE‘

    3. 在内存中维护一个table去保存对应的映射,在内存中的结构为:Map <Metric, Map <Label Key, Order> > table(改进:考虑到内存开销,可以只将表的一部分作为缓存保存在内存中)------- 解决问题:怎样映射label key和它对应的order

    4. 在IoTDB中存储metric,label以及其对应的顺序,通过三条时序(以便在IoTDB重启的时候恢复内存中的table)

      1. 'root.system_p.label_info.metric_name'

      2. root.system_p.label_info.label_name'

      3. 'root.system_p.label_info.label_order`
    5. 添加metric时维护map ------------ 解决问题:在不知道所有label的情况下维护map

      1. 首先判断table.get(metric_name)为空,则向时序'root.LABEL_INFO.metric_name'中添加数据点,时间戳可以是系统当前的时间或者是0,1,2,3,value是metric name,同时在table中添加对应的metric

      2. 其次根据metric_name,label_key判断table.get(metric_name).get(label_key)为空,则向时序'root.system_p.label_info.label_name'中添加数据点,时间戳可以是系统当前的时间或者是0,1,2,3,value是label_key

        同时也要向时序'root.system_p.label_info.label_order`中添加数据点,时间戳和对应的'root.system_p.label_info.label_name'中添加的数据点的时间戳相同,但是value是对应的metric中的最大的order+1

        table.get(metric_name)中添加对应的label_key和lable_order.

    6. 生成IoTDB对应的时序

      1. string paths[]数组记录时序节点,int  largest记录metric中label的order的最大值
      2. 已有的label,paths[label_order]=label_value
      3. 新的label,paths[largest+1]=label_value
      4. 遍历paths数组,null的位置填充ph,得到时序root+sg_name+metric + paths.sub(0, paths.size()-1)

3.4 参考文档

  1. https://docs.google.com/document/d/1UYOUd0YomS6NUitG9Ko0gqzYapn6eqhFuy_5F3NKVxg/edit#heading=h.mdfygy3ywxxh
  2. https://docs.google.com/document/d/1DZL1L0GccLvHbMJyop62cbaSvu1tkJ6Pp1Fp6FsR09U/edit#heading=h.58lkrsg45cf2
  3. https://issues.apache.org/jira/projects/IOTDB/issues/IOTDB-519?filter=allopenissues&orderby=cf%5B12310310%5D+ASC%2C+priority+DESC%2C+updated+DESC
  4. https://prometheus.io/docs/prometheus/latest/storage/
  5. https://songjiayang.gitbooks.io/prometheus/content/exporter/text.html
  6. https://www.taosdata.com/cn/documentation/insert/#Prometheus%E7%9B%B4%E6%8E%A5%E5%86%99%E5%85%A5
  • No labels

3 Comments

  1. suggest to move storage group `root.LABEL_INFO` to `root.system_p.label_info` 

  2. Jialin Qiao  may have something to discuss about the query.

  3. As the big difference of data model between the IoTDB and prometheus, I think it's better to have some assumptions and restrictions to simplify the implementation of the prometheus adapter.

    For example, it's hard to decide the order of the path by the connecter, the exporter should export data as the path order. And storage group is so important that we need to provide some kind of API to let user decide which storage group to user.