快速、高质量、稳定的将数据从业务系统接入到数据平台是至关重要的一环。前面的文章中,我们分别提到了关系型数据库的数据接入和非关系型数据库的数据接入。除了来自技术上的挑战,数据接入还会遇到哪些其他挑战呢?
本文将尝试基于项目中的实践,给大家分享一下我们的思考。
一般而言,实施数据接入将可能碰到如下问题:
下面将结合我们在项目中的实践,分享一下我们的思考。
我们先来看基于关系型数据库的数据源。关系型数据库类型多种多样,常见的如MySQL Oracle SQL Server PostgreSQL等等,如何支持这些数据库呢?
在大数据平台下,我们可以选择Sqoop或Spark的方案。得益于Java丰富的周边生态(Java语言提供了对于数据库访问的统一抽象JDBC,通过实现JDBC驱动器就实现使用统一的JDBC API访问数据,目前市面上几乎所有数据库都提供了驱动器实现),Sqoop和Spark都提供了完善的数据库类型支持。
Spark和Sqoop起步都很早,但Spark定位是通用的计算引擎,比起Sqoop只是定位于Hadoop下的数据导入导出工具而言,Spark的功能要复杂和丰富得多。在技术选择上,Sqoop基于MapReduce计算引擎实现,Spark的数据导入导出功能基于自身计算引擎实现。近几年,Spark由于其灵活性、高性能及成熟稳定的功能,越来越成为大家首选的数据项目框架。
如果查看Spark和Sqoop的代码提交频率,即可看到在活跃度上Spark优于Sqoop很多。
在功能性上,基于Spark的方案也不弱于Sqoop。
Sqoop支持了常见的数据接入需要的功能,如根据查询条件进行数据选择、并发数量控制、读数据时的事务级别、数据类型转换、增量数据导入等。在导入目的地上,可以支持Hive、HBase、文件等。
Spark同样可以支持这些功能,不过使用了Spark特有的术语,如:
根据上面的分析及我们的实践经验,相比Sqoop,我们会更推荐Spark来完成数据接入。
对于非关系型数据库的数据接入,在前一篇文章(非关系型数据库的数据接入)中我们进行了很多的讨论。
总结一下,对于无schema或者schema比较自由的数据库,有如下经验可能值得借鉴:
对于其他基于文件的数据源,可以考虑的做法是先将文件复制到数据平台HDFS,然后用Spark读取HDFS中的文件,然后再写入Hive(或其他)数据仓库。
数据接入可以简单的分为全量数据接入和增量数据接入。全量数据接入是指每天都将所有数据从业务系统复制到数据仓库,适合数据量比较小同时没有数据更新时间字段的数据表。增量数据接入是指每天将改变的数据接入到数据仓库,是最常见的数据接入方式。
一般而言,增量数据接入可以分为两个步骤完成:
听起来很简单,但是仔细分析一下,就会发现很多问题。
第一次全量数据接入需要应对所有历史数据,因此可能需要应对大数据量的问题。
后续增量数据接入需要注意数据接入的范围,通常是前一天所有的新增或修改的数据。这里面存在以下几个问题:
除了上面提到的问题之外,还需要注意的问题是如何应对失败。比如,某一天,由于业务系统和数据平台网络断联,此时数据接入随之失败,如何恢复数据导入任务呢?
如果业务系统允许或者存在从库,则可以随时重新触发任务。越早触发任务,丢失的数据更新越少。如果业务系统只允许在系统闲时进行数据接入,则只能在下一个可接入数据的时段重新触发前一天的数据接入任务。
从数据接入频率来看,目前多是T+1的方式,即每天定时数据接入。这样的数据接入频率一般可以保证第二天可以看前一天的数据。
在多数业务相对单一的互联网公司构建数据平台时,这个问题可能并不是一个值得关注的问题。
但是,对于很多相对传统的企业,他们通常拥有很多业务系统,不少系统可能开发于一二十年前并经过了长时间的逐步迭代,不同的系统可能由不同的供应商开发而成,不同的系统可能需要支持不同的业务线。基于这样的现实情况,谈论数据接入对业务系统的影响就显得很有必要,因为:
数据接入的一个重要目标是在尽量降低对业务系统影响的情况下完成。对于没有只读从库的业务系统,如何实现这一点呢?下面尝试对不同的数据接入任务进行分析。
全量数据接入时,由于需要应对所有历史数据,此时的数据量可能会非常大。我们在进行这一步时,通常要面对的是数千万行数亿行,数十到数百GB的数据。进行如此大量的数据传输,需要仔细设计方案。通常可以参考如下步骤完成:
除了以上问题,还需要考虑数据读取的并发数,如果并发太高,可能给业务系统造成很大压力。通常业务系统会控制数据库最大连接数,这也给数据接入时的并发数设置了限制。一般而言,并发数并不会成为数据接入速度的瓶颈,最大的瓶颈常常来自网络带宽。我们通常可以采用较小的并发数读取数据,通过设置Spark的numPartitions参数可以达到控制并发数的目的。
另一个值得借鉴的做法是,在数据平台搭建一个跟业务系统数据库同样的数据库(可视为帮助业务系统建立了一个只为数据接入使用的从数据库,下文直接称从库),用以辅助进行数据导入。这可以带来以下几个好处:
在我们的项目实践中,针对没有从库的Oracle业务系统数据库,我们用docker搭建了一个Oracle数据库用于充当业务系统数据库的从库,大大提高了数据接入的稳定性和开发效率。
在导入数据到从库时,可以忽略索引,这可以有效减少数据库需要使用的存储空间,也可以加快数据导入的速度。
在增量数据接入时,我们可以考虑新建一张数据库表来存储数据,并且只存储增量的数据,此时不仅可以大大减小数据量从而加快数据接入的过程,还可以用于应对潜在的数据Schema变更。
现在我们应该可以顺利把数据导入到数据平台了,那么导入的数据要怎么存储和管理呢?首先要找个地方存,那就是数据仓库(Data Warehouse,简称DW)了,通常以Hive数据库来实现。数据平台可以视为以数据仓库为中心存储的平台。
很多数据仓库建设的文章中都会建议我们设计一个专门用于存储业务系统数据的层,名为贴源层,或ODS(Operational Data Store)层。贴源层的数据需要保持和业务系统一致,不做任何的加工。
设计贴源层的好处是:
我们也同样建议设计一个贴源层用于存储来自业务系统的原始数据。相比多增加一层带来的数据存储成本,其优势非常明显。
如何存储数据呢?Hive数据库支持分区表,可以为数据存储提供支持。
简单来说,我们可以为所有业务系统的表增加设计一个分区字段用于存储当次接入的数据。此字段可以为整型或字符串类型,其值为数据更新时间。
如果按天进行数据接入,则存储数据更新的当天,比如可以存储为20210520。如果更频繁的每小时进行数据接入,可以将此分区字段的值扩展支持小时即可。需要注意的是,这里的分区字段值最好和数据更新时间对齐,这可以大大方便后续团队成员理解数据、查询数据,从而避免潜在出问题的风险。
分区字段可以很好的应对全量数据接入和增量数据接入的策略。增量的情况下需要注意,第一个分区为全量数据分区,通常数据量会特别大,而且数据没有历史。后续所有更上层的数据加工都要基于这个基本认识,比如:
由于数据接入的过程常常会涉及多张数据库表的数据读取,那么一个很自然的问题是,数据一致性如何保证?
这是一个数据仓库实现的难点,有很多种情况可以影响数据一致性,比如:
在实际的数据仓库建设过程中,由于数据一致性难以保证,我们常常会一定程度上忽略数据强一致性。这可能带来轻微的数据不准确问题,一般而言,这不会带来太大的问题。因为数据平台是主要是为了支持数据分析,而分析常常是统计意义上的结果,所以统计上不会由于有很小的偏差而带来大的影响。这些统计结果一般也是为支持公司决策,公司决策自然也不会轻易受到某一个数值的微小变化的影响。比如,公司的产品销量分析,即便有几笔订单由于数据不一致没有统计到最终的销量中,一般也不会带来太大影响。
虽然多数情况下的数据分析对数据一致性不太敏感,但是还是存在很多对数据准确性要求很高的场景。比如:
对于这类对数据一致性很敏感的场景需要如何处理呢?这里有一些建议。
一是可以尝试在一个数据库事务中读取所有相关表的数据。如果数据源对应的数据量较小,特别是对于增量数据读取,也是具备较高的可行性的。
二是可以配合业务系统一起实现高一致性的数据入库。如果有来自业务系统的配合,一致性相对更容易实现。比如,如果业务系统允许每晚停止服务(或停止数据修改,只允许读数据的业务)一段时间,则可以在停止服务(或只读)时进行数据接入。
三是可以提供补数据的机制。比如,如果我们发现某些统计指标与实际的相差几个数,可以提供一个流程来补充没统计到的数据。简单来说,这可以通过:1. 相关人员进行邮件确认;2. 在计算出来的统计值上面进行最终结果调整。当然,如果有比较充足的时间,也可以实现一个支持系统用于辅助实现这个流程。
总之,要实现更强的数据一致性,所需的成本也是更高的。好的一点在于,在实践过程中,我们常常不需要这样强的数据一致性。当需要保证很强的数据一致性时,可能需要综合具体情况来判断什么样的处理方式是更好的。
上面谈了很多关于如何接入数据,如何在数据仓库中存储数据的经验,其中很多都是基于一个基本假设,那就是这些工作是由一个独立的数据平台团队来完成。有的同学可能会有一个疑惑,为什么数据接入这件事是数据平台团队来做?是不是可以直接交给业务团队来做?业务团队来做这件事不是更容易吗?
这涉及到企业组织结构和团队分工的问题,实际情况常常十分复杂,每个企业都可能根据自身实际情况不同而不同。
一般而言,实际情况常常是由一个独立的数据团队来负责此类工作。原因在于:
如果说企业的数据平台建设已经比较完善,或者企业内部的IT技术能力较强,则情况可能不一样。在一些大型的以软件技术为核心的企业,比如一些大型的商业银行,他们的情况可能是这样:
此时,业务系统开发团队可能只需要通过简单的几步操作即可实现数据接入数据平台。如果是这样,通常不仅数据接入可以交给业务系统团队自己完成,甚至上层的数据开发、报表展示等工作也可以由业务系统团队完成。数据团队在此时的工作重点会变为:
所以,如果我们考虑数据团队的组织和分工,不同企业可能大不一样,但是可能又都是适合企业实际情况的。
如果是由一个独立的数据团队去完成数据接入以及后续的数据加工处理、指标计算等工作,这常常会带来一个问题,那就是需要和业务系统团队较为紧密的协作。这样的协作常常不够顺畅,为什么呢?究其原因,两个团队没有共享同一个目标。数据团队一般基于各业务系统的数据,计算指标,输出报表,或者建立机器学习模型进行业务分析等。其目标是支持业务分析或支持决策。而业务系统团队的目标是开发新功能,维护系统稳定,支持业务运转。
目标不一致会带来很多问题。比如,数据团队觉得优先级高的事情,在业务系统团队看来优先级很低。更具体一点的例子是,如果业务系统中没有数据删除,那么数据接入就可以较容易的实现,但要使得业务系统保留所有数据,这给业务系统的开发带来了更多的看起来没必要的麻烦。
如何缓解两个团队的矛盾呢?一般情况下,可能需要数据团队做出一定让步,因为在数据的价值还没有体现出来时,从企业角度来看,我们需要优先保证业务的正常运转。然后,在此基础上,数据团队可以引导业务系统团队人员进行数据消费,帮助他们认识数据对他们的价值。包括:
总体上看,要想两个团队能友好的高效的合作,还需要双方求同存异,共同为企业大的目标一起努力才行。这可能需要更多的企业文化建设工作。
数据接入的过程中常常还会伴随很多其他问题,这里列举一些比较典型的问题,与大家一起讨论。
我们在进行数据接入的时候,业务系统团队担心他们数据库变更对数据平台造成影响,可能会建议由他们提供API进行数据查询,而不是直接提供数据库访问接口。
在我们看来,由业务系统开发API进行数据导出并不是一种好的方式。主要理由是:
当然,通过开发API(或数据导出任务)的方式进行数据对接也有其好处,那就是两个系统间的接口相对稳定。但是相比其带来的成本而言,这个优势显得不够明显。
比开发特定API接口进行数据对接要更好一些的是,业务系统可以开发数据导出任务,定期运行此任务导出数据。这会给业务系统团队带来一定的开发成本,但是不失为一种保障业务系统稳定运行的好的方式。
此时,我们会建议使用强类型的专用的数据导出格式,而不是基于csv。比如,如果业务系统数据库是MySQL,则考虑使用mysqldump工具进行数据导出。如果是Oracle,则考虑使用exp/expdp工具。如果是MongoDB,使用mongodump。
使用专用的数据导出格式的好处是:
如果使用某种中间格式,比如csv,其问题在于:
在实际的项目实践过程中,我们耗费了很大的精力在应对csv格式的数据接入这件事上,最后的结果也不尽如人意。所以,一般而言,我们会强烈建议避免使用中间文件格式进行数据接入。
虽然开发数据导出任务进行数据接入这种方式看起来不错,但是综合起来看,更为推荐的方式还是直接进行数据库对接,比如:
当前很多云服务提供商也发布了很多相关的数据接入软件,使用这些软件,通常只需要简单的配置即可实现数据接入其云上的数据平台。那么我们是否可以从这样的工具或服务中受益呢?
现在的市场上有大量类似的数据产品存在,但是,事实上通常这种数据产品在很多企业中难以落地实施。经过上面的分析,可以知道,很多情况下,数据接入这个问题并不是技术上可以直接解决的。
这里面涉及:
综合以上这些因素考虑,我们不应该被一个看起来很好用的数据接入UI界面所迷惑,而是应该立足企业具体情况,根据情况选择更合适的方式。
本文从数据接入策略开始,依次讨论了数据接入对业务系统的影响,数据应该如何在数据仓库中存储,接入的数据的一致性,团队组织和分工等问题。其中,分享了很多来自我们的真实项目实践中的经验。
数据接入到数据平台是数据平台构建的第一步,也是极为关键的一步。在实际项目过程中,我们常常需要花费大量的时间在这一步上。为了应对各种数据接入的挑战,我们需要保持清晰的认知,综合考虑各类因素,以便找出最优的解决办法。
基于在多家企业多个项目的经验总结,我们沉淀出一套企业数据开发工作台,可以帮助团队高效交付数据需求,帮助企业快速构建数据能力,工作台地址:https://data-workbench.com/
我们开源了其中的核心模块–ETL开发语言,开源项目地址:https://github.com/easysql/easy_sql