ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

05-数据过期与冷热分离:让存储成本不再失控

05-数据过期与冷热分离:让存储成本不再失控 数据过期与冷热分离让存储成本不再失控大家好我是黒漂技术佬。前面几篇我们聊了怎么往 InfluxDB 里写数据、怎么聚合查询但有个现实问题一直绕不过去——数据越攒越多磁盘怎么办这篇就来解决这个甜蜜的烦恼。一、时序数据为什么要过期先算笔账。一台无人售货柜每5秒上报一次数据假设有6个 field温度、湿度、电流、电压、功率、开门次数1000台设备一天就产生1000台 × 6字段 × (86400秒 ÷ 5秒) 约1.04亿条/天一条记录算100字节一天就是10GB。一个月300GB一年3.6TB。这还是1000台设备的规模要是5000台呢但仔细想想这些数据的价值是随时间急剧衰减的最近7天的原始数据运维要排查昨天那台柜子为什么报了温度告警必须看秒级精度最近30天业务方看趋势分钟级聚合就够了原始数据基本没人碰1年前的数据除了年底做年度报告谁会去翻一年前的温度曲线所以核心思路就一句话让数据在该消失的时候消失该降精度的时候降精度。一直堆着原始数据既费钱又拖慢查询。二、InfluxDB 保留策略Retention Policy什么是保留策略保留策略Retention Policy简称 RP是 InfluxDB 用来管理数据生命周期的机制。简单说你告诉数据库这个 bucket 里的数据保留多久到期后数据库自动删除不需要你写定时任务去DELETE。在 InfluxDB 2.x 中保留时长是绑定在 Bucket 上的。创建 Bucket 时指定即可。创建带保留时长的 Bucket通过 InfluxDB UI 创建时直接填写保留时长Bucket名称: cabinet_raw 保留时长: 7d通过命令行influx CLI创建# 创建保留7天的Bucketinflux bucket create\--namecabinet_raw\--retention7d\--orgyour-org# 创建保留90天的Bucketinflux bucket create\--namecabinet_30d\--retention90d\--orgyour-org# 创建保留1年的Bucketinflux bucket create\--namecabinet_1y\--retention365d\--orgyour-org通过 API 创建curl-XPOSThttp://localhost:8086/api/v2/buckets\-HAuthorization: Token YOUR_TOKEN\-HContent-Type: application/json\-d{ name: cabinet_raw, retentionRules: [ { type: expire, everySeconds: 604800 } ], orgID: YOUR_ORG_ID }everySeconds: 604800就是7天7 × 24 × 3600。创建完成后InfluxDB 后台会自动清理超过7天的数据。修改已有 Bucket 的保留时长业务跑着跑着发现7天不够用想改成30天没问题influx bucket update\--idBUCKET_ID\--retention30d注意把保留时长从7天改到30天后之前已经超过7天的数据并不会复活回来——已经被删的就是删了。但从这一刻起新写入的数据会保留30天。多级保留策略实际项目里我们不会只用一个 Bucket。聪明的做法是按数据精度建多个 Bucket每个有不同的保留时长Bucket数据精度保留时长用途cabinet_raw原始5秒7天短期故障排查cabinet_10m10分钟聚合90天月度趋势分析cabinet_1h1小时聚合1年年度报表这三种 Bucket 的存储量差异巨大。同样是一台设备一天的数据cabinet_raw17280条cabinet_10m144条缩了120倍cabinet_1h24条缩了720倍一个1年数据量的 Bucket存储成本可能只有原始数据的千分之一。这就是多级保留策略的威力。三、冷热数据分离保留策略解决的是自动清理的问题但有些数据你不想删只是不想让它占用昂贵的 InfluxDB 存储。这就需要冷热分离。什么是冷热数据热数据最近N天的数据查询频繁、要求毫秒级响应。放在 InfluxDB 里享受高性能查询冷数据历史归档数据偶尔查一次响应慢点无所谓。导出到 MySQL 或文件腾出 InfluxDB 空间典型的冷热边界是30天或90天具体看业务需求。冷数据导出方案方案一导出到 MySQL适合需要结构化查询的场景比如查某台设备三个月前的日报记录。数据流InfluxDB → 定时任务查询聚合 → 写入 MySQL 归档表// 伪代码思路// 1. 每天凌晨1点执行// 2. 从InfluxDB查询昨天的日报数据聚合后// 3. 写入MySQL的cabinet_daily_report表// MySQL归档表结构// CREATE TABLE cabinet_daily_report (// id BIGINT PRIMARY KEY AUTO_INCREMENT,// device_id VARCHAR(50),// report_date DATE,// avg_temp DECIMAL(5,2),// max_temp DECIMAL(5,2),// min_temp DECIMAL(5,2),// total_power DECIMAL(10,3),// door_open_count INT,// create_time DATETIME,// INDEX idx_device_date (device_id, report_date)// );方案二导出到 CSV / Parquet 文件适合超长期归档成本低、格式通用。Parquet 是列式存储格式压缩率高适合大数据分析工具Spark、Pandas后续处理。# 用influx CLI导出CSVinflux query\from(bucket: cabinet_10m) | range(start: -1d) | filter(fn: (r) r[_measurement] cabinet_metrics_10m) | filter(fn: (r) r[_field] temp) | mean()\--orgyour-org\--file-format csv\/archive/cabinet_temp_$(date%Y%m%d).csv冷热分离的架构图设备数据上报 │ ▼ ┌──────────┐ 保留7天 ┌──────────────┐ │ 热数据 │ ◄──────────── │ cabinet_raw │ ← 原始5秒精度 │ (InfluxDB)│ └──────────────┘ └──────────┘ │ │ Task降采样每10分钟 ▼ ┌──────────────┐ 保留90天 │ cabinet_10m │ ← 10分钟聚合 └──────────────┘ │ │ Task降采样每小时 ▼ ┌──────────────┐ 保留1年 │ cabinet_1h │ ← 1小时聚合 └──────────────┘ │ │ 定时导出每天 ▼ ┌──────────────┐ │ MySQL / CSV │ ← 永久归档 └──────────────┘热数据用 InfluxDB 的速度冷数据用 MySQL/文件的便宜各取所长。四、数据降采样实战降采样Downsampling就是把高精度数据聚合成低精度数据。前面04篇讲过aggregateWindow()的用法这里重点讲怎么用 Task 实现自动化。Task 自动降采样InfluxDB 2.x 的 Task 相当于定时任务按设定的时间间隔自动执行 Flux 脚本。我们用它在 Bucket 之间搬运聚合数据。Task 1原始数据 → 10分钟聚合option task { name: downsample_5s_to_10m, every: 10m, offset: 1m } from(bucket: cabinet_raw) | range(start: -11m, stop: -1m) | filter(fn: (r) r[_measurement] cabinet_metrics) | group(columns: [device_id, _field]) | aggregateWindow(every: 10m, fn: mean, createEmpty: false) | set(key: _measurement, value: cabinet_metrics_10m) | to(bucket: cabinet_10m, org: your-org)逐行解读every: 10m每10分钟执行一次offset: 1m延迟1分钟执行避免数据还没写完就聚合导致最后一个窗口数据不全range(start: -11m, stop: -1m)取最近11分钟到1分钟前的数据和every对齐保证窗口完整group(columns: [device_id, _field])按设备和字段分组各自独立聚合aggregateWindow(every: 10m, fn: mean)10分钟窗口取平均set()改个 measurement 名字区分原始和聚合to()写入目标 BucketTask 210分钟聚合 → 1小时聚合option task { name: downsample_10m_to_1h, every: 1h, offset: 5m } from(bucket: cabinet_10m) | range(start: -65m, stop: -5m) | filter(fn: (r) r[_measurement] cabinet_metrics_10m) | group(columns: [device_id, _field]) | aggregateWindow(every: 1h, fn: mean, createEmpty: false) | set(key: _measurement, value: cabinet_metrics_1h) | to(bucket: cabinet_1h, org: your-org)注意这里的数据源不是cabinet_raw而是cabinet_10m——用聚合后的数据再聚合而不是拿原始数据直接算。这样计算量更小。Task 管理命令# 查看所有Taskinflux task list--orgyour-org# 查看某个Task的运行记录influx task logfind--task-id TASK_ID--orgyour-org# 手动触发一次Taskinflux task run create --task-id TASK_ID--orgyour-org# 暂停Taskinflux task update--idTASK_ID--statusinactive# 恢复Taskinflux task update--idTASK_ID--statusactive五、存储空间监控光配了保留策略还不够你得盯着磁盘防止意外情况把空间吃满。查看 InfluxDB 磁盘占用# 查看InfluxDB数据目录大小du-sh/var/lib/influxdb2/engine/data# 按Bucket查看需通过APIcurl-shttp://localhost:8086/api/v2/buckets\-HAuthorization: Token YOUR_TOKEN|jq.buckets[] | {name: .name, retention: .retentionRules[0].everySeconds}查询数据量统计用 Flux 统计各 measurement 的数据点数量判断哪个 measurement 在疯涨// 统计过去1小时各measurement的数据点数量 from(bucket: cabinet_raw) | range(start: -1h) | group(columns: [_measurement]) | count() | group() | sort(columns: [_value], desc: true)磁盘告警建议建议设置以下监控告警磁盘使用率 70%发告警检查是否有异常写入磁盘使用率 85%紧急告警可能需要扩容或缩短保留时长日增数据量异常波动 50%可能是设备端 bug 导致疯狂重传六、无人售货柜数据保留方案最后给一个完整的无人售货柜数据保留方案你可以直接参考落地三级 Bucket 设计Bucket精度保留时长写入方式查询场景cabinet_raw5秒7天设备直接写入故障排查、实时监控cabinet_10m10分钟90天Task降采样月度趋势、运营分析cabinet_1h1小时365天Task降采样年度报表、同比对比日报归档到 MySQL每天凌晨1点Task 把昨天的日报数据日均温度、最高温度、总耗电、开门次数聚合后写入 MySQL 的cabinet_daily_report表永久保存。这样做的好处InfluxDB 只管时序数据不背历史包袱查询始终快MySQL 管业务报表和订单、设备台账等业务数据放一起方便联合查询成本可控InfluxDB 的存储量被限制在7天原始 90天聚合 365天小时聚合总量可以预估存储容量预估1000台设备每台6个 fieldcabinet_raw7天约70GBcabinet_10m90天约5GB缩小14倍cabinet_1h365天约2GB缩小420倍MySQL日报永久1000台 × 365天 × 100字节 ≈ 36MB/年总计约77GB一块500GB的 SSD 轻松搞定。如果不做降采样和过期一年就是3.6TB——差距50倍。数据过期和冷热分离不是可选项是时序数据系统的必修课。配置好保留策略和降采样 Task你的 InfluxDB 就能长期稳定运行而不会把磁盘吃满。
返回列表