特点

  • 基于时间序列,支持与时间有关的相关函数(如window()mean(),rate()等);
  • 可度量性:你可以实时对大量数据进行计算;
  • 无结构(无模式):可以是任意数量的列;
  • 支持min, max, sum, count, mean, median 等一系列函数;
  • 内置http支持,使用http读写;
  • 强大的类SQL语法;函数式语言Flux
  • 自带管理界面,方便使用


数据模型

python influxdb 数据查询 引入时间变量 influxdb 时间戳_字段


Timestamp

InfluxDB中存储的所有数据都有一个存储时间戳的_time列。在磁盘上,时间戳以纳秒格式存储。InfluxDB格式时间戳以[RFC 3339](https://tools.ietf.org/html/rfc3339)(如:2020-01-01T00:00:00.00Z)格式显示与数据关联的日期和时间。

Measurement

度量名称,字符串类型,充当标记、字段和时间戳的容器。


Fields
必需,非索引。
Field key
字段键是表示字段名称的字符串。
Field value
字段值表示关联字段的值。值的类型为string, float, integer, uInteger, boolean.
Field set
字段集是与时间戳关联的字段键值对的集合。

Tags
可选,索引。
Tag key
索引键
Tag value
索引值
Tag set
tag key 和 tag value 组成的 set 集合

Series
Series = Measurement + Tag set + Field key
Point
Point = Series + Field value + Timestamp
Bucket
所有的数据都存储在一个Bucket中。Bucket结合了Database和Retention period(每个数据点过期的时间)的概念。Bucket 属于一个organization。
Organization
一组 dashboard,task, bucket 和 users 属于一个 organization.

物理模型

Write Ahead Log (WAL)

当存储引擎收到写入请求时:

  • 在WAL文件中追加一条写入操作
  • 数据以fsync()写入磁盘
  • 更新内存中的Cache
  • 数据成功写入磁盘,返回响应

WAL文件的内容与内存中的Cache相同,其作用是为了持久化数据(防止数据丢失),当系统崩溃后可以通过WAL文件恢复还没有写入到TSM文件中的数据。

Cache

Cache是wal文件在内存中的副本。特点如下:

  • 按照 Series 组织数据并存储在其自己的时间顺序范围内
  • 存储未压缩的数据
  • InfluxDB启动时,会遍历所有的WAL文件,重新构造Cache,即使系统出现故障,也不会导致数据丢失。
  • 插入数据时,是往CacheWAL中写入数据,可以认为CacheWAL文件中的数据在内存中的缓存
  • 查询:对存储引擎的查询将Cache中的数据与TSM文件中的数据合并。查询在查询处理时对从Cache生成的数据副本执行。写数据不影响查询的结果。


Cache中的数据不是无限增长的,有一个 maxSize 参数(默认上限为25MB)用于控制当Cache中的数据占用多少内存后就会将数据写入 TSM 文件。每当 Cache 中的数据达到阀值后,会将当前的 Cache 进行一次快照,之后清空当前Cache中的内容,再创建一个新的WAL文件用于写入,剩下的WAL文件最后会被删除,快照中的数据会经过排序写入一个新的TSM文件中。

Time-Structured Merge Tree (TSM)

为了有效地压缩和存储数据,存储引擎按Series对字段值进行分组,然后按时间对这些字段值进行排序。
存储引擎使用TSM存储数据,TSM文件以列格式存储压缩的序列数据。为了提高效率,存储引擎只存储一系列值之间的差异(或增量)。
单个TSM file大小最大为2GB,用于存放数据。

Time Series Index (TSI)

一种服务机制,随着数据增长,保证一定的查询效率。每隔1秒会检查一次是否有需要压缩合并的数据。主要进行两种操作:

  • Cache中的数据大小达到阀值后,进行快照,之后转存到一个新的TSM文件中
  • 合并当前的TSM文件,将多个小的TSM文件合并成一个,使每一个文件尽量达到单个文件的最大大小,减少文件的数量,并且一些数据的删除操作也是在这个时候完成。

文件结构

python influxdb 数据查询 引入时间变量 influxdb 时间戳_字段_02

Engine path

  • /data:存储TSM文件
  • /wal:存储WAL文件

Blot Path

Boltdb数据库的存储路径,存储格式是 Go 的key-value,数据是非时间序列的,包括InfluxDB user, dashboard task等等。

Shard & Shard group

Shards

shard包含由Shard group duration定义的给定时间范围内编码压缩的时间序列数据。在指定的shard group duration内,同一 Series 的所有 Point 都存储在同一个shard中。单个shard包含多个series、磁盘上的一个或多个TSM文件,并且属于一个Shard group。

Shard group

一个shard group 属于一个 bucket,包含由shard group duration定义的特定时间范围的 series 。

Shard group duration

指定每个shard group的时间范围,并确定创建新shard group的频率

python influxdb 数据查询 引入时间变量 influxdb 时间戳_字段_03


Shard group diagram

下图表示一个4天保留时间,shard group持续时间为1天的bucket

python influxdb 数据查询 引入时间变量 influxdb 时间戳_存储引擎_04

Shard life-cycle

Shard precreation
InfluxDB shard precreation服务根据shard组持续时间为每个shard组预先创建具有未来开始和结束时间的shard。precreator服务不会为过去的时间范围预创建碎片。在回填历史数据时,InfluxDB会根据需要为过去的时间范围创建碎片,从而暂时降低写入吞吐量。
Shard writes
InfluxDB 将时间序列数据写入未压缩或 "hot" shard 。当一个 shard 长时间不被写入时,InfluxDB会压缩 shard 数据,从而产生 "cold" shard。
通常,InfluxDB会将数据写入最近的 shard group("hot" shard),但在回填历史数据时,InfluxDB 会将数据写入先解压缩的旧碎片。回填完成后,InfluxDB 重新压缩旧碎片。
Shard compaction
InfluxDB 有以下四个压缩级别:

  • L1:InfluxDB 将内存Cache中保存的所有新写入的数据刷新到磁盘
  • L2:InfluxDB 通过将 L1 产生的包含相同series的多个块组合到一个或多个新文件中的较少块中
  • L3:InfluxDB 遍历 L2 产生压缩文件块(超过一定大小),并将包含相同 series 的多个块组合到新文件中的一个块中。
  • L4:完全压缩,InfluxDB 对 L3 产生的压缩文件块进行遍历,并将包含相同 series 的多个块合并到新文件中的一个块中。

Shard deletion

InfluxDB 的 retention enforcement service 定期检查早于其存储桶保留期的 shard group。一旦 shard group 的开始时间超过bucket的保留期,InfluxDB 就会删除 shard group 以及关联的 shard 和 TSM 文件。

优化策略

  • 控制series的数量;
  • 使用批量写;
  • 使用恰当的时间粒度;
  • 存储的时候尽量对 Tag 进行排序;
  • 根据数据情况,调整shard的 duration;
  • 无关的数据写不同的 bucket;
  • 控制Tag Key与Tag Value值的大小;
  • 存储分离,将 wal 目录与 data 目录分别映射到不同的磁盘上,以减少读写操作的相互影响。

Influx CLI

Bucket

influx bucket create \
  --org dx \
  --token 2y7jSDzWL6PfafiQ1g_RrinwaI2SmgvY-Oo2AdBxkS4ULnUrgbvr1G-P05MixgBqt1pINAf3GmOa1mjBfHz39g== \
  --name newBucket

influx bucket list \
  --token 2y7jSDzWL6PfafiQ1g_RrinwaI2SmgvY-Oo2AdBxkS4ULnUrgbvr1G-P05MixgBqt1pINAf3GmOa1mjBfHz39g== \
  --org dx
  
influx bucket delete \
  --org dx \
  --token 2y7jSDzWL6PfafiQ1g_RrinwaI2SmgvY-Oo2AdBxkS4ULnUrgbvr1G-P05MixgBqt1pINAf3GmOa1mjBfHz39g== \
  --name newBucket

Write

influx write --bucket demo \
  --org dx \
  --token 2y7jSDzWL6PfafiQ1g_RrinwaI2SmgvY-Oo2AdBxkS4ULnUrgbvr1G-P05MixgBqt1pINAf3GmOa1mjBfHz39g== \
  'word_count,word=cc word_count=10'

Query

influx query \
  --org dx \
  --token 2y7jSDzWL6PfafiQ1g_RrinwaI2SmgvY-Oo2AdBxkS4ULnUrgbvr1G-P05MixgBqt1pINAf3GmOa1mjBfHz39g== \
  'from(bucket: "demo")
  |> range(start: -1d, stop: -0s)
  |> filter(fn: (r) => r["_measurement"] == "world_count")
  |> drop(columns: ["_start","_stop"])'

FluxQL

from(bucket: "demo")
  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
  |> filter(fn: (r) => r["_measurement"] == "word_count")
//   |> window(every: 5m)
//   |> mean()
//   |> duplicate(column: "_stop", as: "_time")
//   |> window(every: inf)
  |> aggregateWindow(every:5m, fn: mean, createEmpty: false)
  |> yield(name: "mean") //   |> sort(columns:["_value"])
//   |> group(columns:["_value"])
//   |> keep(columns:["_value"])
//   |> drop(columns: ["_start","_stop"])
//   |> limit(n: 3, offset: 2)
//   |> yield(name: "mean")

Delete

influx delete --bucket demo \
  --org dx \
  --token 2y7jSDzWL6PfafiQ1g_RrinwaI2SmgvY-Oo2AdBxkS4ULnUrgbvr1G-P05MixgBqt1pINAf3GmOa1mjBfHz39g== \
  --start '1970-01-01T00:00:00Z' \
  --stop $(date +"%Y-%m-%dT%H:%M:%SZ") \
  --predicate '_measurement="myMeasurement"'

InfluxDB API

通过HTTP的方式对 InfluxDB 进行管理

写入

curl --request POST "http://121.5.133.125:8086/api/v2/write?org=dx&bucket=demo&precision=s" \
  --header "Authorization: Token 2y7jSDzWL6PfafiQ1g_RrinwaI2SmgvY-Oo2AdBxkS4ULnUrgbvr1G-P05MixgBqt1pINAf3GmOa1mjBfHz39g==" \
  --data-raw "
word_count,word=dd word_count=3i 1624986861
word_count,word=dd word_count=4i 1624987862
word_count,word=dd word_count=6i 1624988863
word_count,word=dd word_count=2i 1624989864
word_count,word=ee word_count=2i 1624990865
word_count,word=ee word_count=4i 1624991866
"

查询

curl --location --request POST 'http://121.5.133.125:8086/api/v2/query?org=dx' \
--header 'Authorization: Token 2y7jSDzWL6PfafiQ1g_RrinwaI2SmgvY-Oo2AdBxkS4ULnUrgbvr1G-P05MixgBqt1pINAf3GmOa1mjBfHz39g==' \
--header 'Accept: application/csv' \
--header 'Content-type: application/vnd.flux' \
--data-raw 'from(bucket: "demo")
    |> range(start: -1d, stop: -0s)
    |> filter(fn: (r) => r["_measurement"] == "world_count")'

删除

curl --location --request POST 'http://121.5.133.125:8086/api/v2/delete/?org=dx&bucket=demo' \
--header 'Authorization: Token 2y7jSDzWL6PfafiQ1g_RrinwaI2SmgvY-Oo2AdBxkS4ULnUrgbvr1G-P05MixgBqt1pINAf3GmOa1mjBfHz39g==' \
--header 'Content-Type: application/json' \
--data-raw '{
    "start": "2021-06-29T00:00:00Z",
    "stop": "2021-07-01T00:00:00Z",
    "predicate": "_measurement=word_count AND word=cc"
  }'

Java API

依赖

<dependency>
  <groupId>com.influxdb</groupId>
  <artifactId>influxdb-client-java</artifactId>
  <version>2.3.0</version>
</dependency>

应用

public class BaseInfluxDBTest {

    protected static InfluxDBClient influxDBClient;

    private static char[] token = "2y7jSDzWL6PfafiQ1g_RrinwaI2SmgvY-Oo2AdBxkS4ULnUrgbvr1G-P05MixgBqt1pINAf3GmOa1mjBfHz39g==".toCharArray();

    @BeforeAll
    static void open() {
        influxDBClient = InfluxDBClientFactory.create("http://121.5.133.125:8086", token, "dx", "demo");
    }

    @AfterAll
    static void close() {
        influxDBClient.close();
    }


}

Telegraf

Telegraf是一个插件驱动的服务器代理,用于从数据库、系统和物联网传感器收集和发送度量和事件。Telegraf是用Go编写的,可以编译成一个没有外部依赖关系的二进制文件,并且需要非常小的内存占用。

python influxdb 数据查询 引入时间变量 influxdb 时间戳_数据_05


应用:

  • 数据库:连接到MongoDB、MySQL、Redis等数据源,收集和发送度量数据。
  • 系统:从云平台、容器和编排器的现代堆栈中收集度量。
  • 物联网传感器:从物联网传感器和设备收集关键状态数据(压力水平、温度水平等)。