对数据漂移的一些小思考

一、前言

最近在ETL工作中遇到了一些数据漂移的问题,写在这里权当做一个记录以及自己的一些思考。

二、什么是数据漂移

通常我们把从源系统同步进入数据仓库的第一层数据成为ODS层,数据漂移是一个很容易发生的现象。通常指ODS的表在同一个业务日期数据中包含前一天或者后一天凌晨附近的数据或者丢失当天的变更数据。
在大数据领域有另外一个东西名字很相近,叫数据倾斜。当然他们完全不是一码事,关于数据倾斜的问题,如果我不偷懒的话会在不远的将来也写一篇博客阐述一番我的理解。

三、我们遇到了什么问题

ODS层往往承接了面向历史的细节数据查询需求,为了查询性能落地到ODS层的数据需要进行切分存储,通常是按照时间维度–天来切分,实际上就是这个时间字段的准确性导致的数据漂移。

实际场景

公司主营短信业务,因此有了一张数据量庞大的短信记录表,这张表按照客户的发送时间来切分分区,字段为smt。实际上这张表里的时间字段非常多,因为整个业务场景就涉及到好几段流程,大概总结为:
客户提交短信请求 → 我们接受请求 → 路由寻找合适的通道 → 提交给运营商 → 运营商返回结果报告 → 匹配发送记录和返回报告 → 反馈给客户发送结果


可以想见,每一段子流程里都会有相应的时间字段。 选择使用客户的提交时间来做分区字段,也是为了贴近客户的实际体验。即某一天的短信记录明细就应该是客户提交给我们的那一天的所有短信。
实际上并不是这样,主要有两种场景导致了异样的发生:

1、通道延迟

我们接受到客户的短信请求后,到提交给运营商这段时间理论上是很快的,秒级响应。但某些时候因为网络波动或者服务器故障,会导致短信积压,卡在某一环节,如果正好卡在落库之前,这时客户在T天提交短信请求,积压解决后短信记录落库实际发生在T+1天。导致T+1天凌晨做ETL数据同步时这批短信记录获取不到,最终数据平台丢失了一部分数据。

1、特殊业务场景

有一类特殊的业务场景叫”先提后审“,客户提交一种特殊的短信请求后,需要客服审核内容,审批通过后才可实际发送。如果客户在客服下班时间段提交了这种短信请求,那么实际要到第二天客服上班后才会实际被提交,落库也发生在客服审批之后。同上一种情况,也会发生丢失数据的情况。

四、解决方案

4.1 延迟重传

我们公司采用了很粗暴的解决方案,T+1天允许T这天的数据存在数据漂移的现象。但是在T+4天,对T天数据进行重传,恢复这些丢失数据,保证最终状态的数据是完整的。
当然这种方式跟公司业务也是跟契合的,因为短信状态会在4天内做更新(因为运营商返回的状态报告也会有几天的延迟,约定4天内不返回报告计为未知状态不再更新)。这种方式本意是用作数据更新的,结果顺带着缓解了数据漂移。(不算解决是因为T+1天到T+3天,数据仍然有丢失,不完美)

4.2 更合理的时间切分字段

既然按照发送时间戳切分,会出现数据漂移,那么换一个业务场景的时间戳呢?
在短信这个业务场景下还真的有,那就是扣费时间。
扣费一旦发生,就不会变化,扣费作为核心关键功能,除非巨大故障也极少发生延迟现象。(当然真的发生了后期再补数据,因不可抗拒因素产生的问题是无解的,只要做到可补救即可)
如果系统有一个统一的钱包扣费服务,这个字段的一致性也是有保证的。公司为啥没有采用这种切分方式,我的理解是有两个原因:

  1. 存在月结客户,并不是所有客户的钱包都是预充值再消费的,一些大客户是先消费再月结的。针对这些客户,并不存在真正的扣费操作。
  2. 遗憾的是扣费服务是散落在系统的各个地方的,并没有统一管理起来,导致扣费这个操作本就不具备业务逻辑上的统一性。

针对问题1,其实是有解的,对月结客户仍然可以走一遍扣费流程,记录下一个“伪扣费时间”,甚至真扣费也无不可,无非钱包余额扣成负数。当然公司目前没有这么操作,针对月结客户,钱包余额是直接锁死的。月结客户的计费依赖月度的离线计算脚本。这样的操作同时带来了数据不统一的问题,在线客户的账单来自交易记录(钱包扣费,系统操作),而月结客户的账单来自短信记录统计(离线统计,脚本计算)。因为这种数据源的不统一,公司的财务计算一直不如意,实在是一个遗憾。


针对问题2,公司的短信业务发展了4年,这么多年里新增了许许多多的业务模块、功能、乃至针对大客户的特权特殊服务。扣费操作并不统一,甚至存在一小部分客户是非系统操作,而是由计算脚本扣费的。不统一的扣费服务也带来了一定的混乱局面,实为另一个遗憾。所幸这个问题以及在推进解决中,公司已经在规划一个钱包服务,作为各业务线的中台应用,解决这个历史顽疾。


当然扣费时间作为切分字段,针对短信业务来说是很合适的。可惜并不是所有业务场景下都能找得到这样的业务时间。很多公司的情况有很多许多业务功能,使用单一的业务时间会遗漏很多其他过程的变化记录,比如很常见的电商业务,就有下单、支付、退款、售后等过程,并不适合以某一单一业务时间做切分字段。

4.3 前后冗余

既然取一天的数据会有数据漂移现象且多半发生在凌晨(因为凌晨是一天的分隔,这不是废话么),那么自然而然就有一种方式:我们多向前一天要一部分数据,也向后一天多要一部分数据。根据一些经验,一般是15分钟。保证数据只多不少,切分时按照需要的业务时间再过滤。这样可以解决那些因为延迟造成的数据漂移,但同时也带来了问题:
如果多获取了T+1天的一些更新变化,会导致T天的最终状态没有被保留,最终存储在T天的数据实际是T+1天凌晨的状态。这对下游的相关统计会造成一些误差。
另外,上文提到的特殊业务场景也并没有解决。

4.4 多时间字段共同限制

这一部分的感受不是很深刻,按照一些文章的说法:

  1. 根据日志时间冗余前后数据,然后用修改时间过滤非当天数据,这一步几乎同4.2描述,保证系统原因的遗漏不发生;
  2. 根据日志时间冗余后一天数据的部分,按照主键以日志时间升序取第一条,为了获取最接近T天状态的数据;
  3. 将1,2步骤的数据做全外连接,限制业务时间来获取T天数据。

五、后话

相对而言,短信业务是一种比较单一、简单的业务场景。这么说,公司同事可能会大有反对声音,但我仍然这么觉得。目前公司采用的T+4重传,很好地解决了数据更新与数据漂移的问题。虽然我认为统一的扣费时间做时间切分会更合理,对财务计算更更友好。
简单的业务场景,解决方案自然也比较简单粗暴。大多数公司的业务实际上都比我们短信业务复杂,在数据漂移上自然要花费更多的精力去解决。

你可能感兴趣的:(数据仓库,数据仓库)