告别手工分表:金仓时序数据库超表架构落地的一次实战复盘

告别手工分表:金仓时序数据库超表架构落地的一次实战复盘 一、金仓时序数据库超表架构难在哪先撂个结论手工分表这套办法毛病不在“分”上在于分完之后所有的活儿都得你自己干。做过时序数据的人应该都懂。按月建表嘛xxx_202501、xxx_202502一路往下排。写入靠应用层拼表名做路由查跨月的数据就 UNION ALL 一串。量小的时候是真没毛病甚至可以说还挺优雅。可数据一上来麻烦就开始一个接一个往外蹦。最先绷不住的往往是分区规则。它散落在代码里啊建表靠定时任务路由逻辑埋在应用里头。新同事不知道有这套约定改查询忘了带月份路由一条 SQL 直接扫当月大表。这种事几乎每个团队都出过出一次记一辈子。然后是跨月查询。UNION ALL 完再聚合你自己琢磨琢磨各表上的索引不就白建了嘛。月份跨得越多越慢没有例外。冷热数据还混着放。三个月前的明细除了出报表那天谁碰它啊可它偏偏和今天的热数据躺同一块盘上磁盘告警三天两头来报到。删又不敢删鬼知道哪张报表哪天要用。到期删旧数据这事儿靠人惦记忘了就堆着堆着堆着就成了谁也不敢动的历史包袱。想扩容就剩换更贵的服务器一条道账单蹭蹭涨。这些麻烦摊开来看根子其实就一个问题分区这件事到底归谁管手工分表时代它归应用管所以桩桩件件都得人扛。金仓的超表Hypertable治的就是这个。它把分区的活儿整个下沉到数据库里头去了。数据进来按时间自动切成一个个数据块Chunk每块只管一段时间的再叠个空间维度比如按点位 ID 哈希把高并发写入摊开。应用这边看到啥从头到尾就一张monitor_point_dataINSERT 该咋写咋写。查半年的数据也是一条普普通通的 SQL跟你当前时间区间没关系的块数据库自己就不碰了。两种模式摆一块儿对比下对比项手工分表金仓超表分区谁管应用建表定时任务规则散在代码里数据库自己按时间空间切 Chunk跨时段查询多表 UNION ALL索引废掉一条普通 SQL没关的块直接不碰写入路由应用按时间拼表名不存在这个环节直接插老数据治理手工 DROP忘了就堆着到期自动按块删以后扩容堆硬件烧钱可以往分布式超表走SQL 兼容-标准 SQLBI 工具直连靠 SQL 吃饭的团队最后一行搞不好才是最香的。报表工具、BI 看板、备份脚本、监控探针、权限体系全能接着用不用为时序能力单独搭一条工具链。人就那么几个的小团队这点比啥跑分都实在。不过丑话说前头超表只是把复杂度从应用层挪到了数据库层它可没消失。块间隔、压缩、保留策略、连续聚合这套新机制各有各的坑坑跟坑之间还会互相影响。下面按落地的顺序一个一个说。目录一、金仓时序数据库超表架构难在哪二、建表三、第一个坑块间隔四、压缩和保留五、第二个坑刷新窗口和保留策略会互相咬六、几句经验二、建表先建张普通表就你平时写的那种一点特殊语法都没有CREATETABLEmonitor_point_data(timeTIMESTAMPTZNOTNULL,point_idINTEGERNOTNULL,metricTEXTNOTNULL,valueDOUBLEPRECISION,qualitySMALLINT);-- 转为超表时间列做主分区point_id 哈希做空间分区SELECTcreate_hypertable(monitor_point_data,time,partitioning_columnpoint_id,number_partitions8,chunk_time_intervalINTERVAL1 day);一个函数调用完事儿。时间轴按chunk_time_interval自动滚新块空间轴按点位 ID 哈希成 8 个分区。应用侧要做的改造就是把原来拼表名那段代码删掉。有个约束得提前讲省得对着报错发半天呆唯一索引必须带上分区列。想拿point_id这种单列做唯一约束数据库直接给你弹回来报错还老长一段。道理不复杂每个 Chunk 各自建索引数据库没法跨块替你保证唯一性所以唯一索引里必须把时间列捎上。三、第一个坑块间隔块间隔这个参数直觉上特别容易犯一个错觉得块切得越小查询越快上来就设个 1 小时。直说了吧会翻车。块切太细后台建新块的频率就飞起写入高峰还会莫名其妙冒出锁等待。为啥建新块要拿的锁比往已有块里插数据拿的锁时间长。一堆事务挤在同一时刻抢着开新块可不就互相顶死了嘛。那到底设多大手册里有参考值按日写入量给的每天写 2GB、内存 64GB 的机器7 天一块正合适一天写到 10GB缩到 1 天一块。所以原则就一句话先抄手册的作业再按自己的量微调。直觉在这儿不值钱。运行中想调也有接口但藏着个语义坑-- 注意只对之后新建的块生效已经建好的块不动SELECTset_chunk_time_interval(monitor_point_data,INTERVAL24 hours);-- 看看当前分区配置长啥样SELECTcolumn_name,num_partitions,time_intervalFROMtimescaledb_information.dimensionsWHEREhypertable_namemonitor_point_data;改间隔只管新块旧块一个不碰。也就是说块间隔设大了想改小旧块是救不回来的。要么干等它自己滚出保留期要么老老实实迁数据。这参数务必上线前定死。四、压缩和保留先问一句一个月之前的明细除了出报表那天还有谁碰它没人碰。时序数据的访问模式就是这么有规律最近的数据天天查老数据出了报表就没人搭理了。压缩策略照着这个规律配就行近几天原样搁着更老的块自动压成列存。ALTERTABLEmonitor_point_dataSET(timescaledb.compress,timescaledb.compress_segmentbypoint_id,timescaledb.compress_orderbytime DESC);-- 超过 7 天的块自动压缩SELECTadd_compression_policy(monitor_point_data,compress_afterINTERVAL7 days);-- 原始明细保留 180 天到期自动删块SELECTadd_retention_policy(monitor_point_data,drop_afterINTERVAL180 days);配置里两个参数说下作用。compress_segmentby是按哪列分组压缩时序场景一般挑设备或者点位 ID。compress_orderby是组内按啥排通常就填时间列。这俩选对了压缩比和查询效率都跟着受益实测压缩比 4:1 上下跟官方口径基本对得上。顺带提个不大但挺阴的细节压缩块上没法直接加带默认值的列要加得先解压。嫌解压麻烦也有变通加个可空列再 UPDATE 把值补上就这么绕过去。五、第二个坑刷新窗口和保留策略会互相咬报表聚合慢靠连续聚合治。思路不玄乎把小时级的聚合结果提前物化成一张特殊的超表后台按策略增量刷新查询直接拿现成的不碰明细。CREATEMATERIALIZEDVIEWpoint_data_hourlyWITH(timescaledb.continuous)ASSELECTpoint_id,time_bucket(INTERVAL1 hour,time)ASbucket,avg(value)ASavg_val,max(value)ASmax_val,min(value)ASmin_valFROMmonitor_point_dataGROUPBYpoint_id,bucketWITHNODATA;SELECTadd_continuous_aggregate_policy(point_data_hourly,start_offsetINTERVAL3 days,end_offsetINTERVAL1 hour,schedule_intervalINTERVAL30 minutes);下面这个坑我个人认为是整套方案里最容易翻车的必须单独拎出来说。很多人配这俩策略的时候是分开想的保留策略拍一个数刷新窗口拍另一个数各管各的看着多合理啊。但它们实际上会互相咬。你保留 30 天刷新窗口也伸到 30 天前会咋样聚合刷新跑到那个时间段一看源数据让保留策略给删了那它就把物化好的结果也顺手删了。注意这整个过程没有报错。没告警没异常日志就是报表上的数字悄无声息地没了。直到哪天有人盯着一条空曲线问数据咋回事你才知道坏了。这种静默失败排查起来最磨人。正确姿势就一条保留周期要远大于刷新窗口。照上面例子那样保留 180 天、刷新窗口只伸到 3 天前让刷新永远落在还有原始数据的时段里这坑就踩不着。手册里对这个组合是有明确警告的别问我为啥知道得这么清楚。日常查趋势还是普通 SQL配个时间桶函数要多细有多细SELECTtime_bucket(5 minutes,time)ASfive_min,avg(value)ASavg_valFROMmonitor_point_dataWHEREpoint_id1024ANDtimenow()-INTERVAL2 hoursGROUPBYfive_minORDERBYfive_min;六、几句经验回头看超表落地这事技术上真不难难的是心态。把原来攥在自己手里那点“分表智慧”整个交还给数据库交出去那几天是真没底老琢磨它真能替我管好几条经验搁这儿。块间隔先抄作业再微调按日写入量对照手册来。这参数改小只对新块生效设大了想缩没有回头路。唯一索引必须带分区列单列唯一约束直接报错把时间列加上就好。保留策略和刷新窗口必须一起设计。这条得再说一遍因为这俩配岔了连报错都没有数据就这么没了。压缩块上别直接加带默认值的列先解压或者可空列加 UPDATE 绕过去。还有个容易忽略的超表的价值不止“快”那一下。应用代码干净了团队里没人再需要搞懂那套分表路由的约定。这种工程上的松快时间拉长了看比查询快几秒值钱。往后单机写入真到了天花板还有分布式超表这条路写入再横向摊一层架构不用推倒重来。先写到这等真跑起来了再补后话。