一批数据上有三个时间:业务时刻、写入时刻、调度时刻。演示里它们差了半天。 三十天到达时刻:12 天晚于 06:00,5 天晚于 06:30,最晚 08:15——那天报表晚了 15 分钟。 准时到不等于数据对:11-03 六点零四就到,行数只有平时的一半。
教材 8.5 节:数据新鲜度的管理。全书最后一节。 结构告诉你它是什么,沿袭告诉你它从哪来,新鲜度告诉你它是几点的。 一句话:新鲜度不是一个值,是一个随时在长的数。
一、一批数据上有三个时间
业务时刻:最后一条订单真正发生的时间,演示里是 11-01 23:59。 写入时刻:数据真正落进表的时间,11-02 06:12。 调度时刻:作业被计划启动的时间,11-02 06:00。
三个时间能差出半天。说「数据是今天的」之前,得先说清是哪个今天。 它们各自回答不同的问题:业务时刻决定这份数据覆盖到什么时候,写入时刻决定它什么时候可用, 调度时刻只说明作业什么时候被叫起来。 演示里调度比写入早了十二分钟——被叫起来不等于跑完,中间在排队。 这十二分钟就是排队时间,很多人排查慢的时候会漏掉这一段。
二、新鲜度是个随时在长的数
新鲜度等于「现在」减去「数据截止」。 同一个批次,06:30 去看是 6 小时 31 分,09:00 去看就是 9 小时 01 分。 所以它不是一个定值,是一个一直在长的数。 这跟「数据量」不一样,数据量放着不动就不变, 新鲜度放着不动就变坏。
隔一天还没更新,就是 33 小时。这种一般不是「慢」,是作业挂了没人发现。 判断一份数据能不能用,问的应该是:它的新鲜度,能不能满足这个用途?日报能接受十小时, 实时风控连十分钟都嫌长。
三、三十天的尾巴
演示模拟了三十天的到达时刻:平时六点前后到,其中四天出了状况。 结果:十二天晚于 06:00,五天晚于 06:30,最晚的一天 08:15——那天报表晚了十五分钟。 三十天的中位数很漂亮,五点半左右。但平均值骗人,尾巴才要命。
每个月总有那么一两天卡在最后十分钟。用户记住的恰恰是那一两天,不是另外二十八天。 所以看新鲜度不能看均值,要看分布:最晚一次多晚、超过阈值的几次、连续晚的有没有。
四、报警要按余量设
演示把三十天分成四档:绿(余量一小时以上)26 天、黄(15 分钟到 1 小时)1 天、 红(0 到 15 分钟)2 天、已违约 1 天。 如果只设一条「超过 08:00 就报警」,那两天红灯全都不报——它们还没晚,但马上就要晚了。 等到报警的时候,报表已经晚了。 报警要报在「还来得及」的时候。
这也是所有监控的通用原则:阈值要设在「还能补救」和「已经没救」之间。设在结果上,就只是通知, 不是报警。
五、准时到,不等于数据对
演示最后放了三天的对照。11-03 那天数据六点零四就到了,新鲜度满分。 但行数只有五万一千,平时是九万九千。 准时到的坏数据,比迟到的数据更危险——迟到会有人问,准时没人查。
所以新鲜度必须和行数、空值率这些指标一起看。行数从哪来?就是第 25 个 Demo 那张作业日志。 元数据这一章讲到这里就齐了:结构告诉你它是什么,沿袭告诉你它从哪来,新鲜度告诉你它是几点的。 三件事合起来只回答一个问题:你敢不敢拿这个数去做决定。
六、动手 Demo:三十天里,有几天赶不上报表
模拟三十天的数据到达时刻,看分布而不是看均值。 按「离报表时刻还剩多少」分四档,数每档几天。 最后对照三天,看新鲜度合格但数据不对的情况。
BASE_MIN, REPORT_MIN = 6 * 60, 8 * 60 # 06:00 更新,08:00 出报表
rng = random.Random(20261102)
slow = {5: 95, 12: 108, 23: 118, 28: 135} # 四天出状况
days = []
for i in range(30):
off = int(rng.gauss(0, 18))
days.append(BASE_MIN + (slow[i] if i in slow else off))
for t in days:
gap = REPORT_MIN - t # 余量
print('%.0f 分钟余量' % gap)
bad = [t for t in days if REPORT_MIN - t < 15]
print('红线以内或违约:', len(bad), '天')
实跑输出:
--------------------------------------------------------------------
数据新鲜度:这批数据是哪一刻的
--------------------------------------------------------------------
① 一批数据上有三个时间
--------------------------------------------------------------------
| 时间 | 值 | 含义 |
|---|---|---|
| 业务时刻 | 11-01 23:59 | 最后一条订单真正发生的时间 |
| 写入时刻 | 11-02 06:12 | 数据真正落进表的时间 |
| 调度时刻 | 11-02 06:00 | 作业被计划启动的时间 |
三个时间能差出半天。说「数据是今天的」之前,得先说清是哪个「今天」。
业务时刻决定这份数据覆盖到什么时候,写入时刻决定它什么时候可用,
调度时刻只说明作业什么时候被叫起来——被叫起来不等于跑完,演示里它比写入早了 12 分钟,就是在排队。
演示里这批数据的业务时刻是 11-01 23:59,写入时刻是 11-02 06:12,
所以它比业务时间晚了 373 分钟才可用。
② 新鲜度 = 现在减去数据截止
--------------------------------------------------------------------
| 批次 | 业务截止 | 现在 | 新鲜度 |
|---|---|---|---:|
| 11-02 批 | 11-01 23:59 | 11-02 06:30 | 6 小时 31 分 |
| 11-02 批 | 11-01 23:59 | 11-02 09:00 | 9 小时 01 分 |
| 11-01 批 | 10-31 23:59 | 11-02 09:00 | 33 小时 01 分 |
同一个批次,问的时间不同,新鲜度就不一样。所以它不是一个定值,是一个随时在长的数。
第三行是隔了一天还没更新的情况:33 小时。这种一般不是「慢」,是作业挂了没人发现。
③ 30 天的实际到达时刻
--------------------------------------------------------------------
| 区段 | 到达时刻 | 超 06:30 的天数 |
|---|---|---:|
| 第 1~5 天 | 05:13、05:39、05:42、06:17、06:03 | 0 天 |
| 第 6~10 天 | 07:35、06:06、05:50、06:54、05:38 | 2 天 |
| 第 11~15 天 | 05:24、05:27、07:48、05:24、05:38 | 1 天 |
| 第 16~20 天 | 05:44、05:34、06:17、05:33、05:43 | 0 天 |
| 第 21~25 天 | 05:02、05:43、06:07、07:58、06:04 | 1 天 |
| 第 26~30 天 | 05:56、06:03、05:38、08:15、06:00 | 1 天 |
三十天里 12 天晚于 06:00,5 天晚于 06:30。
最晚的一天是 08:15,比计划晚了 135 分钟。
报表 08:00 要出,那天 08:15 才到——报表晚了 15 分钟。
平均值骗人,尾巴才要命。 三十天的中位数很漂亮,但每个月总有那么一两天卡在最后十分钟。
④ 报警要按余量设,不按到达时刻设
--------------------------------------------------------------------
| 状态 | 余量 | 动作 |
|---|---|---|
| 绿 | 1 小时以上 | 不吭声 |
| 黄 | 15 分钟到 1 小时 | 群里提一句 |
| 红 | 0 到 15 分钟 | 打电话 |
| 已违约 | 负数 | 报表延期,同时查原因 |
| 状态 | 天数 | 占比 |
|---|---|---:|
| 绿 | 26 | 87% |
| 黄 | 1 | 3% |
| 红 | 2 | 7% |
| 已违约 | 1 | 3% |
按余量分档,一眼就能看出这不是「全都还好」:一个月里有 2 天卡在 15 分钟以内,还有 1 天直接违约。
如果只设一条「超过 08:00 就报警」,那 2 天红灯全都不报——它们还没晚,但马上就要晚了。
等到报警的时候,报表已经晚了。报警要报在「还来得及」的时候。
⑤ 准时到,不等于数据对
--------------------------------------------------------------------
| 批次 | 到达 | 行数 | 新鲜度 | 数据质量 |
|---|---|---|---|---|
| 11-02 | 06:05 | 99842 | 合格 | 合格 |
| 11-03 | 06:04 | 51203 | 合格 | 【不合格】 |
| 11-04 | 07:41 | 99780 | 黄 | 合格 |
11-03 那天数据六点零四就到了,新鲜度满分,但行数只有平时的一半。
准时到的坏数据,比迟到的数据更危险——没人会去查它。
所以新鲜度要和行数、空值率这些指标一起看。行数从哪来?就是第 25 个 Demo 里那张作业日志。
一句话收尾:元数据管的是「你敢不敢信这个数」。
结构告诉你它是什么,沿袭告诉你它从哪来,新鲜度告诉你它是几点的。
第一段那三个时间是本篇的地基。 混用它们,就会出现「数据是今天的」和「数据是截止昨晚的」两种说法,然后开会吵半小时。 第二段那个分配置很讲究:多数天数在六点前后小幅浮动,四天出状况。 这才像真实情况——不是均匀分布,是有尾巴的。 第三段是本篇最该记住的:中位数漂亮不代表能按时出报表,决定成败的是最晚那几次。 第四段的三天对照是收尾。 新鲜度和数据质量是两个维度,一个管「什么时候到的」,一个管「到的是不是对的」。
30 秒实验
- 把
REPORT_MIN从 08:00 提前到 06:30,看绿色还剩几天、违约变几天。 - 把四条慢的那天去掉,看分布变成什么样,再想想「去掉异常值」合不合适。
- 给你手上任何一张报表加三列:业务时刻、写入时刻、新鲜度,看能不能填出来。
常见误区
- 「数据是今天凌晨更新的,所以是今天的数。」凌晨更新的往往是昨天的数据。 看业务时刻,不看写入时刻。
- 「平均六点到,没问题。」平均不重要。看最晚一次,看超过阈值的次数。
- 「数据准时到了,可以用了。」行数、空值率、口径都可能出问题。新鲜度合格只是第一关。
自测三问(点开对答案)
1. 业务时刻、写入时刻、调度时刻分别是什么? —— 业务时刻是数据内容的时间点,写入时刻是它落表的时间,调度时刻是作业被启动的时间。 三个都能差出几小时。 2. 为什么新鲜度不能只看平均值? —— 因为决定能不能按时出报表的是最晚的那几次,不是中位数。平均值会把这些尾巴抹平。 3. 报警阈值应该怎么设? —— 按「离截止还剩多少」设,而不是按「已经超时」设。设在结果上只能通知,设在前头才能补救。全书二十七篇到这里结束。回头看,讲的其实是一件事:让数据从产生到被相信,每一步都说得清。
- ☐ (全书完)