searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

浅谈Influxdb工作原理(一)

2023-06-15 01:43:14
146
0

1. 背景

本文是系统能通过对influxdb 1.8的代码进行基础的走读来理解这个influxdb的工作原理。 理解其中的一些设计思路。 

 

2. 感性认知

将influxdb和传统的数据库MySQL做个简单比较

  MySQL   Influxdb
类似点 table   measurement
  index field   tag
  unindex field   field
  pk   timestamp
       
差异点 CRUD   CRD,  较少Update
  数据值   数据的趋势分析
  结构化数据   schemaless

 

初步感性操作Influxdb

这个是登录到influxdb里进行的SQL操作。可以看到并没有MySQL那种强的表结构的概念,字段是可以随意增加(如图第二个insert增加了一个addr字段), 从这个角度看到是schemaless的。

 

3. 基础概念

3.1  influxdb版本演进

主要是存储引擎的演进。

第一个阶段:

使用leveldb来做数据落地持久化的存储引擎,但是发现随着数据量的增加,leveldb耗用文件句柄过多;第二个问题就是按照时间删除数据代价过高,因为leveldb不是按照时间进行数据分片存储的,可能会涉及到很多文件的查找,性能比较底下。

第二个阶段:

使用一个go写的内存map数据库boltDb,好处就是一个db就是一个文件,虽然解决了文件句柄的问题,但是IOPS有比较大毛刺,性能不够稳定。

第三个阶段
使用boltDB+WAL, 通过日志来缓冲写请求,改为批次写如。

第四个阶段

就是最新的TSM存储引擎,自研。 从0.95和1.X版本都用这个存储引擎。

 

3.2 influxdb的逻辑结构

数据的逻辑组织结构。  它不像传统的MySQL(Database->table->data)库表的逻辑组织结构。

3.2.1 Database

      可以理解为类似MySQL的database概念,这个没太大区别。

3.2.2 RetentionPolicy-保留策略

     但是第二级并不是measurement(类似MySQL的table),  因为 一个measurement可以在不同的RetentionPolicy都存在。

     例子:  下面这个写入数据的db=mydb,measurement=disk_free, 然后写入的api可以指定rp,也就是可以支持写入到多个rp的。

         代码样例: 调用/write接口进行数据写入

               curl -X POST 'https://localhost:8086/write?db=mydb&rp=six_month_rollup' --data-binary 'disk_free,hostname=server01 value=442221834240i 1435362189575692182'

     创建保留策略: create retention policy one_month on ABC  duration 30d replication 2;

     说明:  从这个创建语句我们可以看出来,它定义的是在某个database上的数据保留时间和数据副本数,还可以定义每个shard的时间分片长度。

 

 

3.2.3 Shard

     数据根据时间进行的数据分片。  其实还有shard group的概念的。 这个shard分片主要就是根据时间进行分区, 和measurement没太大关系。 从这里可以看出来时间在数据组织中的重要性。   这样子在数据删除的时候,就变得简单了,直接可以从某个shard进行数据删除,不用想leveldb那样子,全局搜索了。

    每个Shard其实就是一个小型的Level,有自己的cache、wal和TSM 物理文件

 

3.3 数据写入流程

 

influxdb写入流程代码还是绕了几个弯弯, 才找到写入的最终落地代码位置:  influxdb/tsdb/engine/tsm1/engine.go

这里有一个疑问: 如果写入cache成功了,但是写入wal失败了? 那么这个数据能被读取到吗?

从这里也能看出来WAL并不是最先更新写入的。

3.4 物理文件

首层目录:

    wal: 就是存放各个shard的wal的, 例如 wal/abc/autogen/5: 就表示存放abc这个库, autogen存放策略(rp), 分片5的wal数据

    data:  同上

    meta: 存放集群的成员的元数据信息

    hh:  存放需要同步到其他集群成员的落地数据,这样子即便influxdb重启,也能异步进行数据同步。

 

 

4. influxdb源码初探

4.1 github仓库代码目录

这里只说比较重要的三个目录。 其他的逐步摊开就可以了。  influxdb本质是个http服务,那么一个典型的http服务,必定是有(路由,业务逻辑)这样子的结构。

cmd:  存放main函数入口,  这里注册各个services的路由。可以看看下面这个代码文件的这个位置。

services: 各个组件模块的。  例如httpd服务

 

例如以httpd模块来说, 它提供了很多http api来支持 influxdb的操作,例如上面提到的/write,你都能从handler.go文件里找到http路由注册入口,然后找到对应的处理函数,就能逐步梳理出这个influxdb的写入流程了。

 

 

5. influxdb集群版本

5.1 集群版本原理

官方的influxdb的集群版本是做成企业收费版,没有对外开放代码,github开源项目(https://github.com/chengshiwen/influxdb-cluster)参考如下的官方的实现来实现了一套。

 

meta nodes: 就是基于raft协议实现一套元数据的存储,包括节点成员、数据分布、账号验证信息都存储在meta节点上。

 

5.2 集群版本搭建

* 使用一个influxd-ctl的工具,add-meta来首先将3个节点组件成一个raft group。

* 然后使用add-data来讲data节点加入到这个meta group。

* 如果想知道上述这两个add操作做了啥,可以到项目里看看这个工具的操作(就是调用influxd的api进行节点操作)

* 就会在data节点的 ${HOME}/meta节点下有meta服务的节点信息

influxd-ctl add-meta influxdb-meta-01:8091
influxd-ctl add-meta influxdb-meta-02:8091
influxd-ctl add-meta influxdb-meta-03:8091
influxd-ctl add-data influxdb-data-01:8088
influxd-ctl add-data influxdb-data-02:8088
influxd-ctl show

 

5.3 写入一致性

集群版本写入可以配置写入一致性要求, 就是client 可以要求: 写入到全部节点、写入到至少2个节点、写入到任意一个节点就返回给client,这几种数据一致性的要求。

例如如果某个节点挂了,那么这个时候数据没法立即写入到相关节点。 那么这部分数据是通过hint-handoff的模块进行缓存和持久化落地到hh数据目录。这部分的代码实现主要在这个目录里,还是比较好理解的。   因为它主要就暴露2个接口: WriteShard和Empty接口。

6. 总结

本文简单讲述了influxdb的版本演进、逻辑结构、写入流程、集群原理等信息,下一步将讲解一下influxdb的读流程。整体来说 influxdb的代码还是比较易懂的,可以从具体api入手,然后看看对应的api代码实现。

influxdb源码还是比较规整的, 可以作为go学习入门挺好的一个学习项目。

 

 

0条评论
0 / 1000
郑****辉
6文章数
1粉丝数
郑****辉
6 文章 | 1 粉丝
原创

浅谈Influxdb工作原理(一)

2023-06-15 01:43:14
146
0

1. 背景

本文是系统能通过对influxdb 1.8的代码进行基础的走读来理解这个influxdb的工作原理。 理解其中的一些设计思路。 

 

2. 感性认知

将influxdb和传统的数据库MySQL做个简单比较

  MySQL   Influxdb
类似点 table   measurement
  index field   tag
  unindex field   field
  pk   timestamp
       
差异点 CRUD   CRD,  较少Update
  数据值   数据的趋势分析
  结构化数据   schemaless

 

初步感性操作Influxdb

这个是登录到influxdb里进行的SQL操作。可以看到并没有MySQL那种强的表结构的概念,字段是可以随意增加(如图第二个insert增加了一个addr字段), 从这个角度看到是schemaless的。

 

3. 基础概念

3.1  influxdb版本演进

主要是存储引擎的演进。

第一个阶段:

使用leveldb来做数据落地持久化的存储引擎,但是发现随着数据量的增加,leveldb耗用文件句柄过多;第二个问题就是按照时间删除数据代价过高,因为leveldb不是按照时间进行数据分片存储的,可能会涉及到很多文件的查找,性能比较底下。

第二个阶段:

使用一个go写的内存map数据库boltDb,好处就是一个db就是一个文件,虽然解决了文件句柄的问题,但是IOPS有比较大毛刺,性能不够稳定。

第三个阶段
使用boltDB+WAL, 通过日志来缓冲写请求,改为批次写如。

第四个阶段

就是最新的TSM存储引擎,自研。 从0.95和1.X版本都用这个存储引擎。

 

3.2 influxdb的逻辑结构

数据的逻辑组织结构。  它不像传统的MySQL(Database->table->data)库表的逻辑组织结构。

3.2.1 Database

      可以理解为类似MySQL的database概念,这个没太大区别。

3.2.2 RetentionPolicy-保留策略

     但是第二级并不是measurement(类似MySQL的table),  因为 一个measurement可以在不同的RetentionPolicy都存在。

     例子:  下面这个写入数据的db=mydb,measurement=disk_free, 然后写入的api可以指定rp,也就是可以支持写入到多个rp的。

         代码样例: 调用/write接口进行数据写入

               curl -X POST 'https://localhost:8086/write?db=mydb&rp=six_month_rollup' --data-binary 'disk_free,hostname=server01 value=442221834240i 1435362189575692182'

     创建保留策略: create retention policy one_month on ABC  duration 30d replication 2;

     说明:  从这个创建语句我们可以看出来,它定义的是在某个database上的数据保留时间和数据副本数,还可以定义每个shard的时间分片长度。

 

 

3.2.3 Shard

     数据根据时间进行的数据分片。  其实还有shard group的概念的。 这个shard分片主要就是根据时间进行分区, 和measurement没太大关系。 从这里可以看出来时间在数据组织中的重要性。   这样子在数据删除的时候,就变得简单了,直接可以从某个shard进行数据删除,不用想leveldb那样子,全局搜索了。

    每个Shard其实就是一个小型的Level,有自己的cache、wal和TSM 物理文件

 

3.3 数据写入流程

 

influxdb写入流程代码还是绕了几个弯弯, 才找到写入的最终落地代码位置:  influxdb/tsdb/engine/tsm1/engine.go

这里有一个疑问: 如果写入cache成功了,但是写入wal失败了? 那么这个数据能被读取到吗?

从这里也能看出来WAL并不是最先更新写入的。

3.4 物理文件

首层目录:

    wal: 就是存放各个shard的wal的, 例如 wal/abc/autogen/5: 就表示存放abc这个库, autogen存放策略(rp), 分片5的wal数据

    data:  同上

    meta: 存放集群的成员的元数据信息

    hh:  存放需要同步到其他集群成员的落地数据,这样子即便influxdb重启,也能异步进行数据同步。

 

 

4. influxdb源码初探

4.1 github仓库代码目录

这里只说比较重要的三个目录。 其他的逐步摊开就可以了。  influxdb本质是个http服务,那么一个典型的http服务,必定是有(路由,业务逻辑)这样子的结构。

cmd:  存放main函数入口,  这里注册各个services的路由。可以看看下面这个代码文件的这个位置。

services: 各个组件模块的。  例如httpd服务

 

例如以httpd模块来说, 它提供了很多http api来支持 influxdb的操作,例如上面提到的/write,你都能从handler.go文件里找到http路由注册入口,然后找到对应的处理函数,就能逐步梳理出这个influxdb的写入流程了。

 

 

5. influxdb集群版本

5.1 集群版本原理

官方的influxdb的集群版本是做成企业收费版,没有对外开放代码,github开源项目(https://github.com/chengshiwen/influxdb-cluster)参考如下的官方的实现来实现了一套。

 

meta nodes: 就是基于raft协议实现一套元数据的存储,包括节点成员、数据分布、账号验证信息都存储在meta节点上。

 

5.2 集群版本搭建

* 使用一个influxd-ctl的工具,add-meta来首先将3个节点组件成一个raft group。

* 然后使用add-data来讲data节点加入到这个meta group。

* 如果想知道上述这两个add操作做了啥,可以到项目里看看这个工具的操作(就是调用influxd的api进行节点操作)

* 就会在data节点的 ${HOME}/meta节点下有meta服务的节点信息

influxd-ctl add-meta influxdb-meta-01:8091
influxd-ctl add-meta influxdb-meta-02:8091
influxd-ctl add-meta influxdb-meta-03:8091
influxd-ctl add-data influxdb-data-01:8088
influxd-ctl add-data influxdb-data-02:8088
influxd-ctl show

 

5.3 写入一致性

集群版本写入可以配置写入一致性要求, 就是client 可以要求: 写入到全部节点、写入到至少2个节点、写入到任意一个节点就返回给client,这几种数据一致性的要求。

例如如果某个节点挂了,那么这个时候数据没法立即写入到相关节点。 那么这部分数据是通过hint-handoff的模块进行缓存和持久化落地到hh数据目录。这部分的代码实现主要在这个目录里,还是比较好理解的。   因为它主要就暴露2个接口: WriteShard和Empty接口。

6. 总结

本文简单讲述了influxdb的版本演进、逻辑结构、写入流程、集群原理等信息,下一步将讲解一下influxdb的读流程。整体来说 influxdb的代码还是比较易懂的,可以从具体api入手,然后看看对应的api代码实现。

influxdb源码还是比较规整的, 可以作为go学习入门挺好的一个学习项目。

 

 

文章来自个人专栏
数据中间件
4 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
2
0