3. InfluxDB入门:安装配置、核心概念与基础CRUD操作
3.1 为什么选InfluxDB?
做电力数据存储,我第一个想到的就是InfluxDB。为什么?
你想想看,电力系统里全是时序数据——电压、电流、功率、频率,每秒都可能产生成千上万个采样点。传统的关系型数据库存这些数据,读写性能很快就扛不住了。InfluxDB就是专门为这种场景设计的。
我个人习惯把InfluxDB比作「为时间而生的数据库」。它把时间戳作为核心索引,写入和查询都围绕时间轴展开。这在电力数据回放场景下,简直是天作之合。
3.2 安装配置:三分钟跑起来
安装其实很简单。我一般在Linux服务器上部署,Windows和Mac也支持。
方式一:直接安装(Linux)
# Ubuntu/Debian
wget -q https://repos.influxdata.com/influxdata-archive_compat.key
echo '393e8779c89ac8d958f81f942f9ad7fb82a25e133faddaf92e15b16e6ac9ce4c influxdata-archive_compat.key' | sha256sum -c && cat influxdata-archive_compat.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/influxdata-archive_compat.gpg > /dev/null
echo 'deb [signed-by=/etc/apt/trusted.gpg.d/influxdata-archive_compat.gpg] https://repos.influxdata.com/debian stable main' | sudo tee /etc/apt/sources.list.d/influxdata.list
sudo apt-get update && sudo apt-get install influxdb2
# 启动服务
sudo systemctl start influxdb
sudo systemctl enable influxdb
方式二:Docker部署(我推荐)
我在项目中经常用Docker,环境隔离,迁移方便。
docker run -d \
--name influxdb \
-p 8086:8086 \
-v influxdb-data:/var/lib/influxdb2 \
influxdb:2.7
启动后,浏览器访问 http://localhost:8086,设置用户名、密码、组织名和初始Bucket(相当于数据库)。
3.3 核心概念:Measurement、Tag、Field
这三个概念是InfluxDB的灵魂。搞懂了它们,你就掌握了80%的InfluxDB。
3.3.1 Measurement(测量)
说白了,Measurement就是一张「表」。但它比关系型数据库的表灵活得多——不需要预先定义字段结构。
在电力场景中,我通常这样设计:
power_meter— 电表数据transformer_status— 变压器状态line_current— 线路电流
3.3.2 Tag(标签)
Tag是被索引的字段。用来做筛选和分组。
Tag的特点:
- 必须是字符串类型
- 会被自动索引,查询快
- 适合存「元数据」——设备ID、区域、类型等
举个例子:
power_meter,device_id=PM-001,region=华东,phase=A voltage=220.5 1700000000
这里的 device_id、region、phase 就是Tag。
3.3.3 Field(字段)
Field就是实际的数据值。可以是浮点数、整数、字符串、布尔值。
Field不会被自动索引,所以查询时如果按Field过滤,性能会差一些。
power_meter,device_id=PM-001 voltage=220.5,current=5.2,power=1146.6 1700000000
这里的 voltage、current、power 就是Field。
3.3.4 时间戳(Timestamp)
每条数据都必须带时间戳。默认是纳秒精度。
嗯,这里要注意:InfluxDB的时间戳精度可以配置,但一旦写入就不能改了。我建议统一用纳秒,避免后续数据对齐出问题。
3.4 基础CRUD操作
InfluxDB使用类SQL的查询语言——Flux(2.x版本)或InfluxQL。我主要用Flux,更灵活。
3.4.1 写入数据(Create)
行协议格式:
<measurement>[,tag_key=tag_value...] field_key=field_value[,field_key=field_value...] [timestamp]
示例:写入一条电表数据
# 通过CLI写入
influx write \
--bucket power_data \
--precision s \
"power_meter,device_id=PM-001,region=华东,phase=A voltage=220.5,current=5.2,power=1146.6 1700000000"
# 通过API写入
curl -X POST "http://localhost:8086/api/v2/write?bucket=power_data&precision=s" \
--header "Authorization: Token YOUR_TOKEN" \
--data-binary 'power_meter,device_id=PM-001,region=华东,phase=A voltage=220.5,current=5.2,power=1146.6 1700000000'
3.4.2 查询数据(Read)
Flux查询示例:
from(bucket: "power_data")
|> range(start: -1h)
|> filter(fn: (r) => r._measurement == "power_meter" and r.device_id == "PM-001")
|> filter(fn: (r) => r._field == "voltage" or r._field == "current")
|> aggregateWindow(every: 1m, fn: mean)
|> yield(name: "mean_values")
这段代码的意思是:从 power_data 桶中,查过去1小时内设备PM-001的电压和电流,按1分钟窗口取平均值。
InfluxQL查询(兼容模式):
SELECT mean("voltage") AS "avg_voltage"
FROM "power_data"."autogen"."power_meter"
WHERE "device_id" = 'PM-001'
AND time >= now() - 1h
GROUP BY time(1m)
我个人习惯用Flux,虽然语法稍微复杂点,但处理复杂的时间窗口、数据变换时,Flux强大得多。
3.4.3 更新数据(Update)
InfluxDB不支持直接更新已写入的数据。这是时序数据库的特点——数据一旦写入,就是不可变的。
那如果写错了怎么办?
- 方法一: 删除错误数据,重新写入
- 方法二: 写入一条新数据覆盖(查询时取最新值)
# 删除指定时间范围内的数据
influx delete \
--bucket power_data \
--start 2024-01-01T00:00:00Z \
--stop 2024-01-01T01:00:00Z \
--predicate '_measurement="power_meter" AND device_id="PM-001"'
3.4.4 删除数据(Delete)
删除操作要谨慎。InfluxDB的删除是按时间范围和标签谓词来做的。
# 通过API删除
curl -X POST "http://localhost:8086/api/v2/delete?bucket=power_data" \
--header "Authorization: Token YOUR_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"start": "2024-01-01T00:00:00Z",
"stop": "2024-01-02T00:00:00Z",
"predicate": "_measurement=\"power_meter\" AND region=\"华东\""
}'
注意:删除操作不能指定Field,只能按Measurement和Tag来删。这是InfluxDB的设计限制。
3.5 实战:电力数据写入与查询
最后,我分享一个实际项目中用到的模式。
场景: 变电站每台变压器每5秒上报一次三相电压、电流数据。
数据模型设计:
transformer_data,station_id=ST-001,transformer_id=TF-01,phase=A \
voltage=110.2,current=256.3,temperature=45.6 1700000000
transformer_data,station_id=ST-001,transformer_id=TF-01,phase=B \
voltage=109.8,current=254.1,temperature=44.9 1700000000
transformer_data,station_id=ST-001,transformer_id=TF-01,phase=C \
voltage=110.5,current=257.8,temperature=45.2 1700000000
查询:最近10分钟三相电压平均值
from(bucket: "power_data")
|> range(start: -10m)
|> filter(fn: (r) => r._measurement == "transformer_data"
and r.station_id == "ST-001"
and r.transformer_id == "TF-01")
|> filter(fn: (r) => r._field == "voltage")
|> group(columns: ["phase"])
|> mean()
|> yield(name: "avg_voltage_by_phase")
你看,用Tag来区分相位,查询时按phase分组,就能轻松得到三相各自的平均值。这就是InfluxDB的设计哲学——把筛选条件放Tag,把数值放Field。
好了,这一章就到这里。下一章我们深入聊聊InfluxDB的存储引擎和保留策略,看看它是怎么做到「秒级写入百万点」的。