一、痛点
让我们先来谈谈 DataWorks 当前遇到了哪些痛点,这些痛点是倒逼着我们进行技术变革的源动力。
1.1 沉重的历史包袱
首先要提的就是历史原因遗留的各种问题,DataWorks 历d M p W c 7 o z [史上多个版本同步开; 6 } ^发,前后端k ( E % C 5 技术栈多次变革,应用一旦上线就很难废弃,一个对, m f外暴露的 api,很可能是 5 年前开} y ; f ! 8发的,但依然有业务在依赖,通常情况下连这些古老业务的负责人都找不到了。当我们的服务正常运行的时候f ; m ? b,无人搭理,一旦下线,则. 3 ! V v X c X 3可能不知道从哪儿跳出几个用户前来投诉。页面上的功能同样如此,有时候只是过去不知道哪位同学开发中引入的一个 bz F 6 vug,但也因为我们的用户基数庞大,而变成了真理。历史上曾经出现过的隐藏的很深且用户寥E r u `寥的功能点都有自己的忠实拥趸,一旦被我们的开发不小心忽视而做丢了,就会迎来投诉和工单,所以 DataWorks 平b U g台不愧是千锤百炼磨练出来的大数据开发平台的标杆,朴素的界面之下隐藏了无数细致入微的功能点。如果想重造这么一个被阿里巴巴经济体无数数据开发工程师验[ p .证(折磨)过的数据开发平台,都要好好考虑一下这十年来我{ K p A ~ f们的平台到底经历过了什么。
1.2 复杂的软硬件环境
DataWorks 面临的运行环境放眼整个阿里巴巴经济体都是及其罕见的复杂,为了混合云(即专有云)这种私有独立K h b l V S g [ c且封闭的环境,三合一版本之后我们必须放弃依赖弹内成熟的中间件体系,只能寻找那些同样在三个环境下都存在的技术来支撑。也因此,很多在某个环境下缺失的依赖,如果我们无法用开关的方式搞定,或者I i s 2 O n我们判断其复杂度不高,就会通过自研或者去依赖一些开源的体系来解决问题。而公有云上各种网络环境的问题几乎都要靠人肉去排查,从每天居高不下的答疑量上就能看到我们受环境问题的影响是多么耗费人力。除此以外,前不久中美贸易战带0 G $ j P N来的影响也传递给了 DataWorks 平台,运行环境需要匹配国产芯片,我们的进程不但要运行在 X86 指令集上,同样也要能运行在基于 ARM 指令集的6 Z J s S E a j a国产芯片k 8 R P上。同时为了满足部分中小企业用户的购买欲求,敏捷化也是我们需要去N ? B l e裁剪设计的。
DataWorks 平台虽然庞大且复杂,但在种种更加复杂的软硬件环境下,也同样需要能够做到灵活轻便,便于随时随地的拆散组合轻装上阵,以满足不同业务场景下用户的期望。因为挑剔的用户一贯希望用最少的钱购买到最合适的解决方案,DataWorks 的竞争力显然也要* L [ T ] _从灵活且具备演变能力上寻找未来。
1.3 牵一发而动全身
工程之间的复杂关联一直是传统 SOA(Servich K 9 Y j P - %e Oriented Architecture:面向服务架构)发展到一定规模后的噩梦,无论^ j - I 3 J R 最初的设1 f * : | r计是多么合理,多么领域清晰,一旦经历需求的Q O 7积累,规h g ` h Q模的扩张,人员的q R m 0 d ; R W交替,都将逐步或多或少的面临着边界模糊的问题。最: r T e W W c e 8典型的例A U 2 G d子就是单体服务之间的 RESTful 类型的 API,往往这些 API? W f E v D ] h 的 Schema 只能增加元素而不能减少,因为被依赖者并不知道有多少其他服务正在依W W d (赖这个接口,也许某一天某个服务z R k p 7 W ( |从沉睡已久的服务器中被唤醒,结k _ n W Q p z . ?果发现你的} d P O y API 的 Schema 变了,那么一定会把你喊回来修C A 0 _回原来的样子。前后端分离架构下,这类问题更加突出,所以有的前端同学为了减少 schema 变动带来的影响,干脆让! Y u D l后端透传[ G p t G一个大字符串,即使里面夹带了私货,也不会使得页面莫名崩- 1 1溃。DataWorks 平台也正在经历着这一过程,发展到一定规模后,每个功能的改动都要小心翼翼,生怕对其他| } t [ u n # e h模块造成未知的影响,或者有时候我d E f们需要把大量时间投入在调研6 6 E ? x 清楚改动带来的影响上,就算这样严防死守,也依然可能有漏C b B 6 7 G网之鱼,最后功亏一q 0 q *篑,一个故障单就可能把为之付出的努力付之一炬。
1.4 需求变更和频繁发布
除了工程架构上的问题,同样存在问题的还有众多开发者在合作方面产生的问题,gitlab 帮我们解决了版本之间的代码冲突问题,但并不能解决产品发布周期上的冲突。当多- 4 5 j l /个需求都要对外发布上线,尤其在混合云,需要按月为周期产出大版本,我们一边要快速上线新 feature,一边还I s f要按照类似瀑布模型的方式将这些功能打包进专有云版本。弹内、公有云、混合云的发布节奏截然不同,众多 feature 按照不同的节奏要出现在不同的版本迭代中,过去的熔断机制,更加剧x L g c p A Q }了大家在窗口期集G M w [ ? : s n中发布而产生的风险。在 SOA 中的一个单体服务上,N 个开发者开发的 M 个 feature,按照什么样的间隔组合发布上线,使得发布的节奏既不过于频繁,也不会因为发布频次太少而使得版本跨度太大。如w h $ W果这 M 个 feature 之间又存在依赖关系,则进一步放大了发布频次增减之间的矛盾。
1.5 国际化带来的O I a - Q问题
国c w } . : ?际化的问题向来不F c h * X简单,时区、夏令时、语言、习惯、本地化图标等等,对于 DataWorks 这样一个遍布全球 20 个 region 的平台来说,这里面的水深的很。我们团队在国际化方面沉淀很多积累,并且将这些优秀的经验对外开源: https://github.com/alibaba/react-intl-universal 。
1.6 依赖耦合
基于 SpringBoot 的 Starter,我* ) + $ _ b ` n V们提升了代码的复用率,且对S 7 v 4 4 _于 Starter 的精心设计,确保同学们自研踩过的坑不需要反复由不同的同学来踩。但是这毕竟是不同工程9 ` x O中的共] Z Y同依赖,当这些 Starter 暗藏 bug 的时候,凡是使用到这些依赖的工程都将受其影响,甚至某位同学不小心在修改某个依赖甚广的 Starter 的时候写进了 bug,就有可能触发系统雪崩。
1.7 笨拙的灰度机制
我们V r . # y知道搜索引擎在不同的算法中寻找最优解的方法,是将这些算法灌装到不同的桶里,然后引流通过这些算法桶,通过各种指标的对比,将其中最优的算法挑选1 d d 0 ( / m / u出来。这是一种基于架构设计的灰度机制,并不需要人为干g r u & k预流量的导向,从入口处进来的不同搜索自- e d .然而然的就流过了不同的算法桶,随着海量的访问,最优解必然得以显现。但是目前的 SOA+ y P t 2 5 ~ ] 架构下灰度往往依赖于提前设计好的开关,DataWorkL b $ _ P / ! As 便是= j 0 ^ _ ? |如此,当我们需要验证某个功能是否存在问题,传统的办法是找到前端同学,让前端设计一N Z B q ?下开关机制,筛选一部分用户进入到新设计的功能里面,经过一段时间的试跑和调整,逐步把问题解决掉,同时对用户的影响也可以控制在比较小的范围。& d Q但这显然不是一个可以反复的,随意g T T b + l % M 5的,! 4 v自然而然的灰度机制。人为的干预,为灰度而耗费的设计开发,使得一次灰度的成本居高不下,有些时候我们的同学甚至因为想避免麻烦,而忽视做灰度验证。当我们想通过灰度来验证的功能非常的局部,或者用户无关,工作空间无关的时候,或者我们压根不知道哪些f C 1用户会使用到某些功能的时候,灰度机制也会在传统架构下失效,即使我们想去设计,也无从下手。
对于 SOA 下单体服务来说,灰度无法借助于架构的设计,但是 DataWorks 平台下底m J 4层调度服务 Alisa 的 Gateway 集群由于机R 4 6器数量庞大,也可以实现基于架构设计% ` } f M h S q (的灰度机制,几百台 Gateway 中,我们q c , ~ f可以取出一小部分,部= x ~ X 3 G署待验证的新版本,任务下发后通过不同版本的比对,寻找潜在问题。但? o s Q C d这并非 DataWorks 平台后端的常态,几乎^ r o 3所有单体服务并没有部署到这么多机器中,因此这也几乎是大多数 SOA 的状态,都面临着不能M o } L / W基于架构设计,而要基于人为干预的灰度机制。
1.8 外部关联服务的不确定性
外部| k ) B关联服务复杂多变,且不可靠不稳定,随- % ]时会宕机或者网络c M { 7 j I Q -中断,甚至是外部服务升级忘了通知r D / &我们,从而导致故Y o Y ; m障频繁。r A 9 L ` ) o Q这一点对于数据集成这样一6 i 3 : ~个在几十种引擎,数千个数据库实例中搬运数据的应用来说尤其深有体会。为了应对外界服务的不确定性,我们将有众多依- { X 5 +赖的自身应用设计的鲁棒性特别优异,然而这会增加我们自身代码的逻辑复杂度,偶然出现的问题也会被代码的鲁棒性掩盖,问题如果不及时处理,就会逐步积累,当所有出现故障的条件凑齐之后,一次性爆F & ~ + s . s o发一个 P1 级别的大故障。x - 4
1.9 紧缺的前端
DataWorks 研发平台还面临着前端人手不足的问题,这是富交互产z h I o ,品的研发团队都面临的共通问题。前端受制于交互的不同,+ @ p s样式的迥异,业务的区别,以及研发J $ } - $同学各自对业务理解上的差异,以至于能够复用的前端组件极其有限。在浩如烟海B 0 9 L = e S的前端类库、组件、样式中i , , . x,能够实现成本转移的寥寥可数。在前后端分离,基于T Q X C 5 _主流前端框架的设计模式下,相较于历史上的前后端一体设计体系下的用户体验是有提升的,然2 T k N K而这都是基于前端开发同学辛勤的劳作,一点点的调整样式和交互换来9 d A A g 8的成果,这里从来没有捷径可走,而我们只能寄期望于能够复用前端开发同学的研发成果,让每一次设计都不要成为只使用一次的劳动。
1.L | l 5 j G V1q U b0 其他
上面列举的几点G 7 t $ U R当然不是 DataWorks 研发平台面临的所有问题,还有一些不算那么紧急的痛点经常时不时的会出来提醒我们。比如在实际日常工作中,我0 R s | 1 M $ 4们常常希望能够上一些实验性质的功能,让一部分用户尝鲜,通过埋点取得用户的使用情况,给 PD 做参考,但这类工作量往往不小,是需要额外花费精力的。f H N w : S N再比如,数据开发工程师提出的需求,经过 PD 的翻译b I D Z T再经过研l t W S e j : o发同学的理解,往往就变了味,这时候某些有余力的数据开发团队就干脆自己来| C s v % & X实现,他们希望能直接在我们的平台上开发他们需要的功能,如果我们短期无法提供,他们就干脆自己来做个门户,集中自研工具集来满足自己的需求。这些问题不一而足,都需要我们改变自己的架构设计,[ j U B 3 Q O a来迎合弹内外用户的个性化需求。
二、合| ] b j m $作与l N n = v z竞争
DataWorks 研发平台众多功能涵盖了数据开发工程师的日常工作,用户在我们的平台上长年累月的伏案工作,对一些功能点的设计有自己的切身体感,而这些体感是我们平台的研发感受不到的。PD 和我们的 UED 去收集需求去使用去亲自感受,然而毕竟不是专职于数据开发本身,因此很难体2 1 r J a , u会到数据开发工& K i程师长期使用后的那种细微的挫败感。再到细分的垂直业务市场,不同行业下如何使用我们平台,差异更是有天渊之别。面向金融,银行,政府,大型国企,互联网公司,传统企业` V s P 1 8 o K,民营,教育,等等,他们的用法都是完全不同的,有的行业甚至就不知道拿到 DataWoru ? d & nks$ ] J p S o N o j 平台后该做什么。用户的需求千差万别,用户的心智也处于不同阶段。
因此,在我们无暇一一顾及的领域,前方的交付团队或者公司,使用 Da8 ? h 2 7 ^taWorks 平台应用到具体的行业中,然后再将行业的专属需求带回给我们的 PD 进行分析。我们平台本身也会开放| m J f w - D a /一些 Api 给予前方团队包装成产品提供给特定领域的客户,帮助客户解决实际问题。
新的产品规p y { / ! T划还在不断制订之中,引擎n I k ] p I 8 m团队设计好} E Y }自己的产品也需要在 DataWorks 平台上降低用户$ / , G & ~的上手难度,如果永远只是 DataWorks 平台的开发同学按照_ B [ 排期逐步完成这些接入和订制需求,平台注定难以持续发展壮大。因此,从前后端架构层面= * q 2 3 Z @,从无数的合作和竞争场景出发,都迫切需要我们进行C w u G 3 r一次针对自身的技术革命,彻底从 SOA 中解放生产劳动力,引入更多的用户侧的研发力量,帮助平台向V = F x K更健全的方向发展。
三、架构的变革
任何x X 4 $ v一种技术的变革都是循序渐进的,这和 Spring 之父 Ra dodg 9 y e / $ [ / j Johnson 秉持的理念是一致的。他提出了“轮子理论”,也即“不要重复发明轮子”,这是西L B ? 3 Q ] 1 : D方国家的一句谚语,原话是:Don’t Reinvent the Wheel。除此之外a f y v I y ),通过长期的实践后他在著作中总结阐明了循证架构的思想,即“没有最好的架构,只有最合适的架构”。这是架构界进化理论的雏形,意味着我们的架构要不断的演进去配合多变的业务需求。
传统的 SOA 下,服务趋向于稳定和集中,单体服务之间是平等W d u - ? e l u的,或者至少在共通的结构上是类似的,服务与服务之间通过网络通信进行依赖。SOA 下每个单体服务可能是多个开发者围绕着进行合作开发,因此替换任何( A o @ L r一个单体服务都是一件伤筋动骨的事情,当有大的技术栈的变革,例如从 WebX 3.0 升级到 SpringMVC,从 SpringMVC 升级到 SpringBoot,人力成本消耗都是巨大的,升级周期动辄以年为单位,更不用说假设我们想用 Go 语言或者 Python 的 Django 框架来替换 J2EE 体系下已b ; | D经设计好的 web 服务,这几乎是n x { a L k 1不可能完成的任务。也意味着当我4 i l L C W们进入了这n l Z c I { c . 个技术体系j k G W,就很难再j d q w x从这套体系中脱身,更无从谈起架构的演变和进化。
在传统 SOA 下,提升工程效率的c 9 l I ? i m 2手段是极致的代码复用,凡是可复用的代f | e码,都抽取到二方包中设计成类库让不同的单体服务依赖调用。s v | b V 9 {虽然配置越来越复杂了,但4 3 [的确减少了“重复发明轮子”的事情。
还有一个办法,是如我在 2015 年时候尝试新 . s R z / 3 (的架构设计时候采取的方法,即:能抽象成二方包的抽象,不Y } 2能抽象的通过自动化代码生成工具自动生成。一套演练成熟的 SOA 架构工程,从目录结构到配置组装都几乎是稳定不变的,即使有变化,也都是按照 MVC 三层架构进行微调,因此我们可以把一些无法抽象的,或者包含了复杂逻辑,需要灵活调整的代码通过自动化代码生成工具来生成,并且尽可能冗余代码的功能,让开发者从生成的工程代码中尽量做减法或者根据 8 b P 6 ?业务逻辑只修改最少量的代码,从而提升了工程的整洁度和开发效率。
除了D l N Q t ] 7 %代码的复用,还有服务的复用,我们^ 8 H *设计了一些中心化的单体服务,用于将复杂逻辑或启动较慢或需要缓存,等等这样一些功能封装在这些核心服务中,进一步减t / , t !少围绕中心服务的其他应用的体量和复% # 0 d p f , V杂度,当然这也可能会引入单点可靠性的问题,但要确保核心服务的稳定可靠,在一定规模的服务体量下并非难事。
即便如此,S@ , - E ^ U a & KOA 在效率上的提升依然是有限的,初期工程建立的快速高效并不代表长期业务开发后还能维持这样的效率G B a持续发展。前文描述的痛点逐步展现且缺乏行之有效的解决办法,开发者由于整齐划一的使% v l用同一套技术栈甚至同一套工程目录树结构,S a `虽然在协同的时候更加默契,但也消灭了前沿技术在团队内的赛马机制。研发同学W T m u e在一套逐渐古老落后的框架下研究怎么压榨出最后的效率和性能,D P U 0 q ( | F k但往往忽视了也许换个框架换个技术栈甚至换个语言,就会带来质变。因此,当基于谷歌的 K8S 体系成长的生态圈逐步成熟之后,遵循“没有最好的架构,只有最合适的架构”的思想,我们开始思考如何将 DataWorks 的技术方向转向灵活多变的微服务架构。
3.1 微服务架构
提到微服务,理所当然要和云原生关联,所谓云原生(Cl] 5 5 Y T l Moud Native),包含了如下三点:
1)DevOpsL : ! ? 6 : D ^
开发和运维不再是分开的两个团队,而是你中有我,我中有你的一个团队。
2)持f m 0 D b 0续交付
持续交付的意思就是在不影响用户使用! r 2 1 e L 2 -服务的前提下频繁把新功能发布给用户使用。
3)容器化
容器化的好处在于运维的时候不需要再关心每个服务所使用的技术栈,每个服务都被无差别地封装在容器里,可以被无差别地管理和维护。
满足上述三点的云原生环境,对于微服务来说天然适配。当一个产品发展到一定规模,且具备了足够体量,拥有数量众多的子产品,以至于交互和依赖关系日益复杂,则微服务架构将为这样的产品下的工程E ! % Z N 1 7群带来显然易见的好处。本文不对微服务的基本概念和泛泛的常规做法做详细介绍,网上此类文章汗牛充栋,这里仅推荐两p N s I | 6 n 2 )本不错的书《微服务设计》(前几章概念讲解还可以,后面部分一般)和《微服务架构设计模式》,前者适合初步了解,后者适合进阶。本文仅讨论 DataWorks 在新的架构下的做法,从实践中得真知。
对于 DataWorks 研发平台下众多产品应用来说,微服务架构方0 $ | 8 0 +向的改造也许不是能破解所有问题的万能钥匙,但一定是当前k ` a 7 A g q开发模式所遭受的病b 6 + s痛的解药。
★ 3.1.1 认清自身
DataWorks 研发平台属于典型的 PaaS 应用,当然也有数据服务这样的产品做到了 SaaS 层。传统 SOA 遇到的痛点,以及将来我们要对客户开放的定制化能力,需要借助微服务架构来应对,逐步将研发重心从 PaaS 移向 SaaS。
当我们采用基于 K8S 容器化的微服务架构之后,开发者可C ) 1 n Q以在我们自主研发的微服务平台中集成g P Y f ! G 0 2 8 Da& w 6 t LtaWorks 平台开放出来的基础 OpenAPI,也s r t q a - l E可以集成外部应用的 API,在微服务中进行数据整合和业务逻辑的编写,最终暴露出一系列在平台前端可访问的 API,供前端功6 ; N = f能模块使用。在这r . Q S e ! a o个过程中,我们可以顺便化解前文提到的一些痛点{ ; ( i + 5 k v 。
★ 3.1.2 解决痛点
以历史包袱为例,我们可以逐步将年久失修的,陈旧的 SOA 单体服务中包含的功能进行替换,将这个快变质的大饼切割成一个个低耦合的小饼,实现逐步的更替,而非采用长周期的一次性整体替换。陈旧的工程不必再去发展更新,仅维持基本的p F q s O运行,避免了整体替换带来的周期长,故障多,回滚困难的问题。而且我们可以很方便的通y S D # 7过金D ^ O F丝雀发布来验证新上的“小饼”是否成功替代了“变质大饼”中一小部分模块的功能,通过蓝绿@ A x E P u B部署将有问题的小饼快速及时的撤下,也可以做到通过 ABTest 来验证哪 u I块小饼的性能更好、设计更合理。
再以个性化需求为; ) V T 0 Y H例,当我们开放了和 DataWorks 业务耦合的微服务平台z . D,具备自研能力的业务团队(如数据 / 报表开发团队)就可以借助微服务的设计,快速的将自己的需求设计到我们 DataWorks 平台后端,同时前端页面我们也会留出“自留地”(下文描述的插件化)供业务7 o ( Y % a团队自行设计开发。引擎的接入同样可以A ^ }参照此模式进行,DataWoq V 0 :rks 下一部分模块的接入可以更加的傻瓜化,比如检查器,比如功能强大的自定义s & M c 2 z b : c节点等,用户根据文档经过简~ G 4 ! = A ^ * &单的开发后就可以快速自w l a R 7 + %主接入使用,但对于更加订制的功能,例如当前 ADB 引擎正在 DataWorks 平e | w Q ~ $ p D台上进行的可视化建表部分的设计,由于复杂度很高,因此必须通过微服务对接前端插槽(下文描述)5 v g T H来进行开发,从而实现复杂业务逻辑的自. S 3 - [ ~ b主自助接入。
再来描述一下基于架构的灰度机制,在微服务架构Z v 1 e X p 4 . {下,可以轻松的实现蓝绿部署,金丝雀发布和 ABTest,我们的微服务设计应该是尽量面向领域的(当然不太可能做到 100% 的面向领域),高内聚低耦合依然S e V l = ? Q 3 h是单个微服务的设计宗旨。我们可以发布多个版本的微服务用来测试某个领域的问题是否得到某方面的改善,也可以发布多个完全基于不同框架甚至是不同语言设计 L i J , 3 8 B u的微服务,来验证某个领域内谁是最优解。借助于基于架构的灰度机制,基于云原生,这一切都将非常高效且可靠,即使出现问题,也可以快速撤下有问题的微服务,避免扩大影响。
还有其他一些痛点,不一一描述基于微服务架构的解法,比如牵一发而动全身的问题,在 DataWorks 平台全面构建到微服务架构上之后,这个问题自然就会消失。每个同学都可以分管多个面向领域的足够小的微服务,E o 4 W j D o ) P当某个接口需要重新设计,不必立即替换老的接口,而可以将这个接口下对应的微服务低成Q u q 5 l本的重新设计,等待流量切换到新的A n ^ U , _微服务后,再逐步下线旧版本微服务。再比如 SpringBoot 下由 Starter 引入的耦合性,到了微I t ; s W X :服务框! ~ W (架下,将会通过服务发现来解耦,不s I v再需要通过代码层面的依赖来耦合关联。
★ 3.1.3 循证架构
再回过头来讲讲本0 * v文还没提及的一块内容,我们的微服务到底是什么?微` w G A H * }服务当然不是一l [ [ b定要以微小为特征,它还是一个 SOA,只不过会更加轻量级更加面向领域。以机器人3 3 k工厂为例,该产品有一个功能是x s m 7 q l让用户配置一些意图跳转到用户自己设计的应答逻辑中,这部分正在拥抱微服务架构,完成上线后,用户可以根据输入来设计自己的应答微服务,且语言无关。这样做还可以避免用户的微服务在设计不良的情况下崩溃,不至于影响到其他正在运行的微服L c * ` B c c v务,机器人工厂的这个场景也j 4 W e w @ R 8 B可以设计成 FaaS,用户只需要编写函数就可以完- ^ U g = !成自己的b 8 v d J应答逻辑,且按访问量来计量使用情况。
机器人工厂应用微服务
DataWorks 团队设计的微服务平台,充分拥抱了现在大热的 Service Mesh,即服务网格,通过 Mesh 将一部分工作封装在前置的微服务里,这些系统级微服务与开发者设计的微服务运行在同一个 pod 里,使得开发者设计的微服务更加简单,Mesh 更像是 Sl u [ rpring 框架下的8 / 9 @ % ^ E = C HandlerInterceptor 或者 Filter,面向 AOP 编程的~ + s ; 1 = Y h -开发者擅长在工程里开发拦截器和过滤器,到了集成了 Service Mesh 的微v R } ` ] e p服务框架下,可以方便的使用系统级微服务替代一部分传统拦截器的工作。比如登陆跳转、权限控制、服务发现,比如限流、监控、日志聚合等等。
Service Mesh
让业务专注于业务本身,避免诸如登录配置、日志配置等对工程开发的干扰,同时我们还设K 2 q X ~计了不同语言的 DMF(DataWorks MicroS8 L S ? # Aervice FrameWork)框架群/ r E U x # k,帮助开发者快速上手微服务的开发。“没有最好的架构,只有最合适的架构”,将来我们也会开放 DMF 的开发设计,让更多业务方贡献自己M p n M 3 ! _的“最合适的微服务框架”。为了更好的支持和我们业务强相关的 DevOps,我们开发了 DataWorks 微服务平台(DMSh L OP:DataWorks MicroService Platform),用于管控微服务的部署和发f ; 6 { 8 ^ 1 h }布,以及服务治理等其他运维工作。
3.2 前端的体系配合
前面提到的插件化指的是我们前端团队设计的 XStudio 插件化方案,插件结合后端微服务,成为一套整体的解决方案,DataWorks 平台的前端团队希望基于此Y | W _ U L,尝试探索出( j t 7 - .一套提升前端研发效率的方法论。XStudik e { H ` { ] Do 插件化基于 single-spa 和 qiankun 框架实m H C [ g + r l x现。该框架提供了多实例模式,插槽机制和可视化插件编排等重要特性,进一步提升了插件开发的效率。整套插B s U l件化的示意图如下:
前端同学在基于 XStudio 插件化设计的页面上,留好插槽,插槽里面可以是一个按钮,也可以是其他任意s _ 0 v S 8 7 ; ^类型的组件,这个组件后面绑定一个微服务,我们可以将插槽里面的内容连同后端的| ] S s M y v I G微服务一并替换,实现页面功能的快速组装,从而实现一次开发的多处使用。同时,插槽里的内容也可以由业务开发团队来提供,那么业务开发团队也只需要自行设计前后J ] H 0 v F % 9端一体的这样一个插件来放置到前端插槽里,实现个性化需求的订制开发。
在传统的插件化设w E d J m计里,开发者们要么提供一个遵循某种接口协议的二方包、要么提供一系列遵循某种协议的Q v ; r API 再由 SOA 架构向前端输出。这带来的问题要么是对 Sr ^ ~ Q v X @ w aOA 服务有侵入,要么影响了 SOA 服务整体的安全性和稳定性问题,要么受限于编程语言、要么毫无灵活性,而微服务 & 插件化完美的解决了这类问题。
对于需要占用更多页面空间的设计,我们可以将大片区域设置成可替换组件,比如上图的编辑器部分,让用户自行替换掉这片区域的页面内容,跟后端一个或者多个微服务关联起来嵌入到 DataWorks 的前端页面中,方便业务B ] T V b J T ]团队实现更复杂的自定义业务逻辑。当前 ADB 的可视化建表部分的设计Y ^ k u E E g正是遵循了这套方案,由 ADB 引擎团队自行开发接入 DataWorks 平I r 0 & w y台中。
同时,前端体系中还有重要的一环X 9 W _ ]是受访的数据监控和报警,我们设F ! F q h a I V 7计了各种维度的报表和指标监控,无论是自己的业务还是外部业务团队写进来的组件,不用多写一行代码,都可以通过7 H = b“自动化全量埋点技术”,观察和了解组件的| l 3 Z q y % s使用情况。
热力图
3.3 插件的运行
当前我们已经将部分前端基于 XStud, ? ^ oio 架构的组件与后端微服务配合起f F C V 0 ~来实现了插件化封装,比较优秀5 = I的如 Terminam a ,l,DW1 } i M ` . { XEditor,目录树,检查器等插件。以 Terminal 为例,该插件设计完成后,插入到不同的 Studio 中对接不同的引擎,并且可以根据用户的使用情况自动拉起或者销毁容器实例,从而节省运行资源。
Terminal 插件接入到多个引擎,无论是前端还是后端的微服务都不用针对引擎进行额L ; % k !外的开发,从而实现开发效率的提升。插件化的封装设计,不仅可以节约开发资源,而且可以L ^ ] L 7实现多个应用集中使用一套微服务的目的,而弹性编排和自动扩缩容机制保证了服务的性能,同时不至于浪费机器& k L ( S g 1资源。
Terminal 插件的架构设计图
此外,基于微服务架构,我们还可以构建 SaaS 的Q : R i { i 4 N一些实现P g G E ! _ ) f,例如 FaaS、BaaS(Backend as a Service),以及 BFF(Backend For Frontend)。以 BFF 为例,移动端的 D: n p 7 &ataWorks 应用 BFF 后,可以{ @ G q I /减少移动端 H5 页面的网络消耗,将后端多个微服务/ F a I * | | 6 O提供的接口通过 Gateway= N ~ 组装后提供给移动端,实5 m T ~ 8 o e ` G现微服务的聚合。如果通过 BFF 做了 SSR(Server Side Render:页面同构,相当于在服务器端直接渲染成 html 输出到浏览器),则可以进一步降低移动端的渲染性能消耗。
★ 3.r M B 9 F B . _ k3? [ L v m L.1 DataWorks 微服务平台
前后端一体基于 DQ j = [ 3 UataWorks 业务的插件化,也是我J ] S , s . k - ,们坚持要自研设计开4 2 b / e u j {发 DataWorks 微服务平台(DMSP:DataWorks MicroServG V 5 q W `ice Platform)的重要原因。DMSP 打通了前端组件的发布和后端微服务的绑定关联,通过 Swagger 这样的技术手段成功使得前后端在部署后可z @ X $ 3以迅速成为一个业务插件。让团队的前后端都可以在 DMSP 里面实现 DevOps,以持续交付的方式源源不断的将新功能发布给客户。
尤其值得说明的是,DMSP 同样是针对三大p A R z ? * v K环境的,即弹内、公有云和混合云# E z W = Y,插件开发完成后,我们要通过 DMSP 持续交付到公有云多达 20 个 region 的环境中,还要能够实现微服务在专有云的统一打包部署。并且,DMSP 还要让开发插件的同学尽量对复杂的外界部署环境J s G m 0 9 p无感。
未来我们期望整个 DataWorks 平台的大部分页面内容$ ` 2 H d t u都基于插件化设计,从而解决前文痛点里面提到的问题:“灵m H f W活轻便,便于随时随地的拆散组合轻装上阵”。架构驱动的不仅仅是开发模式,而且势必还将影响到整个产品的蓝海。
四、构造生态
构造生态的重 8 : # D J { .要前提C ! h W } % P是要有竞1 9 = C m i争,要有优胜劣汰,构造生态的同Z f * T ) G时就是在构造可以演变,可以适用进化论的技术体系。作为“循证架构”的升华,微服务架构显然在进化方面更胜一筹,循证架构是一种自上而下用进废退的技术演进路线,而微服务架构则是一种自下而上优胜劣汰的技术演进路线。容器化实现了语言无关,框架无关,每个] E E w @微服务都被无差别地封装在容器里,从而可以针对一个功能开发出多种微服务,类似算法桶的优选机制,从这些完成同一Q f ^个功能w C K [ F l的微服务P r B |中挑选出最优解。在理想情况下,无需上层架构师的主动干预,应用就可以在一段时间的进化后自组装成最佳的实践。当然这只是理论上的情形,我们身处的现实世界受很多外界d h 9 y因素的干扰,实际情况下,受限于开发者的技术素养、外界依赖的参差不齐,甚至是受限于 KPI 的导向,都将使得这种理想下的最佳实践无法达成,但微服务架构给予了我们可以通过团队的协作和努力,从而无限接近理论中的最终解的能力。
在微服务架构下,前文提到Y Z L _ ( 2 b 2的垂直业务的定制开发也将成为一种可能性,面向行业的交付团队可以利: P 3 ]用 DataWorks 平台提供的插件化能力,为客户订制完全适配行业特征的智能研发平台。进而在 DataWorks 研发平台上营造一个有活力的创新生态圈,为客户提供更加丰富多彩的选择。架构将驱动整个生态圈的优胜劣汰,Y p ` X从而不断向更有竞争力的方向l 8 E p进化。
我们 Da1 u r ; AtaWorks 研发团队也寄期望于在这套架构之上,实现弹内弹外的共赢模式的合作,推动云智y v L } d H e Q )能事业群下的产品形成合力。
五、前后端组合拳
所谓架构,不仅1 l E I U是技术上的事情,同时也要对人力的分配组织提供整套的指导方案。在应用了微服务架构之后,DataWorks 研发团队的职责显然不能仅仅局限于日常的需求开发,作为微服3 0 b w ( q Z K务架构的倡导者,在推进架构的同时我也对团队的前后端职责进行了思考。首先前后端需要拉出一个框架小组,通过指导前端组件和后端微服务的设计来影响整个架构的进化,团队内需要有关注面向领域设计的研讨,分, + V d * c @析每个插件是否是领域性的,同时需要有把关u 7 q d F的同学,审核第二方(弹内非本团队的开/ a 3 N发者)和第三方(弹外的交付团队或者来自客户的a ) _ | L行业开发者)提交的插件设计,防止不良应用破坏体系构建。
同时,微服务架构由于$ : G语言无关性,还抹平了一些技术上的鸿沟,n r s i A q c前端同学很多擅长 nodejs,也可以在微服务的设计中一展身手,更使前后端在技术上的交流和沟通会更加有默契。我们的产品线中还有一个特殊的产品:AppStudio,专职于 WebIDE 的研发工作,S z $ V w j ] } H将来无论是数据服务提供的数据出口,还是 FaaS 里的函数,还是微服务本身的开发,都可以与 AppStudio 结合,由用户自主开发,可以完全不用脱离 DataW[ ! K V b u torks 全g m j域大数据平台,; L V a | t 4 S就从数据开发到报表设计,再通过微服务编写业务逻辑,达成数据输出的目标,一站式完成用? 8 %户的订制需求。
架构驱动职责的转变
上图是未来的团队职责分工的一个构思^ P v H w Q C,前后端研发同学在这套组织架构下,打出一套组合拳,直击痛点问题,帮助用户攻克技术难关,实现生态的繁荣昌盛。
六、展望未来
技术和架构的未来是什么样子的?在我n O M z _ T的理想中,软件工程的研发技术应该是一个没有止境和边界,且越来R p : e 6 t [ % 2越智能化的领域。DataWorks 的产品中已经有很多开始向I : q 1 q N d c T智能化的方向前进,比如基* D 9 O V d于 VSCode 应用了 Markov 算法的智能编程插件。研发团队的未来很大程度上取决于体系的架构,我们应该鼓励创新,鼓励对技术前沿和边界的探索,不应该人为的制造太多规约从而限制了思考的天马行6 2 ^ J . J K空。如果有一天,智能化编程终于开始替代人工开发,那么通过改变架构的设计y i d A,研发人员也一定可以在新的架构中寻找到新的职责。
本文转载自公众J n u h + Q g y Q号阿里技术(ID:ali_tech)。