4. 数据存储层部署:时序数据库(InfluxDB)安装与配置、关系型数据库(PostgreSQL)设计、数据分片与备份策略

各位同事,这一章我们聊聊数据存储层。说白了,就是风场那些海量数据到底该往哪儿放、怎么放、怎么保证不丢。

我在多个风场项目里摸爬滚打过后,最大的体会是:存储层设计得好,后面运维能省一半的力气。你想想看,一个风场几百台风机,每台风机几十个测点,每秒都在产生数据。如果存储层没规划好,三个月后查询就慢得像蜗牛爬。

核心思路:时序数据(风速、功率、振动)走 InfluxDB,结构化业务数据(设备台账、运维记录、用户权限)走 PostgreSQL。两者各司其职,互不干扰。

4.1 时序数据库 InfluxDB 安装与配置

InfluxDB 这东西,说白了就是为时序数据量身定做的。我最早用的时候还是 1.x 版本,现在 2.x 已经非常成熟了。

4.1.1 安装步骤

我个人习惯用 Docker 部署,干净利落,升级也方便。当然,生产环境建议用二进制包安装,性能更好。

# Docker 方式(推荐开发测试用)
docker run -d \
  --name influxdb \
  -p 8086:8086 \
  -v /data/influxdb:/var/lib/influxdb2 \
  -v /data/influxdb-config:/etc/influxdb2 \
  influxdb:2.7

# 二进制方式(生产环境推荐)
wget https://dl.influxdata.com/influxdb/releases/influxdb2-2.7.0-linux-amd64.tar.gz
tar xzf influxdb2-2.7.0-linux-amd64.tar.gz
cd influxdb2-2.7.0-linux-amd64
./influxd --reporting-disabled &

小技巧:启动时加上 --reporting-disabled 参数,可以关闭匿名数据上报。我在客户现场部署时,安全审计要求必须关掉这个。

4.1.2 初始化配置

安装完成后,需要做初始化。这里我踩过一个坑——bucket 的 retention policy 一定要提前想好

# 通过 CLI 初始化
influx setup \
  --username admin \
  --password YourStrongPassword \
  --org windfarm \
  --bucket wind_turbine_data \
  --retention 90d \
  --force

# 创建完成后,生成 API Token
influx auth create \
  --org windfarm \
  --all-access

嗯,这里要注意:原始采样数据我建议保留 90 天。为什么?因为风机的振动分析、功率曲线诊断,通常需要回溯最近三个月的数据。超过三个月的,可以降采样后存到另一个 bucket 里。

4.1.3 关键配置参数

参数 推荐值 说明
storage-cache-max-memory-size 512m 缓存最大内存,写密集场景可以调大
storage-wal-max-write-size 10m WAL 写入阈值,避免频繁刷盘
query-concurrency 20 并发查询数,根据 CPU 核心数调整
storage-series-id-set-cache-size 100 序列缓存,tag 维度多时需要加大

我曾经在一个 200 台风机的项目里,默认配置下查询经常超时。后来把 query-concurrency 从 10 调到 20,再把 storage-cache-max-memory-size 调到 1G,问题就解决了。

4.2 关系型数据库 PostgreSQL 设计

PostgreSQL 这边,主要存的是「不随时间变化」或者「变化很慢」的数据。比如风机台账、备件信息、运维工单、用户权限。

4.2.1 核心表结构设计

我一般会设计这么几张核心表:

-- 风机基础信息表
CREATE TABLE wind_turbines (
    turbine_id SERIAL PRIMARY KEY,
    turbine_code VARCHAR(32) UNIQUE NOT NULL,  -- 风机编码,如 WT-001
    model VARCHAR(64),                          -- 机型
    rated_power DECIMAL(10,2),                  -- 额定功率(MW)
    longitude DECIMAL(10,6),                    -- 经度
    latitude DECIMAL(10,6),                     -- 纬度
    commission_date DATE,                       -- 并网日期
    status VARCHAR(16) DEFAULT 'online',        -- 状态
    created_at TIMESTAMP DEFAULT NOW()
);

-- 测点配置表
CREATE TABLE measurement_points (
    point_id SERIAL PRIMARY KEY,
    turbine_id INT REFERENCES wind_turbines(turbine_id),
    point_code VARCHAR(64) NOT NULL,            -- 测点编码,如 WT-001-WS
    point_name VARCHAR(128),                    -- 测点名称,如 风速
    unit VARCHAR(16),                           -- 单位,如 m/s
    data_type VARCHAR(16),                      -- 数据类型,float/int/bool
    upper_limit DECIMAL(10,2),                  -- 报警上限
    lower_limit DECIMAL(10,2),                  -- 报警下限
    is_active BOOLEAN DEFAULT TRUE
);

-- 运维工单表
CREATE TABLE maintenance_orders (
    order_id SERIAL PRIMARY KEY,
    turbine_id INT REFERENCES wind_turbines(turbine_id),
    order_type VARCHAR(32),                     -- 工单类型:巡检/维修/保养
    description TEXT,
    assigned_to VARCHAR(64),
    priority INT DEFAULT 3,                     -- 优先级 1-5
    status VARCHAR(16) DEFAULT 'pending',       -- pending/in_progress/completed
    created_at TIMESTAMP DEFAULT NOW(),
    completed_at TIMESTAMP
);

注意:风机编码 turbine_code 一定要用唯一约束。我见过一个项目,因为编码重复导致数据关联全部错乱,最后花了三天才把数据清洗干净。

4.2.2 索引设计策略

查询性能的关键在索引。我的经验是:

  • 外键字段必须建索引:比如 turbine_id,因为 JOIN 操作频繁
  • 时间字段建索引:比如 created_at,按时间范围查询很常见
  • 状态字段考虑部分索引:比如只对 status = 'pending' 的工单建索引
CREATE INDEX idx_turbine_status ON wind_turbines(status);
CREATE INDEX idx_points_turbine ON measurement_points(turbine_id);
CREATE INDEX idx_orders_status ON maintenance_orders(status) WHERE status = 'pending';

4.3 数据分片与备份策略

这部分是真正的「避坑指南」。我见过太多风场因为没做好分片和备份,数据丢了之后追悔莫及。

4.3.1 InfluxDB 数据分片

InfluxDB 自带分片机制,按时间自动切分。但默认的 shard duration 不一定适合你的场景。

数据写入频率 推荐 Shard Duration 说明
高频率(每秒 > 10000 点) 1h 减少单个 shard 数据量,提高写入性能
中频率(每秒 1000-10000 点) 6h 平衡写入和查询性能
低频率(每秒 < 1000 点) 24h 减少 shard 数量,简化管理
# 创建 bucket 时指定 shard duration
influx bucket create \
  --name wind_turbine_data \
  --org windfarm \
  --retention 90d \
  --shard-group-duration 6h

为什么会这样?你想想看,如果每秒写入 5 万个数据点,shard 设成 24 小时,一个 shard 里就有 4 亿多条记录。查询时扫描这么大一个 shard,不慢才怪。

4.3.2 PostgreSQL 分表策略

PostgreSQL 这边,我建议按时间分表。比如运维工单,按月份分表:

-- 创建主表
CREATE TABLE maintenance_orders (
    order_id SERIAL,
    turbine_id INT,
    created_at TIMESTAMP DEFAULT NOW()
) PARTITION BY RANGE (created_at);

-- 创建分区
CREATE TABLE maintenance_orders_2024_01 PARTITION OF maintenance_orders
    FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');
CREATE TABLE maintenance_orders_2024_02 PARTITION OF maintenance_orders
    FOR VALUES FROM ('2024-02-01') TO ('2024-03-01');
-- 以此类推...

经验之谈:分区表记得定期创建新分区。我写了个 cron 脚本,每月 1 号自动创建下个月的分区。这样就不会出现数据写不进去的尴尬。

4.3.3 备份策略

备份这件事,我吃过亏。以前有个项目,硬盘坏了才发现备份文件也坏了——因为备份和源数据在同一个磁盘阵列上。

我的建议是:

  • InfluxDB 备份:用 influx backup 命令,备份到独立的 NAS 或对象存储
  • PostgreSQL 备份:用 pg_dump 做逻辑备份,同时用 pg_basebackup 做物理备份
  • 备份频率:全量备份每周一次,增量备份每天一次
  • 异地容灾:至少保留一份备份在异地机房或云上
# InfluxDB 全量备份
influx backup /backup/influxdb/$(date +%Y%m%d) --org windfarm

# PostgreSQL 逻辑备份
pg_dump -U postgres -d windfarm_db -F c -f /backup/pgsql/$(date +%Y%m%d).dump

# 恢复命令
influx restore /backup/influxdb/20240101 --org windfarm
pg_restore -U postgres -d windfarm_db /backup/pgsql/20240101.dump

警告:备份一定要定期做恢复演练!我见过太多人备份了三年,恢复时才发现文件损坏。每个月抽一天,在测试环境做一次完整恢复,这钱花得值。

4.4 本章知识体系

下面这张图,是我对数据存储层整体架构的理解。你可以把它贴在工位上,部署时对照着来。

数据存储层架构总览 数据源层 风机SCADA数据 | 振动传感器 | 气象站 | 电气参数 数据接入层 Telegraf 采集 | MQTT 网关 | 数据清洗与格式转换 时序数据库 InfluxDB 存储:风速、功率、振动、温度 分片策略:按时间 shard,6h/片 保留策略:原始数据 90天,降采样 1年 关系型数据库 PostgreSQL 存储:设备台账、运维工单、用户权限 分表策略:按月份 RANGE 分区 索引策略:外键 + 时间 + 部分索引 备份与容灾层 全量备份(每周) | 增量备份(每天) | 异地容灾 | 恢复演练(每月)

这张图把整个数据存储层的脉络理清楚了。从上到下,数据从风机流过来,经过接入层清洗,然后兵分两路——时序数据进 InfluxDB,结构化数据进 PostgreSQL。最下面是备份层,兜底保障。

好了,数据存储层就聊到这儿。记住一句话:存储设计是地基,地基不稳,上层再漂亮的系统也是空中楼阁


专注资料整理