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

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,即使系统出现故障,也不会导致数据丢失。 - 插入数据时,是往
Cache与WAL中写入数据,可以认为Cache是WAL文件中的数据在内存中的缓存 - 查询:对存储引擎的查询将
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文件合并成一个,使每一个文件尽量达到单个文件的最大大小,减少文件的数量,并且一些数据的删除操作也是在这个时候完成。
文件结构

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的频率

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

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编写的,可以编译成一个没有外部依赖关系的二进制文件,并且需要非常小的内存占用。

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

浙公网安备 33010602011771号