美团点评数据平台融合实践
本文根据作者在2017年ArchSummit的分享记录整理而成。
背景
互联网格局复杂多变,大规模的企业合并重组不时发生。原来完全独立甚至相互竞争的两家公司,有着独立的技术体系、平台和团队,如何整合,技术和管理上的难度都很大。2015年10月,美团与大众点评合并为今天的“美团点评”,成为全球规模最大的生活服务平台。主要分布在北京和上海两地的两支技术团队和两套技术平台,为业界提供了一个很好的整合案例。
本文将重点讲述数据平台融合项目的实践思路和经验,并深入地讨论Hadoop多机房架构的一种实现方案,以及大面积SQL任务重构的一种平滑化方法。最后介绍这种复杂的平台系统如何保证平稳平滑地融合。
两家公司融合之后,从业务层面上,公司希望能做到“1+1>2”,所以决定将美团和大众点评两个App的入口同时保留,分别做出各自的特色,但业务要跨团队划分,形成真正的合力。比如丽人、亲子、结婚和休闲娱乐等综合业务以及广告、评价UGC等,都集中到上海团队;而餐饮、酒店旅游等业务集中到北京团队。为了支撑这种整合,后台服务和底层平台也必须相应融合。
点评App和美团App的数据,原来会分别打到上海和北京两地的机房,业务整合之后,数据的生产地和数据分析的使用地可能是不一样的。同时,随着公司的融合,我们跨团队、跨业务线的分析会越来越多,并且还需要一些常态化的集团级报表,包括流量的分析表、交易的数据表,而这些在原来都是独立的。
举个例子,原点评侧的分析师想要分析最近一年访问过美团和大众点评两个App的重合用户数,他需要经过这样一系列的过程:如下图所示,首先他要想办法找到数据,这样就需要学习原美团侧数据平台元数据的服务是怎么用的,然后在元数据服务上去找到数据,才能开始做分析。而做分析其实是一个人工去做SQL分解的过程,他需要把原点评侧的去重购买用户数拉下来,然后发到原美团侧的数据平台,这个环节需要经历一系列的操作,包括申请账号、下载数据、上传数据,可能还会踩到各种上传数据限制的坑等等。最终,如果在这些都走完之后想做一个定期报表,那他可能每天都要去人工处理一回。如果他的分析条件变了怎么办?可能还要再重新走一遍这个流程。
所以他们特别痛苦,最终的结果是,分析师说:“算了,我们不做明细分析了,我们做个抽样分析吧!”最后他做了一个在Excel里就能做的去重数据量的分析。我们作为平台开发的同学来说,看到这个事情是非常羞愧的。那怎么办呢?
在经过一些磨合后,我们得出一个结论,就是必须进行数据口整合。
融合实践
确立目标
我们定了一个整体的目标,希望最终是能做到一个集群、一套数据平台的工具、一套开发规范。但是这个目标有点大,怎么把它变的可控起来呢?首先至少看来是一个集群,也就是说从用户访问的角度上来讲,他通过一个Client或一套用户视图就能访问。工具方面至少明确已有的两套,哪些是新的员工进来之后还需要学,哪些是未来会抛弃掉的。最终,让大家认同我们有了一套数据平台规范,虽然这套规范短期内还没有办法做到完美。我们做的这些权衡其实是为了从整体上能将问题收敛。
但即使我们把这个目标缩小了,想要达到也是很难的。难点在哪呢?
难点
架构复杂,基础设施限制
如上图所示,整个数据平台基本上分为数据接入、数据开发、数据分析、数据输出等等几个阶段。我这里只列了其中涉及到跨机房、跨地域的部分,还有很多数据平台产品的融合,在这里就不赘述了。在两个公司融合之前,原点评侧和美团侧都已经在同地域进行多机房的部署了,也都很"默契"地抽象出了离线的机房是相对独立的。在线的业务机房不管是通过消息队列还是原点评自己当时做的Blackhole(一个类似DataX的产品),都会有一系列数据收集的过程、对应任务的调度系统和对应的开发工具,也会有一些不在数据开发体系内的、裸的开源客户端的跳板机。虽然架构大体一致,但是融合项目会牵扯整套系统,同时我们有物理上的限制,就是当时跨机房带宽只有10Gb。
可靠性要求
由于团购网站竞争激烈,两家公司对于用数据去优化线上的一些运营策略以控制运营成本,以及用数据指导销售团队的管理与支撑等场景,都有极强的数据驱动意识,管理层对于数据质量的要求是特别高的。我们每天从零点开始进行按天的数据生产,工作日9点,老板们就坐在一起去开会,要看到昨天刚刚发生过什么、昨天的运营数据怎么样、昨天的销售数据怎么样、昨天的流量数据怎么样;工作日10点,分析师们开始写临时查询,写SQL去查数据,包括使用Presto、Hive,一直到22点;同时数据科学家开始去调模型。如果我们集群不能work,几千人每天的工作就只能坐在电脑面前看着Excel……
当时的分析是这样,如果考虑回滚的情况下,我们运维的时间窗口在平日只有一个小时,而且要对全公司所有用数据的同学进行通告,这一个小时就是他们下班之后,晚上6点至7点的时候开始,做一个小时,如果一个小时搞不定,回滚还有一个小时。周末的话好一点,可以做4小时之内,然后做全面的通告,相当于整个周末大家都没法加班了,他们是非常不开心的。
体量
虽然没有到BAT几万台节点的规模,但是也不算小了,融合时原点评的节点数是500个,数据量是11个P;原美团的节点数是3000个,现在整体已经上6000了。这里有一个比较关键的数据就是每天生成的数据量,由于我们的集群上面以数仓的场景为主,会有很多重新计算,比如说我要看去年每月的去重,这些都是经过一些时间变化之后会进行重算的。它对于分析数据的迭代速度要求很高,我每天可能都会有新的需求,如果原来的数据表里面要加一个字段,这个字段是一个新的统计指标,这个时候我就要看历史上所有的数据,就得把这些数据重新跑一遍。这里的生成数据量其中有50%是对历史的替换,50%是今天新增的。这对于后面我们拷数据、挪数据是比较大的挑战。
平台化与复杂度
两家公司其实都已经慢慢变成一个平台,也就是说数据平台团队是平台化的,没法对数据的结果分析负责,数据平台团队其实对外暴露了数据表和计算任务这两种概念。平台化以后,这些数据表的owner和这些数据任务的owner都是业务线的同学们,我们对他们的掌控力其实是非常差的。我们想要改一个表的内容、一个数据任务的逻辑,都是不被允许的,都必须是由业务侧的同学们来做。两侧的平台融合难免存在功能性的差异,数据开发平台的日活跃就有100和240,如果查询就是每天作分析的日活跃的话,原点评和美团加起来有1000多。所以在平台融合过程中,能让这么多用户觉得毫无违和感是非常有挑战的。
综上,我们做了一个项目拆解。
项目拆解
数据互访打通
数据互访打通其实是最早开始的,早在公司宣布融合以后,我们两侧平台团队坐在一起讨论先做什么,当时做了一个投入产出比的权衡,首要任务是用相对少的开发,先保障两边分析师至少有能在我们平台上进行分析的能力。接着是让用户可以去配置一些定时任务,通过配置一些数据拷贝任务把两地数据关联起来。
在这方面我们总共做了三件事。
原始层数据收集
在原美团侧把原点评侧线上业务机房一些DB数据以及Server的log数据同步过来。这个时候流式数据是双跑的,已经可以提供两边数据合在一起的分析能力了。
集群数据互拷
集群数据互拷,也就是DistCp。这里稍微有一点挑战的是两边的调度系统分别开了接口,去做互相回调。如果我们有一份数据,我想它ready之后就立即拷到另外一边,比如原点评侧有个表,我要等它ready了之后拷到原美团侧,这个时候我需要在原美团侧这边配一个任务去依赖原点评侧某一个任务的完成,就需要做调度系统的打通。本文主要讨论大数据框架的部分,所以上面的调度系统还有开发平台的部分都是我们工具链团队去做的,就不多说了,下文重点描述DistCp。
其实Hadoop原生支持DistCp,就是我起一个MapReduce在A集群,然后并行地去从B集群拖数据到A集群,就这么简单。只要你网络是通的,账号能认(比如说你在A集群跑的任务账号能被B集群认),并且有对应的读权限,执行端有计算资源,用开源版本的DistCp就可以搞定。
这方面我们做了一些权衡:
首先是因为涉及到带宽把控的问题,所以同步任务是由平台团队来统一管理,业务侧的同学们提需求。
然后我们两侧集群分别建立一个用于同步的账号,原则是在读的那一端提交任务。什么叫“读的一端”?比如说我想把一个原点评侧的数据同步到原美团侧,原美团侧就是要读的那端,我在原美团侧起这个任务去读原点评侧的数据,然后写到原美团侧。这里的主要考虑是读端更多是需求端,所以,他要在他的资源池里去跑。另外,对集群的影响读小于写,我们希望对于被读集群的影响能尽量减少。
当然,这都是一些临时的项目,投入较小,但收益是磨合了两地团队。
Kerberos跨域认证架构
接着介绍一下认证部分是怎么打通的。原美团侧和点评侧恰好都用了Kerberos去做认证服务,这个Kerberos在这我不去详细展开,只是简单介绍一下。首先是KDC会拥有所有的Client和Server,Client就是HDFS Client,Server就是Name Node,KDC会有Client和Server的密钥,然后Client和Server端都会保有自己的密钥,这两个甚至都是明文的。所有的密钥都不在传输过程中参与,只拿这个密钥来进行加密。基于你能把我用你知道的密钥加密的信息解出来,这一假设去做认证。这也是Kerberos架构设计上比较安全的一点。
Kerberos不细讲了,下面详细讲一下Kerberos跨域认证架构。
一般公司都不会需要这个,只有像我们这种两地原来是两套集群的公司合并了才需要这种东西。我们当时做了一些调研,原来的认证过程是Client和KDC去发一个请求拿到对应Server的ticket,然后去访问Server,就结束了。但是如上图所示,在这里它需要走3次,原来是请求2次。大前提是两边的Kerberos服务,KDC其中的TGS部分,下面存储的内容部分分别要有一个配置叫krbtgt,它有A realm依赖 @ B realm这样的一个配置。两边的KDC基于这个配置是要一致的,包括其中的密码,甚至是包括其中的加密方式。那这个时候我们认为这两个KDC之间实际上是相互信任的。
流程是Client发现要请求的Server是在另外一个域,然后需要先去跟Client所属的KDC发请求,拿一个跨域的ticket,就是上图中1右边那个回来的部分,他拿到了这个krbtgt CREALM @ REALM。然后Client拿着跨域的ticket去请求对应它要访问Service那一个域的KDC,再去拿对应那个域的Service的ticket,之后再去访问这个Service。这个流程上看文档相对简单,实则坑很多,下面就讲一下这个。
上图是Kerberos跨域认证的一些要求。
首先第一个比较大的要求就是密钥的编码一致,这有一个大坑,就是你必须让两个KDC拿到的信息是一样的,它们基于这个信息去互信,去互相访问。然后krb5.conf里面有一些比较诡异的domain_realm策略,这个在你网络环境不一致的时候会有一定的影响,包括DNS也会影响这个。在你的网络环境比较不可知的时候,你需要做做测试,尝试去怎么配,然后在Hadoop端有两个配置需要做,分别在Server端和Client端配置即可。其中比较恶心的是说,在测试的过程当中,需要去看Hadoop的详细日志,需要开一下它的Debug,然后去看一下它真正请求的那个域是什么样的。因为我们翻代码发现,Hadoop底层有对log,Client去请求realm的隐改,就是说我认为我应该是这个realm啊,它为什么传出来的是另外一个realm?这个是比较坑的一点。
我们做完这个项目之后,分析师就可以愉快地配置一些调度任务去同步数据,然后在对应的集群上去关联他们的数据进行分析了。做完这个项目之后,我们两边的团队也相互磨合,相互形成了一定的认可。因为这个小项目涉及到了数据平台的每一个领域,包括工具链、实时计算、离线的团队都做了一些磨合。
集群融合
粗看起来,打通了数据平台,我们的大目标似乎已经完成了:一个集群、一套数据平台的工具、一套开发规范。把数据拷过来,然后重新改它的任务,就可以形成在统一的一套工具和规范里面用一个集群,然后慢慢把原来团队维护的服务都下掉就好了。事实上不是这样的,这里面有大量的坑。如果接下来我们什么都不做的话,会发生什么情况呢?
数据RD会需要在迁移的目标平台重建数据,比如说我们都定了,以后把原美团侧平台砍掉,那么好,以后都在原点评侧的平台,包括平台的上传工具、平台的集群去使用、去开发。这个时候,至少原美团侧的同学会说:“原点评那边平台的那些概念、流程,可能都跟我不一样啊,我还需要有学习的时间,这都还好”。但他们怎么迁移数据呢?只能从源头开始迁移,因为对端什么都没有,所以要先做数据的拷贝,把上游所有的表都拷贝过去。然后一层一层地去改,一整套任务都要完全重新构建一遍。
那我们有多少任务呢?
我们当时有7000个以上,后来超过8000个任务,然后我们平均深度有10层。也就是说上游先迁过来,然后下游才能迁。整个流程会变成数据表的拷贝,然后上线任务进行双跑。因为必须得有数据的校验,我才能放心地切过来,花的时间大概是拷贝数据1~4天,然后改代码加测试再加双跑,可能要3~5天。这里我们有一个流水线的问题,如上图所示,蓝色的部分只有一层依赖的,当然我把这个左边的ODS都迁完了之后,1层依赖的Task 1、Task 2、Task 3、Task 8中,Task 1、2、3就可以迁了,但是Task 8 还是不能迁的,因为Task 8依赖的Task 7还没过来。我再走一层,Task 4的负责人要等上游相关任务都迁完了之后才能干活,那整个这个迁移就纯线性化,我们大概估了一下,并行度不会超过50。如果是两地两份数据,这个项目的周期会变成特别长,会有长期的两份数据、两份任务。这个时候,第一是我们真存的下吗?第二是如果我要迁移出来那个方向的业务有需求的变更,我怎么改?我要两边都再改一遍?所以这个是非常不可控的。
那这个时候怎么办?
集群融合的问题本质
反思一下这个问题的本质,首先我们是不能双跑的,因为一旦双跑,我们必须有常态化的两份数据,然后衍生一系列的校验、存储量、切换策略等问题。所以我们必须得有一套数据,一套任务执行机制。后续任务的改变,不管是替换工具链上的东西,替换计算引擎,比如说让两边Hive、Spark和UDF去做一致化的时候,其实本质上是说对单个任务的修改,对每个任务灰度的修改就好了。
所以我们推断出,必须自底向上地去进行融合,先合集群,然后后续再推动上游平台和引擎的融合。
集群融合的解决思路
整体我们融合的思路是这样的,集群融合先行,两边的Hadoop的服务架构和代码先进行统一,其次拷贝原点评侧集群的Block,同步到原美团侧机房的两个副本。这里有一个大的前提,第一个是原点评侧的集群节点数相对来讲确实小,再一个就是原点评侧的机房确实放不下了,它当时只能扩容到10月,再往后扩就装不下机器了。
所以我们将原点评侧的集群,合并到原美团侧机房,然后进行拷贝和切换。我们让整个这个集群变成在原美团侧机房一样的样子,然后进行融合。我们会把上面的客户端和元数据统一,使得访问任何一个集群的时候,都可以用一套客户端来做。一旦我们做到这个样子之后,基于统一的数据、集群的元数据和访问入口之后,我们上面的工具链就可以慢慢地去做一个一个机制,一个一个模块的融合了。
简单总结下来就是四步:统一、拷贝、切换、融合,下面我们来展开说一下这四步。
统一
第一优先级要解决的是上图中标红的部分,两边的Hadoop版本是不一样的,我们需要将原上海侧的版本变成我们的2.7.1带着跨机房架构的版本。同时因为我们后面要持续地去折腾Hadoop集群,所以必须先把原上海侧的HDFS架构改全,改成高可用的。
这里有一个小经验就是,我们自研的patch对改的bug或者是加的feature,一定要有一个机制能够管理起来,我们内部是用Git去管理的,然后我们自研的部分会有特殊的标签,能一下拉出来。我们当时其实互相review了上百个patch,因为当时两个团队都有对集群,包括Hive等等这些开源软件的修改。这是统一的阶段,相对容易,就是一个梳理和上线的过程。接下来是拷贝的阶段。
拷贝
上图是最终的效果图,同步在运行的打通任务还是用DistCp,然后先把原点评侧的HDFS跨机房部署。但是这个时候原点评侧的YARN还是在上海机房。在这个过程当中,因为HDFS跨机房部署了,所以原新上线的DataNode可以承载更多在原点评侧集群的冷数据。这个过程是慢慢进行拷贝的,大概持续了4个月,中间长期都是10Gbps的小管子。
切换
这个相当于把原点评侧的NameNode(这个时候还没有彻底下线)切换到原美团侧机房,然后把对应的YARN重新启动起来。这里有一个小trick就是原美团侧机房的承载能力,大概是1000多台节点,是原点评侧的两倍,所以我们才能做这个事,最近我们刚刚把上海机房的节点迁完。
那整个集群的拷贝和切换是怎么做的呢?其实就是用我们自研的一套Hadoop多机房架构。可能做Hadoop集群维护管理的同学们对这个有深刻的体会,就是不时地就要从一个机房搬到另一个机房。设计目标是说我们一个Hadoop集群可以跨机房去部署,然后在块的力度上能控制数据副本的放置策略,甚至是进行主动迁移。
设计是怎么做的呢?整个Hadoop原生的架构其实没有机房这个概念,只支持Rack也就是机架,所有服务器都被认为是在同一个机房的。这个时候不可避免地就会有很多跨机房的流量,就如果你真的什么都不干,就把Hadoop跨机房去部署的话,那么不好意思,你中间有好多的调用和带宽都会往这儿走,最大的瓶颈是中间机房网络带宽的资源受限。
我们梳理了一下跨机房部署的时候大概都有哪些场景会真正引发跨机房流量,基本上就这3~4个。首先是写数据的时候,大家知道会3副本,3个DataNode去建pipeline,这个时候由于是机器和机器之间建连接,然后发数据的,如果我要分机房部署的话,肯定会跨机房。那我要怎么应对呢?我们在NameNode专门增加zone的概念,相当于在Rack上面又加了一层概念,简单改了一些代码。然后修改了一下NameNode逻辑。当它去建立pipeline的时候,在那个调用里面hack了一下。建pipeline的时候,我只允许你选当前这个Client所属的zone,这样写数据时就不会跨机房了。
这些Application在调度的时候有可能会在两个机房上,比如说mapper在A机房,reducer在B机房,那么中间的带宽会非常大。我们怎么做的呢?在YARN的队列里面,也增加zone的概念,我们用的是Fair Scheduler。在队列配置里面,对于每一个叶子队列,都增加了一个zone的概念。一个叶子队列,其实就是对应了这个叶子队列下面的所有任务,它在分配资源的时候就只能拿到这个zone的节点。读取数据的时候有可能是跨机房的,那这个时候没有办法,我们只有在读取块选择的时候本地优先。我们有一些跨机房提交job的情况,提交job的时候会把一些job里面的数据进行上传,这个时候加了一些任务的临时文件上传的是任务所在的目标机房。这里做一些简单的改动,最重要的是提供了一个功能,就是我们在拷贝数据的时候,其实用balancer所用的那一套接口,我们在此基础之上做了一层Hack,一层封装。形成了一个工具,我们叫ZoneTransfer,又由它来按照我们一系列的策略配置去驱动DataNode之间的跨机房的block粒度的拷贝。
上图是我们跨机房架构的架构图,下面的Slave里面有DN(DataNode)和NM(NodeManager),上面跑的同颜色的是一个App。我们在RM(ResourceManager)里面的叶子队列里配置了zone的概念,然后在调度的时候如大家所见,一个App只会在一个机房。然后下面黑色的线条都是写数据流程,DN之间建立的pipeline也会在一个机房,只有通过root去做的,DN之间做数据transfer的时候才会跨机房进行,这里我们基本上都卡住了这个跨机房的带宽,它会使用多少都是在我们掌控之内的。
在上线和应用这个多机房架构的时候,我们有一些应用经验。
首先在迁移的过程当中我们需要评估一点就是带宽到底用多少,或者说到底多长时间之内能完成这个整体数据的拷贝。这里需要面对的一个现实就是,我们有很多数据是会被持续更新的。比如我昨天看到这个块还在呢,今天可能由于更新被删,那昨天已经同步过来的数据就白费了。那我昨天已经同步过来的数据就白费了。所以我们定义了一个概念叫拷贝留存率。经过4个月的整体拷贝,拷贝留存率大概是70%多,也就是说我们只有70%的带宽是有效的,剩下的30%拷过去的数据,后面都被删了。
第二个是我们必须得有元数据的分析能力,比如说有一个方法能抓到每一个块,我要拷的块当前分布是什么样子。我们最开始是用RPC直接裸抓Active NameNode,其实对线上的影响还是蛮大的。后面变成了我们通过FsImage去拉文件的列表,形成文件和块的列表,然后再到把请求发到standby,那边开了一个小口子,允许它去读。因为FsImage里面是没有block在哪一个DataNode的元信息的。
这里需要注意的一点就是,我们每天都会有一个按天的数据生产,为了保证它的一致性,必须在当天完成。在切换之前,让被切换集群的NN(NameNode)进入SafeMode的状态,然后就不允许写了,所有的写请求停止,所有的任务停止。我们当时上线大概花了5~6个小时吧,先停,然后再去拷贝数据,把当天的所有新生产的数据都拷过来,然后再去做操作。这里最基本的要做到一点就是,我们离线的大数据带宽不能跟线上的服务的带宽抢资源,所以一定要跟基础设施团队去商量,让他们做一些基于打标签的带宽隔离策略。
融合
当我们把集群搬到了原美团侧的机房之后,又做了一层融合。想让它看起来像一个集群的样子,基本上只需要3步。首先是“把冰箱门打开”,把原点评侧集群的那个NN作为一个federation合到原美团侧的集群,只需要改cluster ID,去客户端改mount table配置,cluster ID是在元数据里面。第二个是对Hive进行元数据的融合。我们恰好两侧元数据存储都是用MySQL的,把对应的表导出来,灌到这边,然后持续建一个同步的pipeline。它是长期活动的,到时候把上传的服务一切就可以。
前面说的那个做了跨域认证的配置我们还是要拆掉的,必须进行服务认证的统一,不然的话以后没法看起来像一个集群,这个时候把原来的KDC里面的账号进行导出,之后逐步地去切换每一个配置,让它慢慢切到新的KDC。切的过程当中,我们各种请求还是有跨域情况的,我们认为两个域是一体的,是一样的。等切干净之后,也就是原来的KDC没有请求了之后,我们再把它干掉。
开发工具融合
集群融合结束后,我们就做了开发工具的融合。由于这个跟大数据基础架构这个主题关系不是特别大,开发工具都是我们内部自研的,涉及的程序也很复杂,是一个特别大的项目,涉及一系列复杂的工具,每个模块的融合、打通。所以这个暂时不讲了。另外我觉得比较有意思的是下面这一点,就是原点评侧的一个拆库,这个在很多公司的数据平台慢慢扩大的过程当中可能会用到。
原点评侧拆库
难点
先说一下背景,由于原点评和原美团整体历史上发展经验、周期和阶段不同,如上图所示,原点评侧的数据仓库是先有的Hadoop集群,后有的数据仓库平台,因此有很多平台完全没法掌控的私有库,但是他们对于数仓所在库的掌控是非常强的,所有的任务都在这一个大的Hive库里面,里面有七八千张表。而原美团侧是先有的数据平台,后来因为数据平台整个体量撑不住了,底层改成了Hadoop。同时在平台化的演进过程中,已经慢慢把各个业务进行独立拆分了,每个业务都有一个独立的私有库,简单来说就是库名和库名的规范不一样。我们希望能让这两套规范进行统一。
我们如何去做呢?
原来任务的内容大概是insert into一个BI库里面的一张表,接着select from BI库里面的某两张表,然后where group by。像这样的任务我们有七八千个,它们在我们平台上配置着每天的依赖调度。我们希望把它都改成下图中的样子。所有涉及到的这些表都需要改名字,说白了就是一个批量改名字的事儿。
改名字听起来很简单,实际上并不是,我们有近8000个这样的任务需要改,同时这些任务相互之间都有非常复杂的依赖。下图是我随便找的一个,原美团侧某一个任务所有上游和下游的依赖关系图,如此复杂,任务的平均深度大概有10层,这还是平均数,最严重的可能要有大几十层。如果我们改这里面的任务表达,就只能分层推动。但是,当我们每改其中一个的时候,可能上下游都得跟着改,具体是什么样子的呢?
下图是我们的原始结构,首先这里有一个大前提是每一个任务只对一个结果表。原始的结构中,a表只依赖o1表,b表依赖o1、o2,然后c表只依赖o2,它们之间相互关联。这时候我希望可以对库名和表名进行一次性的修改。那如果我们逐层地去改写怎么办呢?首先要先把最上层的mart表改了,而我一旦改上游的某一个表,所有跟对它有依赖的表都必须改任务内容。每推动一层改动,下面一层都要变动多次,这样一来,我们这个流程就非常受限。
刚刚那个情况基本上是类似的,就是说我们对它们的改动没法批量化、信息化、流水线化,所有的用户和数据开发们,需要跟我们去聊,最近改了多少,然后谁谁谁没改完,谁谁谁又说要依赖他,整个依赖图是非常大的,我们整个项目又不可控了。那怎么办呢?
解决方案
很简单,我们只干了一件事情,就是在Hive层面上进行了一波Hack。比如说我要让原来叫bi.o2的表未来会变成mart_b.o2,我就同时允许你以mart_b.o2和bi.o2这两种方式去访问bi.o2这张表就好了。不管是写入还是读取,我们只需要在Hive的元数据层面去做一层Hack,然后做一个对应表,这个对应表我们是有规范的、能梳理出来的。在这之后,任何一个人都可以把他的任务改写成他希望的样子而不受任何影响,他写的那些表还是原来的那些表,真正在物理上的存在还是bi.什么什么这样的表,我们整个项目就run起来了。
具体的实施流程是这样,首先先梳理业务,确定整体的映射关系。然后Hive元数据入口上去做别名能力,我们是在Hive metaserver里面去改的,大部分请求都在这里面,包括Spark的、Presto的、Hive的等,都能兼容掉,推动分批次改写,单任务内以及任务链条内完全不需要做依赖关系的约束,最终真正实现的是自动化地把SQL文本替换掉了。业务的同学们只需要批量看一个检测报告,比如说数据对应上有没有什么问题,然后一键就切了。
我们用了一个季度业务侧来磨合、尝试练习和熟练,同时做工具的开发。然后第二个季度结束后,我们就完成了7000多个任务中90%SQL任务批量的改写。当任务都切完了之后,我们还有手段,因为所有的请求都是从Hive的metaserver去访问的,当你还有原有的访问模式的时候,我就可以找到你,你是哪一个任务来的,然后你什么东西改没改,改完了之后我们可以去进行物理上的真正切分,干掉这种元数据对应关系。
物理上的真正切分其实就是把原来都统一的库,按照配置去散到真实的物理上对应的库上,本质还是改NN一个事情。
总结与展望
未来——常态化多机房方案
我们目前正在做的一个项目,就是常态化地把集群跨机房去跑,其中最核心的就是我们需要对跨机房的数据进行非常强的管理能力,本质上是一个Block粒度Cache的事情,比如说Cache的击穿、Cache的预热或者Cache的等待等等,都是一个Cache管理的事情。我们会引入一个新的server,叫zone Server,所有的Client请求,NameNode进行块分布的时候,调整和修改。之后大家会在美团点评技术博客上看到我们的方案。
反思——技术换运营
数据平台做起来是很痛苦的,痛苦在哪儿呢?第一,数据平台对上层提供的不只是RPC接口,它要管的是数据表和计算任务。所以我们做SLA很难,但是我们还在努力去做。第二,就是最开始的时候一定是基于开源系统拼接出来的,然后再到平台化,这一定是一个规范的收敛,也是限制增多的过程。在这个过程中,我们必须去推动上面应用的、不符合规范的部分,推动他们去符合新的规范。平台的变更即使做到兼容,我们的整体收尾还是要尽快扫清的,不然整个平台就会出现同时进行大量灰度、每一个模块当前都有多种状态的情况,这是不可维护的。
综上,我们定义了一个概念叫“可运营性”,推动用户去做迁移、做改动是一个"运营的事情"。可运营性基本上的要求如下。
- 可灰度。任务的改动是可灰度的。
- 可关门。当某一刻,我不允许你再新增不符合新规范的任务、表或者配置,我们内部叫“关门打狗”,就是说先把新增的部分限制住,然后再去慢慢清理老的。
- 进度可知。清理老的我们需要有一个进度可知,需要有手段去抓到还有哪些任务不符合我们新的规范。
- 分工可知。抓到任务的分工是谁,推动相关团队去改动。
- 变更兼容/替代方案。我们肯定过程中会遇到一些人说:不行,我改不动了,你deadline太早了,我搞不定。这时候得有一些降级或者兼容变更的一些方案。
那我们什么时候去使用技术降低运营成本呢?前面已经有两个例子,就集群的迁移和融合,还有Hive表别名去帮助他们改任务名,这都是用技术手段去降低运营成本的。
怎么做到呢?
第一是找核心问题,我们能否彻底规避运营、能不能自动化?在集群融合的过程当中,其实已经彻底避免了运营的问题,用户根本都不需要感知,相当于在这一层面都抽象掉了。第二,是即使我没法规避,那我能不能让运营变得批量化、并行化、流水线化、自动化?然后当你抓核心问题有了一个方案之后,就小范围去迭代、去测试。最后还有一点,引入架构变更的复杂度最终要能清理掉,新增的临时功能最后是可被下线的。
体会——复杂系统重构与融合
最后稍微聊一下复杂系统的重构与融合。从项目管理的角度上来讲,怎么去管控?复杂系统的重构还有融合本质上最大的挑战其实是一个复杂度管理的事情,我们不可能不出问题,关键是出问题后,对影响的范围可控。
从两个层面去拆分,第一个层面是,先明确定义目标,这个目标是能拆到一个独立团队里去做的,比如说我们最开始那四个大的目标,这样保证团队间能并行地进行推动,其实是一点流水线的思路。第二,我们在团队内进行目标的拆分,拆分就相对清晰了,先确定我要变更什么,然后内部brainstorming,翻代码去查找、测试、分析到底会对什么东西产生影响,然后去改动、测试、制定上线计划。
内部要制定明确的上线流程,我记得当时在做的时候从11月到12月我们拆分了应该是有11次上线,基本上每次大的上线都是在周末做的,10、11、12月总共有12个周末,一共上线11次,大的上线应该是占了7到8个周末吧。要提前准备好如何管理依赖,如何串行化,然后准备上线,上线完怎么管理,这些都是在整个项目管理过程当中需要考虑的。
其中,两个可能大家都持续提的东西,第一个是监控,要知道改完了之后发生了什么,在改的时候就像加测试用例一样把改动部分的监控加好。第二要有抓手,如果我线上垮了,这个时候重复恢复的成本太高,也就是完全重启、完全回滚的成本太高,我能不能线上进行一些改动?
最后这张图,献给大家,希望大家在对自己系统改动的时候,都能像这哥们一样从容。
下一章:Android漏洞扫描工具Code Arbiter
目前Android应用代码漏洞扫描工具种类繁多,效果良莠不齐,这些工具有一个共同的特点,都是在应用打包完成后对应用进行解包扫描。这种扫描有非常明显的缺点,扫描周期较长,不能向开发者实时反馈 ...