知道这个概念最近两年被炒的比较热,我是故意等热度稍微退一点之后再来聊这个话题的,其实早在7月初,我就曾受邀参加ITPUB和腾讯云联合举办的技术分享大会。作为分享嘉宾,会上分享的主题便是:大数据核心系统与数据治理。老实说,我一直不太喜欢去聊那些宽泛而虚空的话题,不能立马落地的东西,我一向是比较排斥的,比如这个所谓的数据治理。
首先,这并不是一个什么新潮的词,更不是引入的一项什么新技术,而是自从数据系统诞生之日起,就伴随着整个数据流转链路生命周期中,技术人必须要面对的数据在每一个接入、落地、计算、存储、价值传递过程中,对每一步的效率和合理性的思考。
我斗胆的认为:让数据在上述过程的每一步,都试图对其进行制约和管理,使其能够被高效、规范的利用,让数据价值达到最大化,就是所谓的数据治理。而且我还坚持的认为:对于一个大数据系统而言,设计合理的技术架构以及坚守开发过程中的各种规范,那么你的数据治理就根本不需要去额外操心,或者即便去做,也只是对系统的锦上添花而已。数据治理这个概念近年来之所以受到追捧,其本质原因在于太多公司前期在进行数据系统建设时,欠下了大量的【技术债】,一开始,公司高层都把目光盯在【出成绩】上呢,一味的只看数据的KPI。至于数据在流转过程中的流程管理、开发规范、存储规范、使用规程,不好意思,又不能直接给公司带来直接的经济效益,投资人也不care,管他呢,数据结果怎么快出来就怎么来。
另一个原因就是一些公司的技术团队的人员水平也都不咋地,能根据业务需要把需要的数据结果给你【倒腾】出来就不错了,你还想要他给你设计多么合理、鲁棒性多强的技术架构,遵守多么合理的开发规范,实属有点难为他们了。
说到底,现在提出所谓的数据治理,其实就是一帮企业想着如何给自己的数据系统【擦屁股】,因为再不去治理一下子,随着公司业务量的不断增多、要处理的数据量不断加大,系统不知道还能【苟延残喘】多久,说不定哪天就嗝屁了。
而数据治理如果只是想通过设立一个岗位,甚至雇佣一个团队来做,其成效未必有预想的那么好,从我目前了解的来看,几乎从事这个职位的人没有说不坑的,原因很简单,原始团队的开发们会觉得:能跑的就不要动、能出结果的就不要改。那些屎山代码、冗长的架构设计、不合理的存储,虽然很影响效率,但是这些东西可都是牵一发而动全身啊,谁敢轻易去动,谁敢去负这个责任?除非有上面大领导亲自挂帅、亲自授权、亲自监督。否则,很难真正去推行。要想从根本上做好数据治理,就一定要触及灵魂,而不是做一点隔靴止痒的表面功夫,比如优化个别代码,给某张表建个索引之类,这种顶多叫代码优化。作为一个还算设计过几个大数据系统的程序员,这篇文章就来谈谈在架构设计这个角度,如何在设计数据系统的每一步中,去思考数据治理如何落地。
大数据系统千千万,不同公司、不同部门、不同项目也都各不相同,那为了方便说明在做系统架构设计时,对数据治理的思考。
比较抽象,但是基本上能代表时下主流的大数据系统架构,或者说任何一个复杂的大数据系统,其架构都可以抽象成图中的这几个层次。
下面,将从系统设计的每一层出发,聊聊架构设计与数据治理的关系与思考。这个是数据系统架构设计的第一步,这一步设计的好坏,直接影响整个系统后续的数据处理效率,没有意见吧。
先思考数据源都有哪些,不同数据源的数据产生频率也会不一样,有的数据源是实时产生,有的数据源是一段时间生成一个文件等等。
那么这个时候就需要根据不同数据源的数据生成快慢,来确定是实时接入,还是离线方式接入。一般而言,数据源端跟大数据系统端分属于两个不同的系统,由不同的团队甚至不同的公司来管理。因此,这里面会涉及到一个数据接入主动权的问题,也就是数据源到底是数据源端推(push)给我呢?还是我大数据系统端主动去拉取(pull)呢?
对于很多系统设计者来说,可能都没有仔细考虑这一点,会问:有啥区别?
这种方式是由数据源端将数据推送给大数据系统,对于大数据系统端来说,就是被动接收的。
这种方式由数据源端根据自己的规则,将数据推送到大数据系统端,推送程序部署在数据源端。

特点为:数据源端掌握接入数据的主动权,接入速度完全由数据源端来控制,需要暴露大数据系统端的服务地址。1)数据源端有严格的权限控制,不能暴露自己的地址身份;2) 数据源端数据多且分散、数据生成频率很随机,想将数据第一时间送达大数据系统,用推送方式;3)跟拉取(pull)相比,用推送的方式更节省人工成本,比如数据源端本身就拥有数据推送的环境。
这个时候就是大数据系统端通过程序,直接请求数据源端的数据,将其拉入到大数据系统端,接入程序部署在大数据系统端。

特点为:大数据系统端掌握数据接入的主动权,接入速度由大数据系统端控制,暴露数据源端的服务地址。
2)大数据系统端对于数据处理的业务时间点相对苛刻,需要大数据系统端来控制接入速度;
3)数据源相对集中,接入程序部署在大数据系统端更好控制;
4)数据接入程序如果部署在数据源端,会对数据源系统造成比较大的侵入性,对数据源端影响较大;接入频率和接入方式确定之后,接下来就要确定如何选择接入程序了,首先要明确一点的就是,接入程序的目的是什么?
架起数据源端和大数据系统端的一座沟通桥梁,本身不存储数据,仅仅用于数据传输,这便是其目的。而接入程序的核心功能又分为:监控阶段,以及传输阶段。

至于接入程序,又分为:开源工具和自建API两大类。
Flume(可靠、Hadoop生态)、Logstash、Filebeat(ELK生态),Sqoop(Hadoop生态)、canal、dataX(阿里系)等等。
根据数据源的特点,同类型的选择一个足矣,一定不要噼里啪啦什么都要,否则,运维起来会哭的。
一般而言,数据源的数据定义和规范是各种独立的,甚至千奇百怪的,那么把这些异构系统的数据给接入到一个统一的大数据平台上来,想要它们乖乖的为你产生数据价值,那就得对其统一【驯服】一番。

1)共性业务字段统一命名:比如:start_time、begin_time、id、data、number等同意义的字段,用一种写法;
2)共性字段统一字段类型:比如时间统一用13位时间戳、数字统一用数值类型等;
3)添加统一的数据来源字段:比如source_id,来标记每张表的出处,有问题好追溯;
4)统一空值填充:用0或者””代替所有为null的值,防止后续程序处理时 出现的空指针异常;
5)异常数据提前告警:一般在数据接入大数据系统前,都会约定数据的schema,大致的数据量,以及一些重要的数据质量标准,这个就需要在接入的时候做好数据检查,看接入的数据是否符合当初约定的规范,如果没有遵守,就要在接入时第一时间进行告警,及时把锅给甩出去,防止此类数据入库,给后续的生产过程带来不良影响,把损失扼杀在萌芽处。
上文既然已经把数据从数据源给【接】出来了,那么下一步,自然想到的就是要把它给【落】到大数据平台的某个地方。而把接入的数据源放到大数据平台给“暂存”,或者“备份”起来,提供业务重跑,或者因为数据流量过大而为其提供缓冲的这种行为,就叫【数据落地】。
1)分布式消息队列:最常用的就是kafka了,当然,根据业务需要也可以选择其他的,主要用来存储实时数据,满足实时业务需要,对应上文的实时数据接入。
其特点就是:高效、实时;
2)分布式文件系统:比如HDFS,用于存放离线数据,简单的裸放,不带schema,对数据的及时性和数据的schema没有要求。
3)分布式数据仓库:比如hive,同样也是存储离线数据,但是比HDFS多了个创建schema的过程,可以提供较好的数据压缩,数据获取时的谓词下推等优点;
2.1 落地层的数据治理

2.1.1 对于消息队列
统一序列化方式,如果用普通的string,那么确定统一的分隔符,如果数据需要保证一定隐秘性,可以选择用自定义对象,自定义序列化的方式,这样即便数据在传输过程中被拦截,也不会直接暴露数据内容。
其次,为了后续计算引擎的效率考虑,可以将数据在写入消息队列前,根据业务字段提前分区,这样就相当于将一部分业务的计算前置,减轻后续的数据计算负担。
2.1.2 文件系统
比如提供统一的写入工具类、创建标准的目录结构,以业务为单位设定目录层级、以数据落地时间作为文件名的后缀等。
这样后续程序读取数据的时候,就可以根据这一标准复用一套规范的代码逻辑进行读取,不同数据根据参数自动调整,避免硬编码现象。
2.1.3 分布式数仓
拿hive来举例,在每项业务数据入库前,先确定如何分层,以及每一层的含义,数据粒度,是否创建维度层等。
其次,每一层的数据表是建内表,还是外表,是否让其支持ACID,如果数据在保存之后还需要对其进行改动,考虑内表,否则外表就够了。
再者,数据入库前,尽可能考虑分区、分桶这些可以提高后续数据查询的手段,思考哪些业务字段是每次查询必须用到的,比如日期,区域等字段来进行分区。
还有存储格式,用ORC还是parquet,或者其他格式,哪种更有利于你的业务场景。
最后,思考数据入库是用静态分区的方式写入,还是动态分区方式写入,这两种方式带来的效率变化,以及存储优缺点,小文件问题等,都值得你去花心思设计。
3. 数据计算层
数据落地考虑完了,就开始考虑对数据如何计算处理了,把落地的数据【捣鼓】成业务需要的结果,就是这层的核心目的,这一层主要用分布式计算引擎来完成。
计算引擎需要分别从上文提到的3个地方读取数据源,然后对其进行计算:

3.1 如何选计算引擎
这里面涉及到第一个问题就是如何选择适合自己业务的计算引擎?
目前主流的开源计算引擎有这几种:MR、Tez、Spark、Flink、Strom。
那么如何来选择,其实对于大数据技术发展到目前为止,基本上就是spark和Flink之争。
对于MR和Tez来说,现在几乎没有人用他们进行编程了,之所以还在用是因为他们作为一些OLAP工具的内置计算引擎而存在,于是排除。
再来看strom,虽然它是第一个真正意义上的开源实时计算框架,但是因为生态的没落,用的人也很少。
至于spark和flink,选谁?
都可以,都是当下分布式计算引擎的王者,都兼容离线和实时计算,选一个你熟悉就够了,只要你能玩好,一定都可以满足你的业务需要。
如果你让我选,现阶段,我毫无疑问选Spark,因为生态更成熟,兼容的开源组件更多,坑更少。
有人会说Flink才能玩实时,spark都是微批,我只能告诉你:你一定没真正玩过,那些只是你的道听途说而已,凡事要懂得实践。
3.2 计算层数据治理
这块其实非常大,因为对于一个大数据开发团队而言,其大部分的工作量都围绕在这块进行,数据计算层也是一个数据系统的核心。
关于这块的数据治理,因为不是针对具体案例,我也只能泛泛的聊几句:
1)开发规范:这个必须要制订,所有开发人员在开始干活前,必须都得熟悉一遍,严格执行,否则团队人数一多,你会发现各种【八仙过海各显神通】的类命名、变量命名,长度不一的方法、类和很多魔幻的代码操作;
2)制订合理的软件架构:对于一个大数据系统而言,一定会用到各种技术组件,以及很多第三方类库,那么在软件工程里面,就必须要根据一定的规范进行分层,比如组件功能,或者业务功能划分,否则各种功能都杂糅到一起,一旦某个地方修改,就只能牵一发而动全身,后期升级会非常痛苦;
3)代码治理:对于一些常用的公共模块,进行抽取形成工具类,比如我们在开发过程中很多时候就需要跟比如MySQL、Redis打交道,那么对于他们的连接池管理,各种数据操作管理,是不是可以提取出来形成工具类,避免一些水平比较低的开发,自己来实现这部分功能而把数据库搞挂掉。
这些可都是在生产中出现过的切肤之痛,一定要注意;
4)合理的try...catch:为什么把这部分单独拿出来说,原因很简单,因为曾经痛过,很多同学写的try....catch是不规范的,该try的不try,不该try的又乱try,这块如果管理不当,很多代码或者数据故障可能都暴露不出来,非常的坑爹;
5)建立统一的全局配置:这点也非常重要,我们知道,在开发过程中一定会存在跟各个服务地址打交道,这里面就一定会涉及到很多的ip、端口、用户名、密码等的配置管理问题,如果不能构建一个全局读取配置的方法,那么当项目人员一多,代码一复杂,就非常容易乱套。
尤其涉及到一套代码,需要跑在多个生产环境中的情况时,经常会搞错;
6)代码效率的治理:这点体现在代码的review上,如果数据处理的代码逻辑复杂度过高(包括时间复杂度和空间复杂度),不合理的高IO操作等,就需要对代码进行优化甚至重写。
这个作为一个大数据系统后端的最后一层,用来承接计算引擎所处理的所有结果。因为上一步是用的分布式计算引擎做的数据计算,那么为了满足良好的写入性能,较高的WPS,因此在大数据系统中的结果存储也会尽量选择分布式数据库。至于数据库如何选择,一般需要从下面几个因素来考虑:1)数据使用习惯:这个是在选择数据库时第一个要考虑的,因为只有当你知道了怎么用数据,你才能确定如何存数据,以及存哪里。
查询方式:比如普通的精确匹配,模糊匹配,全文搜索、还是聚合查询居多?查询频率:是高QPS还是低QPS,连接池管理复不复杂,吞吐量怎么样?
2)数据增量如何:根据业务特点估算出每天的结果数据增量有多少,然后需要保存多少天,是否存在冷数据和热数据的区别,是否需要有分区功能;
3)易用性如何:这里主要看其生态怎么样,跟上游的计算引擎的兼容度如何,有哪些可能的坑,api是否好用,团队对这个技术接受程度怎么样?上手起来复不复杂等等。
1)建表命名规范:统一表的命名规范,拼音还是英文缩写、驼峰还是全小写拼接;2)字段命名规范:所有相同的含义的字段类型,命名方式必须全局一致;3)单个表的大小规范:限制数据在写入到单个表时候,根据业务场景,单个表大小不能超过某个阈值,否则就要进行分表操作,这样就可以保证数据的查询性能;4)如果数据量巨大:需要思考存储分级,加入缓存等方案,比如热数据用SSD硬盘,而一般数据用普通SATA等;
5)存储结果校验:这个也是数据治理非常重要的一环,一般对于一些重要的报表数据而言,业务是需要对其结果进行验证的,也就是所谓的数据质量稽查。
一种办法是:可以根据历史数据来做这种数据量,或者某个业务统计指标的同比、环比的比较,比如波动指标在百分之多少以内算数据质量正常,超出阈值就要告警,代表数据有问题,需要第一时间去检查;这个虽然跟数据没有直接的关系,但是却能够提高整个大数据系统的效率,比如以下几点:1)对所有的数据处理任务设计统一的调度管理机制,记录每一步执行的操作日志,并进行统一的日志管理,当任务出现报错,第一时间能够找到对应的运行日志;
2)根据项目周期,制订合理的代码版本管理,以及代码回滚机制;
3)构建适用于整个项目的CICD自动化流程,尽可能减少手工操作,避免不必要的低级失误,提高代码发布效率。
下面是已经用在我的某个项目中的一个CICD的例子,供你参考:
好了,以上就是我围绕一个大数据系统的核心架构展开的,基于数据治理的思考,虽然还是有些抽象,但一直以来我都是这么干的。因为只有把数据治理这个理念植入到系统架构的各个方面,落实到每个细节中去,你的数据治理才能是最有效的、最根本的。
那种事后的缝缝补补,小打小闹根本无法从根上让一个数据系统真正健康起来。最后,希望这篇文章能对你在数据治理方面的理解有所帮助。