一张表底下几千个分片:金仓时序数据库的超表怎么工作

运维手册里最容易出事的,常常是那种写得特别清楚的条目。

比如这一条:「每月 25 日前,执行 create_partition.sh,创建下月分区。」

它清楚、简单、写在文档第七页,然后在某个月的月初被发现漏了------写入开始报错,采集端的数据堆在缓冲区里,补数补了一整天。事后复盘的结论通常是"加个巡检",于是又多一个定时任务、一条告警规则,以及下次轮岗时要交接的一件事。

在时序场景里,这类活是常态。

一、分片为什么总是落到人头上

时序数据的特征,金仓的材料里概括得挺准:采集的设备多、指标多、频率高;数据持续流入;查询大多是某个时间段的聚合视图;超过一定时长之后数据不再有价值。四个特征对应四项工程要求------数据分片与压缩存储、高吞吐稳定支撑、场景深度优化、数据生命周期管理。

麻烦的是,在不少方案里,这四件事最后都得由人来落地。

分区要人建。 按月、按周还是按天,分区表怎么命名,提前建几个,建完了怎么校验。这些决定一旦做出来就要一直维护下去。

路由要写进应用。 数据该落到哪张分区表,查询该扫哪几张,这个逻辑如果不在数据库里,就一定在应用里。它会以工具类、以 if-else、以拼接字符串的形式散落在代码各处,并且在表结构调整时集中爆发。

跨分区查询要人拼。 查一周的数据跨了七张表,SQL 里就得有七段 UNION ALL,或者一段动态生成表名的逻辑。查询窗口一变,这段代码就得改。

过期数据要人删。 大批量 DELETE 在任何数据库里都不便宜:产生大量日志、留下大片碎片、还要跟在线写入抢 IO。很多团队最后选择"半夜删、限速删、删完再收缩",本质是拿运维时间换存储空间。

扩容要人重分布。 单机顶不住的时候,得决定按什么维度拆到多个实例,存量数据怎么搬,搬的过程中查询怎么办。

这些活单看都不难,难在没有终点。设备接入量涨一倍,分区数量涨一倍,脚本执行时间涨一倍,巡检项也涨一倍。到某个规模之后,时序库的日常运维就变成了分片管理本身。

二、超表:对上是一张表,对下是一堆 Chunk

金仓时序组件给出的答案是超表(Hypertable)。

官方文档的定义很短:超表默认以分区表形式存储组织数据,并基于 Chunk 实现自动分区;在项目中,超表普遍以「设备 ID + 时间」实现二级分区。

图里左右两块讲的是两件事。左边是单机形态:一张逻辑表,底下自动切成若干分区表。右边是分布式形态:同样是一张逻辑表,分区可以落到不同节点。

中间那条链路值得看清楚。用户先定义一张普通的时序表,把它注册 成 Hypertable;此后写入的数据经过分区自适应算法,以时间戳列作为分区键,自动落进对应的子表;每个子表各自建索引、各自落文件。

分工因此变成:应用面对的是那张逻辑表,分片是存储层自己的事。

INSERT 写的是超表,SELECT 查的也是超表。数据落在哪个 chunk、下个月的 chunk 建了没有、这次查询跨了几个 chunk 要不要合并结果------这些问题不出现在应用代码里,也不出现在运维手册第七页。

上一节列的五项活,前三项在这个模型下直接消失:分区不用人建,路由不在应用里,跨分区查询就是一条普通 SQL。

三、"自动"到底自动在哪一层

分两个维度看。

时间维度是基础。 分区键就是时间戳列。新数据到达时,如果对应时间区间的 chunk 还不存在,由分区自适应算法负责创建。没有提前量的概念,也就没有"忘了提前建"这回事。

时间加空间的组合是项目里的常态。 文档特意点明,实际项目中超表普遍做「设备 ID + 时间」的二级分区。这个组合不是为了好看:只按时间切,同一时刻所有设备的数据会挤进同一个 chunk,写入热点集中在一个分区上;加上设备维度之后,同一时刻的写入被分散到多个 chunk,吞吐才上得去。查询侧的收益也对应------查"某台设备最近一周",可以按设备和时间做两次裁剪,扫描量比只按时间切小一个量级。

生命周期这一端同样是自动的。 官方的说法是"基于分区自动删除配置的数据生命周期管理"。关键差别在于:过期数据的清理是丢掉整个分区,不是逐行 DELETE。丢分区是元数据操作,代价和数据量基本无关,不产生大量日志,也不留碎片。前面说的"半夜删、限速删、删完再收缩"这套流程,在这里没有存在的必要。

存储这一侧还有一条:文档写明数据压缩默认可达 4:1。时序数据同一列内取值高度相似,压缩比高是合理的,这个数字属于该场景的正常水平。

四、开发者看到的仍然是标准 SQL

自动分片本身不算稀奇,专用时序数据库大多都做。超表这套设计真正的分界线在另一处:它没有把用户带进一套新语言。

金仓的表述是,时序组件基于 KES 组件化扩展框架,可完整复用 KES 能力及生态,包括标准 SQL 访问接口。

具体长什么样,看官方附录里那组 TSBS 基准的 SQL 最清楚。取一台设备一小时内每分钟的 CPU 指标最大值:

sql 复制代码
SELECT time_bucket('60 seconds', time) AS minute,
       max(usage_user) AS max_usage_user
FROM cpu
WHERE tags_id IN (SELECT id FROM tags WHERE hostname IN ('host_249'))
  AND time >= '2023-08-26 14:44:01 +0000'
  AND time <  '2023-08-26 15:44:01 +0000'
GROUP BY minute
ORDER BY minute ASC;

除了 time_bucket 这个时间分桶函数,其余全是标准写法:子查询、GROUP BYORDER BY。没有 chunk 的影子,没有分区表名,也没有专有 DSL。

再看一个复杂些的,取每台设备的最后一次读数:

sql 复制代码
SELECT DISTINCT ON (t.hostname) *
FROM tags t
INNER JOIN LATERAL (
    SELECT * FROM cpu c
    WHERE c.tags_id = t.id
    ORDER BY time DESC LIMIT 1
) AS b ON true
ORDER BY t.hostname, b.time DESC;

关联、横向子查询、每组取一条,全都在 SQL 语义之内。这类写法的价值不在于语法优雅,而在于它是可迁移的技能------团队里会写 SQL 的人不需要为了时序场景再学一遍查询语言,已有的 BI 工具、报表平台、ORM 也不用为它单独适配。

表怎么设计同样留给用户。文档给了两种范式:窄表 用"设备 + 时间戳 + 度量指标名"拆分,一行记录某设备在该时间的某一个指标值,属单值模型;宽表可以用"设备 + 时间戳"拆分,一行记录该时间点的多个指标,也可以用"设备 + 度量指标名"拆分,一行记录该指标在多个时间区间的取值,都属多值模型。设备属性这类元数据作为辅助数据,可以直接放在其他表里,需要时用 JOIN 关联。

这是关系建模的常规思路。选窄表还是宽表,取决于指标是否稀疏、是否经常整行读取,而不取决于数据库支持哪一种。

五、水平扩展:分片是存储层的自由度

把分片交给存储层管,还带来一个副作用------它同时成了扩展的接口。

分布式 Hypertable 把 chunk 分布到不同节点上。对应用来说仍然是一张表,对运维来说增加的是节点,不是分区管理工作量。

官方文档里有个案例,规模足够说明问题。

场景是某省的船舶安全综合管理平台:沿海范围内 15 万艘船舶、20 万台终端的定位数据,时序数据日峰值写入 3000 万条,300 亿条定位数据参与地理查询分析。

关键问题写得很直白:新增时序数据压力和历史容量都高,写入和统计都需要横向扩展方案支撑;同时要结合海域 GIS 数据做关联查询,以提供安全管控能力,响应时延要求毫秒级。

方案是 KES 时序 + GIS + Sharding:5 节点分片提供最高 1.5 亿条/天的 1KB 数据写入;按年查询时涉及 5 个节点共 100 亿行数据,取某一范围内的船舶信息,毫秒级返回。

这个案例值得注意的不只是规模,还有它同时动用了两种数据模型。船舶的位置是空间数据,位置的变化是时序数据,业务问题("这片海域这一年里有哪些船")必须把两者关联起来才能回答。时序和 GIS 在同一套库里,这个关联就发生在库内;分开部署,它就变成一次跨系统的数据搬运。金仓对时序组件的定位里也提到这一点:可与 GIS、向量、文档等多种数据模型融合处理。

六、性能数据要分规模看

金仓给了一组基于 TSBS(Time Series Benchmark Suite)的对比,测试环境是 96 vCPU、512 GB 内存、1TB 块存储、CentOS 7.5,对比对象是 InfluxDB。这组数据值得完整看,因为它不是一边倒。

摄入端,每秒插入指标数量的比值(KES 相对 InfluxDB):

设备数量 100 4000 10 万 100 万 1000 万
每设备指标数 10 10 10 10 10
KES vs InfluxDB 90% 162% 95% 221% 267%

金仓自己给的结论也是分情况的:数据规模不大的负载(例如 100 台设备发送 10 种度量),InfluxDB 性能优于 KES;大数据规模的负载(例如 4000 台设备发送 10 种度量),KES 优于 InfluxDB。

查询端,简单查询互有优劣,差异在毫秒的一位或两位数量级;复杂查询 KES 领先 2 到 70 倍不等。差距最大的是 lastpoint 这类"取每台设备最后一次读数"的查询,在 100 设备 × 1 指标下是 4867%,400 设备 × 10 指标下到 7135%。但同一张表里也有 KES 落后的项------double rollup 的双分组查询,100 设备 × 10 指标时是 46%,400 设备 × 10 指标时是 55%。

需要说清楚的是,这是厂商自测数据,测试环境、参数和对比对象都由厂商选定,当选型参考可以,不能当独立评测。好在 TSBS 是开源基准,真要决策,拿自己的硬件和数据分布跑一遍更靠得住。

七、剩下的运维项去哪了

分片自动了,别的事情并没有自动消失,只是收进了同一套体系。

摄入这一端支持 telegraf 采集代理接入,工业级传输协议覆盖 OPC-UA、modbus、mqtt、sql、http、Websocket 等,终端设备、芯片、日志、程序、网络的数据可以直接进库,再往上接监控分析平台。

高可用沿用 KES 的集群能力:基于物理日志的全同步复制,数据不丢失。同步模式下 RPO 为 0,RTO 默认 30 秒,支持并行回放并可配置更小值;异步模式下 RTO 依赖人工介入,RPO 通常是故障转移期间几秒或更短,取决于备份策略。备节点支持只读连接,驱动层做智能负载均衡。选主用增强型一致性协议避免脑裂,节点故障恢复后自动回归集群。

这些和分片管理是两码事,但它们和时序数据共用同一套备份、监控、权限和审计。这意味着时序数据不需要一份单独的容灾预案,也不需要在安全评审时单独走一遍流程。

八、回到那个脚本

「每月 25 日前执行建分区脚本」这条运维条目,在超表这套设计里不存在。不是有人替你执行了,是这件事从模型里被拿掉了------分区的创建是写入路径的一部分,由算法在数据到达时完成。

同理消失的还有:提前量的取舍、分区命名规范、跨分区查询的 UNION ALL、过期数据的删除窗口、扩容时的数据重分布方案。

留下的是一张表、一套 SQL、一组节点。

值不值得为此换一套底座,要看你现在有多少张这样的表、多少个这样的脚本,以及上一次分区没建成是什么时候。

相关推荐
whcyhhh1 小时前
头歌实践教学平台:数据科学与大数据技术导论(七上)
大数据·数据库·python
夕除2 小时前
redis--007
数据库·分布式
润乾软件2 小时前
CodeBuddy+SQLazy 编写复杂 SQL 详解
数据库·sql·codebuddy·sqlazy
360智汇云2 小时前
MySQL-DTS数据同步工具:告别手动拼方案,迁移同步一站完成
数据库·mysql
东方护航数据恢复(深圳)2 小时前
国产信创数据库(达梦DM8/人大金仓)损坏恢复技术:从DMF文件解析到数据字典重建
大数据·数据库
这个DBA有点耶2 小时前
GaussDB和金仓KingbaseES本质差异:技术路线、Oracle兼容度、适用场景全解析
数据库·oracle·架构
LINgZone23 小时前
系统架构与分支规范
java·数据库·架构
这个DBA有点耶3 小时前
SQL优化进阶:读懂“索引下推”,告别回表噩梦
数据库·sql·性能优化
发量惊人的中年网工3 小时前
如何验证DDoS高防真的生效?从源站隐藏到正常访问的完整验收方法
运维·网络·数据库·ddos