业务系统的重要数据存储在关系型数据库中,对于数据量较大的表还会做分库分表,数据仓库侧做数据处理需要将数据从业务系统同步过来,这就需要将db中的数据同步到hdfs中,在hdfs之上通过hive外表的方式去查询分析处理数据。这个过程就需要数据同步工具发挥作用,开源的数据同步工具强大,但是不一定贴切具体的业务,所以会自己开发这样的工具,简单梳理一下在用的同步工具的设计思路,以及设计一个同步工具时候需要考虑的问题。
命令行模式数据同步工具
使用方式
命令行的参数有:数据库的url,数据库的类型,数据库表名,数据表列名,where语句参数,数据split主键,查询数据库的批次大小,hdfs路径,hdfs文件切分的规则以及help option等。
实现方式
数据同步由脚本启动jar接收命令行参数的方式实现,整体的流程大致如下。
数据同步部分
将脚本中jar包的传入的option通过反射查询注解找到解析参数的类,通过JCommander解析option参数,通过反射找到对应的task类,用解析好的参数初始化task类,初始化数据库连接池,线程池等,通过数据库类型,差异化初始sql,查询where语句限定的数据split主键的最大最小值,通过分批次查询将数据获取到,启动多线程写读取数据按照hdfs文件切分的规则写hdfs文件。
数据同步还有一些其他的处理,比如如果输入的表名是正则的方式,那么将会在当前库只给你查询正则匹配到的所有表;对于一些不hive识别不了的类型做mapping,例如对于postgresql数据库中的hstore类型,在同步的过程中会将字段装换成json 字符串。
环境和部署
在脚本中封装数据同步jar包,设置JAVA_OPTS参数,mktemp生成日志文件,将脚本加入到系统的path中,通过固定的命令行启动数据同步。JAVA_OPTS参数 设置的一定要合理,脚本中会有默认值,在同步大表的时候有OOM情况需要在脚本外部export 合适的JAVA_OPTS 参数。
数据同步系统
上述脚本的方式虽然好用,但是还是免不了需要有脚本作为载体,理想的数据同步系统是完全不需要开发量,全流程拖拽即可实现,以上是数据同步系统的思路。数据同步系统按照master–slave的方式实现。
master部分
matser的web部分提供了创建,修改,保存等功能。同时还负责维护目前已知的元数据,即将在系统上配置的数据库下的所有表的结构定时的同步到matser底表中,在创建任务的时候一旦选中数据源以后,就可以将库中的所有表和字段展示在前端可供选择。master还负责与调度系统打通,将创建的数据同步任务初始化到调度系统上,让调度系统管理任务的执行。
slave 部分
slave在得到调度指令以后,通过查询master的接口查询需要同步的表和字段,初始化数据库连接池,分批次的去查询数据,直接写文件到本地磁盘。再通过slave上的文件处理脚本对文件做split和gz压缩,然后put到外表对应的路径上。
优缺点对比
同步工具目前只支持分库表的同步,同步系统在数据源的上面封装了数据源的集合,可以支持分库分表的同步;
同步工具只支持orc文件,同时按照文件行数均匀做了切分,文件直接写到hdfs,对本地磁盘压力小,同步系统只支持文本格式,通过过程利用了本地磁盘,容易出现磁盘被打满的情况;
同步工具可以通过option获取表的建表语句和注释,方便了建hive的外表,同步系统目前没有这个功能,需要人工将db的建表语句转换为hive的建表语句,稍显麻烦出错性高;
同步工具的表结构是实时查询拿到的保证了表的及时性,同步系统通过定时轮训获取表接口,加快了同步的效率,在分库分表的表同步上尤为明显;
同步系统的几个问题
在设计一个新的同步系统的时候一般都需要考虑以下问题。
表结构变更
数据库字段 | hive字段 | 处理 |
---|---|---|
a,b | a,b | 正常 |
a,b,c | a,b | 忽略数据库的多余字段,以Hive为准 |
b,a | a,b | 顺序不对,调整 |
a | a,b | 数据库少一个,报错 |
a,c | a,b | 不匹配, 报错 |
hive表命名规范
方案一: ods_+table_namehive表命名规范
方案二:ods_+业务线+table_name
方案三:ods_+业务线+数据库名+table_name
方案三:ods_+业务线+数据库名+table_name+增量全量标识符
和调度的关系
方案一:调度发消息,同步去执行,执行完消息回去,调度更新任务状态。
方案二:调度轮训查询同步接口。
方案三:在新建同步任务的同时注册任务到调度系统。
文件格式
ODS:Operational Data Store,操作数据层,在结构上其与源系统的增量或者全量数据基本保持一致。作为数据准备区,承担着基础数据的记录以及历史变化。目前来看用orc格式存储比较合理。
增量和全量
无id和时间的表,强制后端加字段。
通过id增量:需要将目前hive表中的最大id拿到:1. 每次同步完成以后记录当前的最大id到数据库中,下次同步前读取;2. 每次同步前先查询hive库中的最大id,然后再开始数据同步。
通过时间字段增量:如果每天抽取的严格就是昨天的数据,那么之要限制时间字段等于昨天即可,如果不是严格的一整天,同样需要拿到最大的时间。这里分区又有两种处理:每个分区里放全量数据,每个分区放每天新抽取的数据。
文件大小
多大的文件做为一个文件的切分。
ods表怎么分区
全量分区:占用hdfs空间大,使用相对方便。
- 无物理删除数据的表
每次全量同步数据:同步数据量大时间长,对数据库入侵大
每次增量同步数据,merge数据到新分区:merge过程出现问题发现比较晚的话,需要从问题数据前一天开始往后merge,或者再全量一次。 - 有物理删除数据的表
只能全量同步数据:同步数据量大时间长,对数据库入侵大
- 无物理删除数据的表
增量分区:占用空间小,使用不太方便,涉及到业务信息的相对会更麻烦
- 无物理删除数据的表
每次增量同步数据,放到单独的分区 - 有物理删除数据的表
不适用
- 无物理删除数据的表
系统发布怎么保证任务不失败
执行jar包和应用分离,在jar中更新任务执行状态
同步任务执行中将任务状态持久化到本地文件中,发布系统后通过状态重新调起任务。
特殊类型处理
pg:hstore,geometry,ltree