文章开头介绍下,有粉丝朋友曾留言让我分享下《数据增量同步和全量同步》,于是就抽空写篇原创博文来仔细讲讲吧,做技术分享。
本篇就来聊一聊 大数据领域 「数据接入」
这块知识点。
通过大纲提问式进行概览,你能通过文章学到什么:
1. 常见的几种数据接入方式
2. 数据接入的几种业界同步策略
3. 面对海量数据同步的挑战,如何优化解决方案
把数据同步至数据仓库中,称为数据接入,一般同步过来的数据存放在ODS贴源层
。主要有抽数业务系统同步和埋点数据上报。
那么同步至数据仓库前的数据源有哪些呢?
- 关系型数据库的结构化数据:例如mysql/oracle/sqlserver 等
- 非关系型数据库的非结构化数据:例如hbase/mongodb/oceanbean 等
- 文件系统的结构化和非结构化数据:例如 阿里云对象存储OSS/文件存储NAS 等
直连同步是指通过定义好的规范接口API和基于动态链接库的方
式直接连接业务库,如 ODBC/JDBC 等规定了统一规范的标准接口,不同的数据库基于这套标准接口提供规范的驱动,支持完全相同的函数调用和SQL实现
直连同步这也是目前大数据平台离线同步数据的主要手段,但该方式对业务源系统的性能影响可能会较大
,比如涉及到大批量数据同步时会拖垮业务系统的性能,如果业务数据库有采用主从库策略的话,那么我们从从库抽数还可以避免对业务系统的影响,但是数据量大的表同步,效率还是不高。
关于直连同步总结:
- 实现简单,是大数据平台离线同步的主要手段
- 同步数据量大的表,会影响业务系统的性能,谨慎操作,数据库若有主从库策略则要从从库抽数避免对业务系统直接影响,而且还要制定数据接入规范,避免业务高峰期大批量抽数操作,不然随时会带来影响线上服务的风险。
数据文件同步通过约定好的文件编码、大小、格式等,直接从源系
统生成数据的文本文件,由专门的文件服务器,如 FTP 服务器传输到目标系统后,加载到目标数据库系统中。
互联网的日志类数据通常是以文件形式保存的,适合这种同步方式。
不过毕竟通过文件服务器上传下载的话难免会有丢包或者错误的风险,所以在传输数据文件的同时,为了确保数据文件同步的完整性,会一并传输一个校验文件,该校验文件记录了数据文件的数据量以及文件大小等校验信息,以供下游目标系统验证数据同步的准确性。另外还可以在源系统生成数据文件的同时进行压缩和加密操作,在目标系统接收数据文件时再进行解压缩和解密操作,保证数据文件同步的效率和安全性。
关于数据文件同步总结:
- 日志类数据通过以文件形式存储,适合这类同步方式
- 保证数据文件同步的完整性和安全性以及传输效率,可在传输数据文件的同时一并传输一个校验文件供目标系统校验,同时可对数据文件进行加密和压缩操作
大多数主流数据库都已经实现了使用日志文件进行系统恢复,因为日志文件信息足够丰富,而且数据格式也很稳定,完全可以通过解析日志文件获取发生变更的数据,从而满足增量数据同步的需求,比如mysql,一般是通过解析binlog日志方式来获取增量的数据更新,并通过消息订阅模式来实现数据的实时同步。
关于数据库日志解析同步总结:
- 对业务系统影响较小,而且可实现实时与准实时的同步,延迟控制在毫秒以内
- 成本较高,需要在源数据库和目标数据库之前搭建一套系统实时同步数据
顾名思义,就是每日进行增量同步数据,每日调度任务根据业务记录时间字段从数据库增量同步数据。
-- 增量同步数据
insert overwrite table ods.table_in partition (dt='${yyyy-MM-dd}')
select *
from table_source -- 业务源表
where create_time >= '调度当日时间'
or update_time >= '调度当日时间'
这样每日增量同步过来的数据都放在增量分区表的每日分区内,可以保存数据的历史变更状态,不过要取历史全量数据的数仓最新状态数据对于增量分区表的话就会取数麻烦些
。比如要取全量订单记录当前最新状态,需要先扫描增量分区表历史全部分区得到全量订单数据,再取每笔订单数仓最新的那条状态记录。
顾名思义,就是每日进行全量同步数据,每日调度任务直接从数据库全量同步数据。
-- 全量同步数据
insert overwrite table ods.table_tm partition (dt='${yyyy-MM-dd}')
select *
from table_source -- 业务源表
全量分区表,下游要取历史全量数据的数仓最新状态数据就很便捷了,只需要取全量分区表最新分区的全量数据即可,就代表着全量数据且数仓最新状态。不过这种抽数方式不建议使用,数据量小还行,因为每日分区存储一份历史全量数据会对HDFS存储造成浪费是一方面,当数据量大的话这样做是绝不可行的,会拖垮业务源系统数据库,对业务源数据库造成压力负载,严重时还会造成线上故障。
(重点)
基于以上增量同步 和 全量同步 2种同步数据方式的利弊,结合起来形成一种同步T+1的增量数据,再合并历史T+2的全量数据 的抽数方式
,这样就在最新分区表里即满足了数仓全量最新快照数据,同时也降低了对存储的浪费以及对业务源数据库的压力负载,兼容了上述2种策略。
以下附 技术代码案例讲解:
-- 增量合并全量方案一:union all
insert overwrite table 全量表 partition (dt = '${yyyy-MM-dd}')
select *
from
(
select
*
,row_number() over (partition by 去重主键 order by 时间字段 desc) as rk
from
(
select
*
from 增量分区表
where 1 = 1
and dt = '${yyyy-MM-dd}' -- 增量表T+1当前增量数据
union all
select
*
from 全量分区表
where 1 = 1
and dt = '${yyyy-MM-dd,-1d}' -- 全量表T+2历史全量数据
) a
) b
where rk = 1 -- 取最新状态数据
;
-- 增量合并全量方案二:full outer join
insert overwrite table 全量表 partition (dt = '${yyyy-MM-dd}')
select
-- 优先取增量表最新数据更新覆盖
coalesce(a.主键,b.主键) as 主键
,...
from
(
select
*
from 增量分区表
where dt = '${yyyy-MM-dd}' -- 增量表T+1当前增量数据
) a
full outer join
(
select
*
from 全量分区表
where dt = '${yyyy-MM-dd,-1d}' -- 全量表T+2历史全量数据
) b
on a.主键 = b.主键
关于增量合并全量方案的小结:
- 方案一和方案二 这2种解决方案 本质上都是用增量数据来更新覆盖历史全量数据,不过呢通过full outer join方式合并前要确保记录是唯一的,这样关联时才不会发生数据发散。
- 若说2种解决方案的性能对比的话就大差不差吧,数据量大的话方案一可能发生的性能瓶颈主要在合并过程的全局排序去重,方案二可能发生的性能瓶颈主要在合并过程的大表关联上,个人觉得两种方案都ok,
目前业界离线批数据接入大致也是这种思路-增量合并全量。