4. 时序数据模型与Schema设计
时序数据平台迁移与扩容工程中,Schema 设计是决定后续写入性能、查询效率、存储成本和扩容难度的根基。时序数据模型与关系型模型最大的区别在于:它把“谁在什么时间产生了什么指标”拆成测量点(measurement)、标签(tag)、时间戳(timestamp)和字段(field)四类要素,并围绕时间维度组织存储。理解这四类要素的职责边界,是设计可迁移、可扩容 Schema 的前提。
测量点、标签、时间戳与字段的职责划分
测量点相当于关系型数据库中的“表”,但它不是按业务实体划分,而是按“一类被采集的指标集合”划分。例如 cpu_usage、disk_io、http_request 各自是一个测量点。标签是索引维度,用于过滤和分组,典型如 host、region、service、device;标签值通常是低基数、可枚举的字符串。时间戳是每条记录的主键组成部分,精度需在迁移前统一,常见为纳秒或毫秒。字段是实际被聚合和计算的数值,如 usage_user、usage_system、bytes_read,也可以是布尔或字符串,但字符串字段不宜作为高频聚合对象。
一个关键判断是:标签用于“怎么找”,字段用于“算什么”。如果把高基数、持续增长的值(如 request_id、session_id)放进标签,会导致索引膨胀、写入放大,扩容时元数据迁移量急剧上升;反之,如果把本应作为过滤维度的 region 放进字段,查询就只能全表扫描。迁移前应逐测量点审查标签基数,通常建议单测量点标签组合基数控制在百万级以内,超过则考虑拆分测量点或改用字段承载。
字段类型选择与迁移影响
字段类型直接影响压缩率和聚合精度。整型字段(int64)适合计数器类指标,如 bytes_read、request_count;浮点字段(float64)适合比率、延迟、温度等连续量。迁移时若把原本的 float 字段改成 int,会丢失小数精度;若把 int 改成 float,则压缩率下降、存储膨胀。建议在迁移前对每个字段做一次类型审计,记录原始类型、目标类型和转换规则。对于布尔状态字段,可编码为 0/1 整型,避免字符串比较开销。
时间戳精度同样需要统一。如果源端是毫秒、目标端是纳秒,写入时需乘以 1e6;反之则需截断。精度不一致会导致同一时间窗口内出现重复点或空洞,降采样结果失真。迁移脚本中应显式声明时间单位,并在写入前做一次抽样校验,确认时间戳落在预期区间内。
保留策略与降采样聚合模型
保留策略(Retention Policy)决定数据在原始精度层、降采样层和归档层各保留多久。常见做法是三层联动:原始层保留 7 天,降采样层保留 90 天,归档层保留 2 年。降采样不是简单丢弃数据,而是按固定窗口做聚合,常用聚合函数包括 avg、max、min、count、sum、p95。选择哪些函数取决于查询场景:容量趋势看 avg 和 max,告警复盘看 max 和 p95,计费统计看 sum 和 count。
降采样任务通常由定时任务或流式聚合引擎执行。以 10s 原始点聚合成 1min 为例,每个 1min 窗口包含 6 个原始点,聚合后写入降采样测量点,标签保持不变,字段变为聚合结果。迁移扩容时,降采样任务需要随分片一起迁移,否则会出现部分时间窗口缺失。建议在迁移前记录降采样任务的窗口对齐方式(如按自然分钟对齐还是按写入时间对齐),迁移后做一次窗口完整性校验。
Schema 设计检查清单
| 检查项 | 判断标准 | 常见问题 |
|---|---|---|
| 标签基数 | 单测量点标签组合基数 < 100 万 | request_id 误入标签导致索引膨胀 |
| 时间戳精度 | 全链路统一为纳秒或毫秒 | 源端毫秒、目标端纳秒未换算 |
| 字段类型 | 数值型字段占比 > 90% | 字符串字段参与聚合导致性能下降 |
| 保留策略 | 三层保留周期明确且不重叠 | 原始层与降采样层保留期倒挂 |
| 降采样窗口 | 窗口对齐方式与源端一致 | 迁移后窗口偏移导致数据空洞 |
完成上述设计后,Schema 就不再只是建表语句,而是迁移映射、扩容分片和查询优化的共同契约。下一阶段的分片与副本设计,将直接建立在这份契约之上。