深入数仓离线数据同步:问题分析与优化措施

一、前言

在数据仓库领域,离线数仓和实时数仓是常见的两种架构类型。离线数仓一般通过定时任务在特定时间点(通常是凌晨)将业务数据同步到数据仓库中。这种方式适用于对数据实时性要求不高,更侧重于历史数据分析和报告生成的场景。

然而,采用离线同步方式可能会引发业务数据与数据仓库数据不一致的问题。本文的目标是深入分析这些问题的根本原因,并提供一些建议来优化同步流程,以确保数据的一致性。

二、场景

在大数据平台中,业务部门常常需要查看历史某一天的表数据。为了记录历史数据的变化,离线数仓常见的解决方案是拉链表和快照表。而由于拉链表的查询方式较为复杂不便直观的展现问题,因此在这里我选择使用快照表作为示例,以便更清晰地阐述离线数仓的数据一致性问题。

快照表是用来存储某个时间点的所有数据-通常粒度是天,相当于是对每天的业务数据做了一次快照,存储当天的全量数据;例如:快照表12号分区中的数据是从历史到11号的所有数据,13号分区中的数据是从历史到12号的所有数据,其他的以此类推,示例如下:

  1. [Mysql] 业务数据 - 用户表全量数据:
idnamephonegendercreate_timeupdate_time
1jack1112023-06-01 13:00:002023-06-01 13:00:00
2jason2222023-06-01 13:00:002023-06-01 13:00:00
3tom3332023-06-01 13:00:002023-06-01 13:00:00
  1. [数仓]由于离线数仓是T+1处理,故2023-06-02时数仓快照表数据如下:
idnamephonegendercreate_timeupdate_timedt[分区字段]
1jack1112023-06-01 13:00:002023-06-01 13:00:002023-06-01
2jason2222023-06-01 13:00:002023-06-01 13:00:002023-06-01
3tom3332023-06-01 13:00:002023-06-01 13:00:002023-06-01

加粗为分区字段

  1. [Mysql] 2023-06-02 业务数据新增了一名用户,且更改了tom的手机号,此时表数据如下:
idnamephonegendercreate_timeupdate_time
1jack1112023-06-01 13:00:002023-06-01 13:00:00
2jason2222023-06-01 13:00:002023-06-01 13:00:00
3tom4442023-06-01 13:00:002023-06-02 09:00:00
4tony5552023-06-02 10:00:002023-06-02 10:00:00

加粗为更新/新增数据

  1. [数仓]由于离线数仓是T+1处理,故2023-06-03时数仓快照表数据如下:
idnamephonegendercreate_timeupdate_timedt[分区字段]
1jack1112023-06-01 13:00:002023-06-01 13:00:002023-06-01
2jason2222023-06-01 13:00:002023-06-01 13:00:002023-06-01
3tom3332023-06-01 13:00:002023-06-01 13:00:002023-06-01
1jack1112023-06-01 13:00:002023-06-01 13:00:002023-06-02
2jason2222023-06-01 13:00:002023-06-01 13:00:002023-06-02
3tom4442023-06-01 13:00:002023-06-02 09:00:002023-06-02
4tony5552023-06-02 10:00:002023-06-02 10:00:002023-06-02

加粗为更新/新增数据

以上是快照表的表现形式,接下来我们看下具体实现

三、实现

离线数仓(T+1)中关于快照表的实现方式有两种:全量同步和增量同步。

值得强调的是,这些同步任务的执行方式并不局限于特定的工具或框架,例如sqoop/spark;因此在本文中我们将使用SQL语句来表达数据处理过程。

需要注意的是这两种实现方法都有可能导致数据不一致的问题,下一节将对此进行详细讨论和解释。

3.1、全量同步

  1. 全量同步顾名思义是将业务数据用户表全量同步一份到数仓快照表中的指定分区内,该方式简单粗暴,这里以:2.1、示例中的 2023-06-02业务数据新增了一名用户,且更改了tom的手机号为例;过程如下:

  1. sql语句:
# 2023-06-03凌晨执行的全量同步sql语句
INSERT INTO 数仓快照表 PARTITION (date='2023-06-02')
select * from 业务用户表 where update_time < '2023-06-03 00:00:00';

3.2、增量同步

增量同步顾名思义是将业务数据用户表按天为粒度将增量数据与数仓快照表中的前一天数据进行join对比后放入到指定分区内,关于增量同步的实现不在本文赘述,对此感兴趣的读者可参考笔者的另一篇文章:数仓日常维护:剖析每日增量同步的内部机制

四、数据一致性问题

以上述快照表为例,可能引发一致性问题的情况是指在执行层的Spark或Sqoop任务启动和执行期间,业务数据库表的数据发生了变化,从而导致快照表与业务表的数据不一致。这种不一致性问题可能会对数据处理和分析产生负面影响,示例如下:

假设业务表在2023年6月2日新增了“Tony”修改了“Tom”手机号这两条数据。在凌晨定时任务启动后,引擎初始化及加载数据时,业务数据中的“Tony”发生了变更,其“update_time”字段也随之变化。然后,执行引擎再次通过“update_time”字段读取业务数据时,由于变更,它可能会错过“Tony”这条记录。这将导致数仓快照表中2023年6月2日分区的数据缺失“Tony”用户信息,造成了当天数据不一致的问题,过程如下:

在这里插入图片描述

上图采用全量同步方式,增量同步同样会有此问题

以上问题的本质是数据同步执行层在启动或数据加载过程中,由于业务数据库表数据的动态变化,特别是在数据加载期间或引擎启动期间发生的数据更新操作,导致了读取到的数据无法准确地反映业务表在特定时间点的状态。这样的数据变化可能会使得快照表在某些情况下缺少或错误地反映了业务表的最新状态,导致了数据不一致的问题。

五、解决方案

4.1、加锁

同步任务在凌晨前启动,当时钟指向零点时,对需要同步的数据库表进行锁定,以防止其他更改操作干扰数据读取,确保数据一致性。

然而,这种方式存在明显弊端。首先,要求业务库支持锁操作,并且同步任务必须具备相应的锁权限。更重要的是,这种方式会对业务库产生较大影响,因此不推荐使用。值得一提的是,Flink-CDC 1.x版本的全量同步采用的就是使用了这种对表加锁的策略,不过该痛点已在2.x版本后改为增量快照读取机制从而解决了加锁问题

对此感兴趣的读者可参考笔者另一篇文章:深入解析 Flink CDC 增量快照读取机制

4.2、实时同步

实时同步是一种有效解决数据一致性问题的方法,因其同步方式大多是采用binlog + checkpoint分布式快照的形式故不会存在漏读情况,但这可能需要对现有技术架构做出较大的改变。实时同步具体实现不在本文赘述,感兴趣的同学可以看笔者另一篇文章:Flink实时数仓同步:拉链表实战详解

4.3、binlog修正

此思路灵感来源于 Flink-CDC 2.x 的增量快照读取机制。这种修正方式相对简单,且不会对现有的离线数仓架构产生改变,仍然可以使用 Spark 或 其他执行引擎。对此感兴趣的读者可参考笔者另一篇文章:深入解析 Flink CDC 增量快照读取机制

具体思路如下:相较于之前的离线同步,新增了一个读取 binlog 消息修正的步骤。当同步任务读取完业务数据后,它会读取从零点到当前时间内的 binlog 日志。如果发现了 update 操作的日志,则判断该条日志中 after 数据的 update_time 是否属于当前快照表的时间范围。若属于,则将 after 数据补充到已读取的业务数据中。

在这里插入图片描述

这种方法能够有效解决离线数仓同步数据一致性的问题,而且不需要修改现有的离线数仓架构。因此,对于那些不想对原有技术架构做出变更的人来说,这种方法值得推荐。

六、相关文档

  • 23
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 如果要设计一个基于 Hive 的网站访问数据离线数仓,需要以下步骤: 1. 收集网站的访问数据,并存储在 Hadoop 分布式文件系统(HDFS)上。 2. 利用 Hive 建立数据仓库,并对访问数据进行结构化。 3. 在 Hive 中创建数据表,并导入数据。 4. 使用 Hive 查询语言(HQL)进行数据分析,生成统计报告和图表。 5. 将分析结果导出到外部存储,便于进一步使用。 6. 定期对数据仓库进行维护和更新,保证数据的最新性。 这些步骤可以帮助你设计一个稳健的、高效的离线数仓,用于分析网站的访问数据。 ### 回答2: 基于Hive的网站访问数据离线数仓设计需要以下步骤: 1. 数据采集和存储:通过日志收集器收集网站访问日志,将这些日志数据传送到Hive的数据仓库中进行存储。可以使用Flume或Kafka等工具来实现数据采集和传输。 2. 数据清洗和转换:使用Hive的ETL功能对原始数据进行清洗和转换。这包括去除无效数据、处理数据格式、合并数据等。可以使用Hive的查询语言(例如HQL)来实现这些操作。 3. 数据建模和分区:根据网站访问数据的需求,设计合适的数据模型,并进行分区以提高查询性能。可以使用Hive的表分区功能根据时间、地域、用户等维度进行数据分区。 4. 数据加载和索引:使用Hive的加载命令将清洗和转换后的数据加载到数据仓库中,并根据查询需求创建索引以加快查询速度。可以使用Hive的分区索引或bitmap索引等技术来实现数据加载和索引。 5. 数据查询和分析:通过Hive的查询语言对数据仓库中的网站访问数据进行查询和分析,并生成相应的报表和可视化结果。可以使用Hive的聚合函数、分组和排序等功能来实现数据查询和分析。 6. 数据备份和恢复:定期对数据仓库进行备份,以防止数据丢失或损坏。可以使用Hive的导出和导入功能将数据仓库中的数据备份到其他存储系统,如HDFS或云存储。 通过以上步骤设计的基于Hive的网站访问数据离线数仓可以实现高效的数据存储、查询和分析,为网站运营和决策提供可靠的数据支持。 ### 回答3: 基于Hive的网站访问数据离线数仓设计如下: 1. 数据源收集:首先,需要收集网站访问数据源,包括网站服务器日志、用户行为数据、广告点击等相关数据。这些数据可以通过Flume等数据采集工具实时收集到Hadoop集群上。 2. 数据预处理:将收集到的原始数据进行预处理,包括数据清洗、字段解析、数据格式转换等。可以使用Hive进行数据清洗和转换操作。 3. 数据存储:将预处理后的数据存储到Hive或者HBase中,便于后续的查询分析。Hive提供了数据仓库的功能,并可以通过Hive SQL进行数据查询和分析操作。 4. 数据分区:根据业务需求将数据进行分区,可以按照时间、地区、用户等维度进行分区,提高查询效率和性能。 5. 数据建模:设计合适的数据模型,根据业务需求创建表结构,并建立关联关系。可以使用Hive的表和分区来组织数据,并使用Hive内置的函数和脚本来处理数据。 6. 查询分析:根据业务需求,使用Hive SQL语句进行查询和分析操作,例如统计网站的访问量、独立访客数、页面流量等指标。可以使用Hive的MapReduce和Tez来进行大规模数据处理和计算。 7. 数据可视化:将查询结果通过可视化工具(如Tableau、Superset等)进行展示,生成直观的数据报表和可视化图表,供业务人员和决策者进行数据分析和决策。 8. 定期更新:根据实际情况,定期将新的网站访问数据导入数据仓库进行更新,保持数据的实时性和准确性。 通过以上步骤,可以设计一个基于Hive的网站访问数据离线数仓,实现对网站访问数据离线分析和查询,为业务决策提供数据支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Light Gao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值