首页 文章 精选 留言 我的

精选列表

搜索[AI提效],共10000篇文章
优秀的个人博客,低调大师

Midway Serverless 发布 2.0,一体化让前端研发再次提效

自去年 Midway Serverless 1.0 发布之后,许多业务开始尝试其中,并利用 Serverless 容器的弹性能力,减少了大量研发人员对基础设施和运维的关注。对前端开发者而言,他们只需写几个函数即可实现后端业务逻辑,推动业务快速上线。去年我们也说,使用了 Serverless 的架构,可以让整个前端研发效能提升。 在 2021 年 3 月,我们推出了 Midway Servereless 的第二个大版本。就像两年前说的一样,开源只是开始,终态远没有到来。Midway 体系希望能够在当前的十字路口,不断向前演进,让前端可以去发展,朝着应用工程师前进。 Midway Serverless 2.0 的内部代号是“Hercules”,是希腊神话以及漫威中的大力士,藉由半神半人的出生,初步迈向成神之路。而我们,藉由用户在 v1.0 的使用情况,我们看到了不少问题,这一次 v2.0 的迭代重构,我们希望去解决这些问题,让用户体验和开发效率更进一步。 Midway Serverless 的演进 Midway Serverless 是 Midway 产出的一套面向 Serverless 云平台的开发方案。其内容主要包括函数框架 @midwayjs/faas ,以及一系列跟平台配套的工具链,启动器等。 在 2020 年初发布之后,在同年 6 月,又发布了前后端一体化方案,可以方便的在前端代码直接调用函数端代码,我们将这一体化方案应用到了集团的中后台项目,效果显著。 同年 9 月,我们发布了全新的 midway 应用框架的第二个版本,引入了组件生态,之后 swagger,typeorm,mongo,gRPC 等组件不断的孵化,大大扩充了 Midway 的能力。 在 2021 年 3月,我们发布 Midway Serverless 2.0,在原有的基础上,Midway Serverless 和 Midway 的能力将复用,有着相同的 CLI 工具链,编译器,装饰器等等。 Midway Serverless 2.0 的最大变化 就像前面提到的一样,Midway Serverless 是一套面向 Serverless 的解决方案,它包括框架,运行时,工具链,配置规范几个部分,这几部分的组合之后,提供了一些面向 Serverless 体系的特有能力。 传统 v1.0 时,我们主打: 平台间迁移更容易,让代码在不同的平台相同 让应用更易维护和扩展,提供了标准的云平台函数出入参事件定义 让传统应用无缝部署到 Serverless 环境 而 v2.0,我们主打的是应用函数一体,前端和后端一体,体验更加,开发效率更高。 原有的 v1.0 底层是通过编译,包含一个令人烦恼的 .faas_debug_tmp目录,不少开发的同学都踩过它的坑,一旦出错,难以排查。 这本质上,是由于没有采用和应用相同的进程重启方案,也是因为函数开发和传统不同,技术选型差异造成的。函数的执行和缓存,造成了 v1.0 数据可能不更新,经常出现改了代码无效的情况。 在新的 v2.0 中,我们彻底抛弃了原有的编译方式,采用了和应用相同的实现方式,同时又对函数场景做了优化,对用户来说,在某些场景下(HTTP),开发函数和开发应用是相同的结构和体验,函数和应用只有部署时有差异。 可以看看优化后的开发情况,不仅和应用一样,速度还比较快,也不会生成临时目录,修改实时生效。 这是 v2.0 和 v1.0 的根本性变化,也是整体架构升级带来的巨大优势。 当然,这一块并不是功能的新增,除了架构升级之外,我们还提供了更多的能力。主要分成下面四大方面。 v2.0 纯函数增强 首先,我们在纯函数开发的场景下,对 HTTP 场景的函数,包括(HTTP触发器,API 网关等)做了额外的增强支持。 v2.0 升级 - 装饰器统一 v1.0 时期,我们将触发器的各个参数定义在 f.yml中,虽然在云原生看来是标准的,但是实际在编写代码的时候,用户觉得非常繁琐,特别是加上我们的依赖注入容器中 @Func装饰器和类的命名,函数名 + handler 名 + 类名 + 方法名用户需要命名多遍。 v2.0 版本开始,我们直接沿用应用的开发方式,使用原有的 @Controller装饰器应用到 HTTP 函数的开发中。 同时,原有 f.yml里的 functions字段将不再需要填写,我们的发布工具会自动从代码中分析路由,注册函数。 除了 @Controller装饰器,我们也支持传统应用的参数装饰器,比如 @Query, @Body等常用的从请求中获取参数的装饰器,也支持例如 SetHeader, ContentType等对响应操作的装饰器。 除了装饰器统一之外,我们将原有的 @midwayjs/faas框架也接入到了新的 Framework 体系,现在 @midwayjs/faas成为了函数 Framework,它也拥有和应用相同的 Application, Context定义。比如下面的 app方法,和应用完全一致。 为了更好的支持函数式的写法,我们对入口的 configuration.ts增加了函数式写法,这样在一体化等函数式场景也可以选择函数是写法来编写。 v2.0 升级 - 工具链升级 从 midway v2.0 开始,我们使用 @midwayjs/cli作为我们的基础 cli 工具,原有的函数 cli(@midwayjs/faas-cli)将逐步完成它的历史使命,也将统一到 @midwayjs/cli 中。 传统的 cli 是把所有的功能都组合成一个大包,放到一个 npm 包下,这样每个应用都要装一份,比较占用硬盘空间和资源。新版本我们做了一个按需加载能力,按照场景进行区分,比如函数和应用场景安装的 cli 工具就会不同。 这样的好处是,新版本的 cli 安装的包比较少,自然速度就快。同时,也能够自由的去组合其中的插件,将其更合理的应用到不同的场景中。 v2.0 升级 - 单元测试 针对原有函数的单元测试的情况,我们也做了调整。 原来的 invoke方法,虽然简单,但是很难跟创建应用的流程结合,每次 invoke 都是一次完整的初始化逻辑和调用,而且在 HTTP 的场景下,要填写的参数众多,难以模拟实际的效果。 新版本,我们沿用了应用的思路,既然能用应用模式启动,那自然也使用应用的开发方式,使用 supertest 来做测试,比原来简单和自然多了。 v2.0 升级 - Web 模式 在 v1.0 时期,我们针对业界常用的 egg/koa/express,做了将应用代码无缝迁移到 Serverless 环境的功能,这三种框架都可以在 f.yml中增加 deployType的方式,通过构建自动化生成入口,支持传统应用上弹性容器的诉求。 之前也有用户问道,如果我代码不希望再跑在函数环境了怎么办?v2.0 的答案是,你可以将那些代码,通过应用的模式部署到自己的传统容器,或者 Docker。 部署的方式很简单,由于使用了 @midwayjs/serverless-app(上面测试提到过),和应用一样的编码模式,就可以启动一个 HTTP 应用了。 v2.0 一体化能力增强 去年 6 月,我们向社区开放了一体化编码的方案,使用函数式编码,类 React Hooks 的编码方式,让前端开发的同学无比熟悉。 在 v2.0 之中,我们进一步增强了这套一体化方案,让前端开发的体验进一步提升。从下面这四个方面,我们将一一为大家介绍。 一体化增强 - 极速启动 首先是极速模式,传统的 React/Vue 开发/构建的时间大家也都了解,Webpack 的工作时间往往接近 20s,而得益于最近新出的 vite,经过我们的测试和使用,传统的 20s 将缩减到了 2s 以下,可以说前端再一次得以飞跃。 而 vite 良好的兼容性,可以包容非常多的前端框架,虽然 vite 刚出不久,相信过不了多久,就会在全前端场景铺开。 一体化增强 - 单元测试 第二个方面是单测,传统的一体化,由于编译的存在,我们的单测十分困难,有用户不止一次的问我们,怎么做单测,怎么优雅的做前后端调用。 在新的 v2 中,我们采用了两种方案做测试。 即可使用 supertest 来执行传统的 HTTP 行为模拟做单测,也可以使用我们提供的 runFunction函数来做单测。 一体化增强 - 支持应用 第三个特性是非常令人惊喜的,一体化项目除了能在函数场景下使用,如今,我们也将其沿用到了应用开发上。传统的 Midway 项目也可以使用一体化方案开发了。 一体化增强 - 运行时升级 在 v1.0 时期,由于编译器的限制,我们的入口函数编写时有着诸多限制,但是在 v2.0 的时候,我们将运行时换成了原生框架以及原生的 node 模块,这样以前的种种限制都不存在了。 同时,你也可以编写自己的 hooks 模块,将业务逻辑轻松的组合到一起。 未来 Midway Serverless 2.0 提供了诸多能力的升级,但是还远远不够,我们依旧在不断提供新的能力,让不同的场景都丰富起来,让前端可以游刃有余的享受到新体系的红利。 未来,是 Serverless 和云的时代。 Github: https://github.com/midwayjs/midway, 欢迎到 Github 帮我们点个 Star~

优秀的个人博客,低调大师

阿里零售通 App 工程提效实践:提升 50% 的编译速度

前言 当前,大多数 Android 工程都是基于 Gradle 工具进行构建和编译的,一开始,当你的工程不够复杂,或者还只是小型项目的情况下,基本都不需要去关心构建优化的事情,而随着业务变得复杂、代码量的增多以及越来越多的依赖,原有的 单 module 工程变成了多 module 工程,构建时间变得也越来越多。 说到这里,有的同学可能会有疑惑,对于大项目来说,这么多模块和依赖,本来就需要更多的编译时间,还怎么减少构建时间?恰恰相反,实际上越大的项目越能省出来时间。 为了让开发者引起对构建分析的重视,Gradle 官方在最近的版本更新中推出了一个神器 build scan,可视化的深入分析和诊断所有构建相关的数据,并基于此分析结果帮助开发者找出构建问题以及针对构建性能进行优化。 背景 零售通买家端 App 是面向线下小店的一个补货工具,可以快

优秀的个人博客,低调大师

赋能平台、提效工具、场景化应用,地产大数据玩转有诀窍

在2017在线峰会——票选最美云上大数据暨大数据技术峰会上,来自明源云的刘峥分享了整个的地产行业的趋势以及探索应用实践。他主要从行业趋势和应用实践两个方面进行了分享。他详细的分享了数据管理平台DMP平台的基础层、画像层、算法层、展示层的架构设计,并通过应用场景诠释了大数据在地产行业的作用。 以下内容根据直播视频整理而成。 背景 上图是明源2017年产品整体的战略布局。最底层ERP,是20年来我们专注做的事情。从项目投资收益、计划、采购、成本、费用、售楼覆盖地产全生命周期的业务管理软件。4年前,明源开始通过阿里云做SAAS产品转型,随着SAAS业务的不断扩张、覆盖产生了很多平台的增值服务。随着SAAS业务及平台增值业务进一步扩张,从业务中积累的数据也越来越多,大数据业务就自然涌现出来。通过一年多的探索实践,大数据已经融入地产业务的方方

优秀的个人博客,低调大师

数据开发提效有秘诀!离线开发BatchWorks 六大典型场景拆解

回顾大数据的发展历程,一句话概括就是海量数据的高效处理。在当今快节奏、不断变化的市场环境下,优秀的开发效率已经成为企业数字化转型的必备条件。 数栈离线开发BatchWorks 是一款专注离线数据ELT开发的产品,采用先进的大数据生态底层技术,具备高性能且功能丰富的大数据处理能力,对大数据离线计算、数据仓库建设提供有效支撑,是企业建设数据中台、数据仓库,加速数字化转型的基础设施。 BatchWorks 经过6年多的打磨已经服务于包括金融、教育、政企、零售等多个行业在内的300+客户,在开发效率提升方面发挥了巨大的价值。本文将从多个项目实施过程中遇到的6个典型场景来介绍一下离线开发BatchWorks 在开发效率提升上的一些解决方案,与大家共同探讨。 场景一:大批量数据快速迁移 问:客户数仓计划从 Oracle 迁移到 Hadoop,初始化需要完成几万张表的数据同步,如何快速进行大批量 hive 表的创建并做数据抽取? 答:BatchWorks 支持连接数据源进行关系型数据库到包括 Hive 在内的多目标数据库之间的整库同步,可一次性完成大批量表的自动创建和同步任务的生成,支持按日期增量和全量两种数据同步方式。考虑到同一时间点启动大量数据同步任务会造成数据库压力过大,还可支持任务并发数的配置。 场景二:SQL 逻辑的复用和批量管理 问:一条业务线上有20+产品,每个产品的数据分析由一个 SQL 任务完成,所有产品的任务逻辑完全一致且需要保持变更同步,而实际业务在快速变化,数据开发每次调整业务逻辑都需要每个 SQL 任务分别手动变更,经常出现调整错漏的情况,如何解决? 答:增加“组件”功能,用户可把在大量任务中通用的业务 SQL 逻辑抽象出来作为组件进行维护,不同的产品只需引用组件并配置输入输出表和字符参数,即可快速完成任务配置。当业务变更时只要调整组件的逻辑就能实现所有引用此组件任务的同步变更。 一个简单例子:业务方需要对不同产品的用户群体做年龄分层,可创建组件做年龄筛选,配置以下输入输出参数: • 输入参数:数据来源表 • 输出参数:年龄层中的最大最小值(字符串)、数据输出表 实现从产品1中筛选出年龄为20-30的用户数据,在创建任务时选择上述组件配置年龄输入参数和数据来源表,并指定写入的结果表: 场景三:计算结果跨任务复用 问:任务存在上下游依赖时,下游任务可能需要直接使用上游部分任务的计算结果,同时用户不希望建太多临时表,或产生一些额外的重复计算,如何解决? 答:BatchWorks 支持了任务上下游参数传递功能,上游任务的计算结果可进行周期性存储,直接被下游计算引用。 一个简单例子:从业务库完成销售明细表数据采集清洗,按天汇总后将销售金额最高的门店数据输出 sales_1d 任务,从 sales_details 中通过输入参数获取日期数据,然后将当天最高销售数据对应的门店通过输出参数输出传递至下游的同步任务,同步任务筛选此门店数据同步至 oceanbase。 场景四:任务依赖自动解析 问:当任务较多且依赖关系复杂时,依赖关系的配置会占用一定的工作量,尤其在对任务做了修改后,依赖关系可能会有更新不及时/漏更新的情况,发现问题时往往已经到了下游环节,如何解决? 答:BatchWorks 支持了上游任务依赖自动解析推荐/自动依赖功能,选择此功能进行依赖任务配置时,平台将对当前任务进行 SQL 解析,得到来源表和结果表,并寻找来源表的产出任务,用户可从这些推荐任务里选择全部或部分任务添加到上游依赖,也可直接选择自动依赖,当 SQL 调整时自动进行上游依赖的更新。 场景五:任务异常快速排查 问:离线实例的运行流程涉及实例上游依赖检查、到达计划时间检查、资源检查、质量校验等多个环节,运行过程出现异常时仅通过日志难以直观地进行问题溯源,问题处理不及时直接影响下游业务,如何解决? 答:BatchWorks 支持实例诊断功能对实例的运行过程进行分析,将实例调度流程及每个流程当前的状态、节点时间全部展示,用户可直观地看到当前实例的运行阶段和异常原因。 比如在进行上游依赖异常检查时,BatchWorks 将构建以当前实例为末位节点的异常依赖树,寻找直接导致其未运行的根源任务组,快速直达阻塞点。此外针对 SparkSQL,可监控其指标健康状况并给出调参建议,针对 HiveSQL 可观测运行过程中资源使用变化情况,从而可进一步进行任务调优。 场景六:以用户组为单位的用户管理 问:某公司的数据开发团队不定期会有一些人员调整,因业务量大、开发项目比较多,人员调整后开发平台上的维护十分繁琐。例如有新员工入职,需要将其添加到相关的多个开发项目中并赋予不同的角色,任务告警值班时需要添加进对应的告警规则中等等,增加管理员的用户管理成本且容易缺漏,如何解决? 答:BatchWorks 的用户中心支持以用户组为单位的用户管理,每个用户可被添加进一个或多个用户组。项目添加用户、告警圈选用户时均可以用户组的方式进行配置。后续增删用户时仅需在用户中心的用户组内进行操作,即可完成人员->项目/角色等的快速调整。 《数据治理行业实践白皮书》下载地址:https://fs80.cn/380a4b 想了解或咨询更多有关袋鼠云大数据产品、行业解决方案、客户案例的朋友,浏览袋鼠云官网:https://www.dtstack.com/?src=szkyzg 同时,欢迎对大数据开源项目有兴趣的同学加入「袋鼠云开源框架钉钉技术qun」,交流最新开源技术信息,qun号码:30537511,项目地址:https://github.com/DTStack

优秀的个人博客,低调大师

提效降本,Spotify 为开发人员升级设备至 Apple M1

音乐流媒体服务 Spotify最近为其 Client Platform (CLiP) 团队升级到 Apple M1 设备。根据介绍,其 CliP 团队的核心动机是授权和疏通客户开发人员,并为团队提供他们需要的工具,以确保愉快和令人满意的开发人员体验 (DX)。与此相呼应,Spotify 表示,他们也希望通过改变基础设施来改善开发团队的编码体验。 Spotify每季度进行一次工程满意度调查,以确定降低开发人员整体满意度和生产力的障碍。其最近一次面向 318 名工程师的工程满意度调查结果显示,由于构建时间较长,开发人员的生产力和满意度受到了影响。基于此,该公司着手通过多项更改来缩短构建时间,其中之一就是为构建系统测试不同的硬件。最后分析发现,使用 Apple silicon 机器可以有更快的体验,同时还可以提升经济效益。 总体而言, Apple silicon 机器上的构建时间比基于 Intel 的 Mac 系统快 43%;在 Android 系统的构建中快 50%,在 iOS 系统的构建中快 40%。 验证过程 鉴于 M1 的处理能力,Spotify 先假设 M1 机器本地构建时间会显着改善。 AvgLocalBuildTime(M1) < AvgLocalBuildTime(non-M1) 实证结果 总体而言:Apple 芯片的速度提高了约 43%。 Android:Apple 芯片的速度大约快 50%。 iOS:Apple 芯片的速度提高了约 40%。 升级到 M1 是否有任何经济效益? 在三个月内实现收支平衡,每个团队的工程成本可能节省 36%。 因此,Spotify 方面得出结论称,“根据实证结果和我们的财务分析,升级到 Apple silicon 机器绝对符合我们的标准,并且是减少开发人员构建时间问题的可行解决方案。” 开发者反馈 —— 六个月后 为了衡量升级的成功与否,Spotify 从开发者体验、生产力感知以及任务成功三个方面对组织内 100 名参与的客户开发人员进行了调查。结果表明: 开发者体验 几乎所有接受调查的开发人员(约 98.8%)都将他们的开发体验评为 4 或 5,其中 5 是最佳体验分数。 生产力感知 大多数接受调查的开发人员(约 91.6%)将他们的生产力感知评为 4 或 5,其中 5 是最高的生产力评级。 任务成功 大约 83% 的受访开发人员在任务完成方面经历了积极的变化(4 或 5),其中 5 是最佳体验分数。 一些开发人员直接反馈称,升级设备以后构建运行得更快,等待时间更少,还有一些其他积极的体验。 结果总体上是积极的。Spotify 总结称,“创造积极的开发者体验仍然是我们的首要任务,我们从调查中收到的反馈表明,我们正朝着实现开发者满意度目标的正确轨道前进。” 更多升级详情可查看官方博客。

优秀的个人博客,低调大师

闲鱼架构如何一招提效30%?Flutter+Serverless 研发实践公开

阿里妹导读:Serverless(无服务架构)被誉为下一代云计算,自概念推出以来,因为能带来研发交付速度提升与成本的降低在业内异常火爆。闲鱼客户端基于Flutter进行架构演进与创新,通过Flutter统一Android和iOS双端提升研发效能之后,希望通过Flutter+Serverless 解决各角色间存在大量的协同,导致整体研发效率低,移动端离业务越来越远,服务端没有时间做底层领域沉淀的问题,从而进一步提升整体研发效率。 研发架构的演进 接下来我们带着这里两个问题回顾前后端研发架构演进的历史。 PC互联网早期没有还没有前后端的概念,此阶段单个业务需求通常一个开发人员可以完成研发,前端网页与后端逻辑都写在一个工程中。随着业务越来越复杂,原本开发者负责前后端研发已经变得效率低下,此阶段随着移动互联网的爆发,服务端需要服务与PC、Android、iOS等多种前端。 服务端总是有一个疑问:服务端设计接口时,是应该面向 UI,还是应该面向通用服务?一个方案是抽取一部分服务端做 BFF(Backend For Frontend服务于前端的后端),作为前后端之间的适配层,核心是解决数据的聚合与编排,重新探索更合理的分层协作模式。 服务端写BFF带来新的问题,总是包接口无法提升个人能力。如果BFF由端侧同学开发可以解决这个问题,具体技术方案也是接下来我们要思考的问题。 云端一体化技术方案 Serverless 由 BaaS(Backend as a Sevice)与 FaaS(Function as a Service)两部分组成。BaaS 主要包括数据库存储、消息队列等能力,针对复杂的需求建议由服务端在 BaaS 层封装领域服务供 FaaS 层使用。作为端侧开发,核心关注客户端与FaaS层的代码开发。 目前公司 FaaS 环境已经支持 Java、Kotlin、Swift、Dart、Node.js 等多种语言与框架,闲鱼通过 Android(Flutter)、iOS(Flutter)、FaaS(Dart Runtime)都使用Dart 达到语言一体,并且实现协议一体与工程一体。 语言一体:Android、iOS、FaaS层使用 Dart 语言开发,实现三端语言统一,有效屏蔽FaaS层语言学习成本。 协议一体:通过一体化框架屏蔽通信细节,前后端同一份State,减少协议转换,前端同学调用FaaS服务时,如同调用本地函数一样简洁。 工程一体:前后端可以在同一个工程中进行开发,利用Dart特性可以通过Hot Reload机制进行快速开发联调。 下单页一体化实践 下面以闲鱼下单页一体化为例,通过页面渲染与交互两部分展开一体化实践过程。 下单渲染一体化 从上图左侧可以看出,客户端渲染此页面需要在端侧请求5个接口,处理渲染接口之间的逻辑,把接口返回的Data转为为ViewModel。经过一体化改造之后,原有在端侧的逻辑都移到FaaS层,包括聚合5个领域服务,处理业务逻辑,进行字段映射与页面编排,端侧无任何渲染与业务逻辑,直接获取返回的ViewModel刷新页面。以下是云端一体之后的流程图。 下单页交互操作一体化 从上图右侧可以看出,有4种操作都会改变实付款,原本这些操作处理逻辑都在端侧处理,一体化改造之后,端侧不存在任何计算逻辑,客户端每次操作都会请求服务端,有FaaS进行红包是否过期等数据校验,再返回页面数据进行刷新。 一体化研发框架 Nexus Framework:基于Flutter的一体化移动端UI框架。Logic Engine:基于Flutter的一体化通信与调度框架。Nexus Server:基于Dart Runtime的一体化服务端框架。 代码示例 下图为客户端下单页初始化的代码示例: 下图为FaaS层对客户端发起的初始化请求的处理: 以上是Flutter+FaaS双端协议一体的开发示例,双端都是通过BinderAction进行交互,Action中的State是同一个类型,从而有效屏蔽通信细节,提高研发效率。 收益与效果 下单页已经上线,回顾整个研发过程,云端一体研发架构不仅仅只是新的技术方案,价值在于扩展端侧工作边界,带来生产关系的重塑。 协同效率提升:相比Flutter带来的双端一体来说,该三端一体的架构进一步提升了30%整体研发效率。 业务闭环:端侧还可以更快速地反馈与响应业务,不断尝试,从而搭建起更完善的产品模型,为业务创造更多的价值。 人员成长:端侧从只关注用户体验的开发资源,转变为整个业务研发的技术负责人,从只关注端侧的局部视角到更专注业务闭环的全局视角。Faas层调用底层领域服务来完成自己的业务,原来服务端可以更加地去专注领域服务的沉淀。 总结与展望 Flutter+Serverless 三端一体研发架构,能够解决本篇提出的原有研发架构的两个问题,通过改变端侧职能边界有效减少协同,客户端可以负责整个业务,服务端有更多的时间进行领域沉淀,但是闲鱼实践Flutter+Serverless三端一体研发架构时也遇到以下挑战: FaaS层研发体验需要继续提升、调试只能通过GAIA日志查看,目前规划是把平台日志抓取到本地,并且提供FaaS代码远程调试功能。 运维成本增加 问题定位、请求链路、压测、安全生产的工作转移,如何抹平与服务的差异。 以上是实践过程中发现的新的挑战,现在都已经列入到下一阶段的工作中,我们通过优化技术方案完成这些挑战。 原文发布时间:2019-12-27作者:古风本文来自阿里云合作伙伴“阿里技术”,了解相关信息可以关注“阿里技术”。

优秀的个人博客,低调大师

提效 7 倍,Apache Spark 自适应查询优化在网易的深度实践及改进

本文基于 Apahce Spark 3.1.1 版本,讲述 AQE 自适应查询优化的原理,以及网易数帆在 AQE 实践中遇到的痛点和做出的思考。 前言 自适应查询优化(Adaptive Query Execution, AQE) 是 Spark 3.0 版本引入的重大特性之一,可以在运行时动态的优化用户的 SQL 执行计划,很大程度上提高了 Spark 作业的性能和稳定性。AQE 包含动态分区合并、Join 数据倾斜自动优化、动态 Join 策略选择等多个子特性,这些特性可以让用户省去很多需要根据作业负载逐个手动调优,甚至修改业务逻辑的痛苦过程,极大的提升了 Spark 自身的易用性和灵活性。 作为网易大数据基础软件的缔造者,网易数帆旗下网易有数团队自 AQE 诞生起就关注其应用。第一个应用 AQE 的系统是 Kyuubi。 Kyuubi 是网易开源的一款企业级数据湖探索平台,它基于 Spark SQL 实现了多租户 SQL on Hadoop 查询引擎。在网易内部,基于 Kyuubi 的 C/S 架构,在保证 SQL 兼容性的前提下,服务端可以平滑地实现 Spark 版本升级,将社区和内部的最新优化和增强快速赋能用户。从 Spark 3.0.2 开始,网易有数就在生产环境中逐步试用和推广 AQE 的特性。而在 Spark 3.1.1 发布后,AQE 在 Kyuubi 生产环境中已经是用户默认的执行方式。在这个过程中,我们还端到端地帮助某个业务迁移了 1500+ Hive 历史任务到 Spark 3.1.1 上,不仅实现了资源量减半,更将总执行时间缩短了 70%以上,综合来看执行性能提升 7 倍多。 当然,AQE 作为一个“新”特性,在实践过程中我们也发现它在很多方面不尽如人意,还有很大的优化空间。秉着坚持开源策略,网易有数努力将团队遇到的问题和 Spark 社区分享,将我们的优化努力合进社区。以下章节,我们将展开介绍这半年多来 AQE 特性在网易的实践经验和优化改进。 AQE 的设计思路 首先明确一个核心概念,AQE 的设计和优化完全围绕着 shuffle,也就是说如果执行计划里不包含 shuffle,那么 AQE 是无效的。常见的可能产生 shuffle 的算子比如 Aggregate(group by), Join, Repartition。 不同于传统以整个执行计划为粒度进行调度的方式,AQE 会把执行计划基于 shuffle 划分成若干个子计划,每个子计划用一个新的叶子节点包裹起来,从而使得执行计划的调度粒度细化到 stage 级别 (stage 也是基于 shuffle 划分)。这样拆解后,AQE 就可以在某个子执行计划完成后获取到其 shuffle 的统计数据,并基于这些统计数据再对下一个子计划动态优化。 图片来自 databricks博客 有了这个调度流程之后,AQE 才可能有接下来的优化策略,从宏观上来看 AQE 优化执行计划的策略有两种:一是动态修改执行计划;二是动态生成 shuffle reader。 动态修改执行计划 动态修改执行计划包括两个部分:对其逻辑计划重新优化,以及生成新的物理执行计划。我们知道一般的 SQL 执行流程是,逻辑执行计划 -> 物理执行计划,而 AQE 的执行逻辑是,子物理执行计划 -> 父逻辑执行计划 -> 父物理执行计划,这样的执行流程提供了更多优化的空间。比如在对 Join 算子选择执行方式的时候可能有原来的 Sort Merge Join 优化为 Broadcast Hash Join。执行计划层面看起来是这样: 动态生成 Shuffle Reader 先明确一个简单的概念 map 负责写 shuffle 数据,reduce 负责读取 shuffle 数据。而 shuffle reader 可以理解为在 reduce 里负责拉 shuffle 数据的工具。标准的 shuffle reader 会根据预设定的分区数量 (也就是我们经常改的 spark.sql.shuffle.partitions),在每个 reduce 内拉取分配给它的 shuffle 数据。而动态生成的 shuffle reader 会根据运行时的 shuffle 统计数据来决定 reduce 的数量。下面举两个例子,分区合并和 Join 动态优化。 分区合并是一个通用的优化,其思路是将多个读取 shuffle 数据量少的 reduce 合并到 1 个 reduce。假如有一个极端情况,shuffle 的数据量只有几十 KB,但是分区数声明了几千,那么这个任务就会极大的浪费调度资源。在这个背景下,AQE 在跑完 map 后,会感知到这个情况,然后动态的合并 reduce 的数量,而在这个 case 下 reduce 的数量就会合并为 1。这样优化后可以极大的节省 reduce 数量,并提高 reduce 吞吐量。 Join 倾斜优化相对于分区合并,Join 倾斜优化则只专注于 Join 的场景。如果我们 Join 的某个 key 存在倾斜,那么对应到 Spark 中就会出现某个 reduce 的分区出现倾斜。在这个背景下,AQE 在跑完 map 后,会预统计每个 reduce 读取到的 shuffle 数据量,然后把数据量大的 reduce 分区做切割,也就是把原本由 1 个 reduce 读取的 shuffle 数据改为 n 个 reduce 读取。这样处理后就保证了每个 reduce 处理的数据量是一致的,从而解决数据倾斜问题。 AQE 优化规则实现都是非常巧妙的,其他更多优化细节就不展开了,推荐阅读 Kyuubi与AQE。 社区原生 AQE 的问题 看起来 AQE 已经是万能的,我们经常遇到的问题点都被覆盖到了,那么实际用起来的时候真的有这么丝滑吗?这里列举一些网易在使用 AQE 过程中遇到的痛点。 覆盖场景不足 就拿 Join 倾斜优化来说,这真的是一个非常棒的 idea,什么都很好但是有一个缺陷:覆盖的场景有限。在网易的深度实践过程中,经常会遇到一些 Join 明明就是肉眼可见的倾斜,但却没有被优化成想象中的样子。这种情况对用户来说会带来极大的困扰,在成百上千行的 SQL 里,哪些 Join 能被优化,哪些不能被优化?要花费很大一部分时间来去校验确认。 广播 Join 不可逆 广播配置 spark.sql.autoBroadcastJoinThreshold 是我们最常修改的配置之一,其优势是可以把 Join 用广播的形式实现,避免了数据 shuffle。但是广播有个很严重的问题:判定一张表是否可以被广播是基于静态的统计数据,特别是在经过一系列的过滤操作后,再完美的代价估计都是不精确的。由这个问题引发的任务失败报错就很常见了,Driver 端的 OOM,广播超时等。而 AQE 中的广播是不可逆的,也就是说如果一个 Join 在进入 AQE 优化前已经被选定为广播 Join,那么 AQE 无法再将其转换为其他 Join (比如 Sort Merge Join)。这对于一些由于错误估计大小而导致被广播的表是致命的。也是我们遇到影响任务稳定性的一大因素。 配置不够灵活 虽然 AQE 真的很好用,但是配置还是不够灵活。比如 stage 级别的配置隔离,我们知道 AQE 是基于 stage 的调度,那么更进一步的,SQL 的配置也可以是 stage 级别的,这样可以最细粒度的优化每一次 shuffle。听起来可能有点过犹不及的感觉,但是最容易遇到的一个需求就是单独设置最后一个 stage 的配置。最后一个 stage 是与众不同的,它代表着写操作,也就是说它决定了最终产生文件的数量。所以矛盾和痛点就这样出现了,最后一个 stage 考虑的是存储,是文件数,而过程中的 stage 考虑的是计算性能,是并发。 网易数帆在 AQE 上的改进 网易是 AQE 这个特性的重度使用者,当然不应该放着这些痛点不管,基于社区版本的分支下我们做了一系列的优化和增强,并且已经把其中的一部分内容 push 到了社区。在开源这个话题上,网易秉持着开放的理念。 回合社区补丁 Spark 的发布周期没有那么频繁,就算小版本迭代一般也要小半年,那么我们不可能只眼睁睁看着一系列的 bug 存在于旧分支。因此网易在 Spark 分支管理上的策略是:自己维护小版本,及时跟进大版本 (小版本可能是从 3.0.1 到 3.0.2,大版本则是从 3.0 到 3.1)。在这个策略下,我们可以及时回合社区新发现的问题。比如 AQE 相关的补丁 SPARK-33933,这个补丁的作用是在执行子物理计划的时候优先执行广播其次 shuffle,从而减小在调度资源不足情况下广播超时的可能性。社区的这个补丁需要到 3.2.0 分支才能发布,但是出于稳定性的考虑,网易内部把它回合到了 3.1.1 分支。 回馈社区 提高广播 Join 的稳定性 为了解决静态估计执行计划的统计数据不准确以及广播在 AQE 中不可逆的问题,我们支持了在 AQE 自己的广播配置 SPARK-35264。这个方案的思路是增加一个新的广播配置 spark.sql.adaptive.autoBroadcastJoinThreshold 和已有的广播配置隔离,再基于 AQE 运行时的统计数据来判断是否可以用广播来完成 Join,保证被广播表的数据量是可信的。在这个条件下,我们可以禁用基于静态估计的广播 Join,只开启 AQE 的广播,这样我们就可以在享受广播 Join 性能的同时兼顾稳定性。 增加 Join 倾斜优化覆盖维度 我们对 Join 倾斜优化做了很多增强,这个 case 是其中之一。在描述内容之前,我们先简单介绍一个 SHJ 和 SMJ (Shuffled Hash Join 简称为 SHJ,Sort Merge Join 简称 SMJ)。SMJ 的实现原理是通过先把相同 key shuffle 到同一 reduce,然后做分区内部排序,最后完成 Join。而 SHJ 相对于 SMJ 有着优秀的时间复杂度,通过构建一个 hash map 做数据配对,节省了排序的时间,但缺点也同样明显,容易 OOM。 一直以来 SHJ 是一个很容易被遗忘的 Join 实现,这是因为默认配置 spark.sql.preferSortMerge 的存在,而且社区版本里触发 SHJ 的条件真的很苛刻。但自从 Spark 3.0 全面地支持了所有类型的 Join Hint SPARK-27225,SHJ 又逐渐进入了我们的视野。回到正题,社区版本的 AQE 目前只对 SMJ 做了倾斜优化,这对于显式声明了 Join Hint 为 SHJ 的任务来说很不友好。在这个背景下,我们增加了 AQE 对 SHJ 倾斜优化的支持 SPARK-35214,使得 Join 倾斜优化在覆盖维度上得到了提升。 一些琐碎的订正 由于 Spark 在网易内部的使用场景是非常多的,包括但不限于数仓,ETL,Add hoc,因此我们需要最大程度减少负面的和误导用户的 case。 SPARK-35239,这个 issue 可以描述为当输入的 RDD 分区是空的时候无法对其 shuffle 的分区合并。看起来影响并不大,如果是空表的话那么就算空跑一些任务也是非常快的。但是在 Add hoc 场景下,默认的 spark.sql.shuffle.partitions 配置调整很大,这就会造成严重的 task 资源浪费,并且加重 Driver 的负担 SPARK-34899,当我们发现某些 shuffle 分区在被 AQE 的分区合并规则成功优化后,分区数居然没有下降,一度怀疑是没有找到正确使用 AQE 的姿势 SPARK-35168,一些 Hive 转过来的同学可能会遇到的 issue,理论上 MapReduce 中 reduce 的数量等价于 Spark 的 shuffle 分区数,所以 Spark 做了一些配置映射。但是在映射中出现了 bug 这肯定是不能容忍的。 内部优化(已开源) 除了和社区保持交流之外,网易数帆也做了许多基于 AQE 的优化,这些优化都在我们的开源项目 Kyuubi 里。 支持复杂场景下 Join 倾斜优化 社区版本对 AQE 的优化比较谨慎,只对标准的 Sort Merge Join 做了倾斜优化,也就是每个 Join 下的子算子必须包含 Sort 和 Shuffle,这个策略极大的限制了 Join 倾斜优化的覆盖率。举例来说,有一个执行计划先 Aggregate 再 Join,并且这两个算子之间没有出现 shuffle。我们可以猜到,在没有 AQE 的介入下,Aggregate 和 Join 之间的 shuffle 被剪枝了,这是一种常见的优化策略,一般是由于 Aggregate 的 key 和 Join 的 key 存在重复引起的。但是由于没有击中规则,AQE 无法优化这个场景的 Join。有一些可以绕过去的方法,比如手动在 Aggregate 和 Join 之间插入一个 shuffle,得到的执行计划长这样子: 我们在这种思路下,以增加规则的方式可以在不入侵 AQE 代码的前提下,自动增加 shuffle 来满足 Join 倾斜优化的触发条件。选择这样处理的理由有 3 个 增加 shuffle 可以带来另一个优秀的副作用,就是支持多表 Join 场景下的优化,可以说是一举两得 不用魔改 AQE 的代码,可以独立于我们内部的 Spark 分支快速迭代 当然这不是最终的解决方案,和社区的交流还在继续 小文件合并以及 stage 级别的配置隔离 Spark 的小文件问题已经存在很多年了,解决方案也有很多。而 AQE 的出现看起来可以天然的解决小文件问题,因此网易内部基于 AQE 的分区合并优化规则,对每个涉及写操作的 SQL,在其执行计划的顶端动态插入一个 shuffle 节点,从执行计划的角度看起来是这样的: 再结合可以控制每个分区大小的相关配置,看起来一切都是这么美好。但问题还是来了,其中有两个最明显的问题: 简单添加一个 shuffle 节点无法满足动态分区写的场景 假设我们最终产生 1k 个分区,动态插入的分区值的数量也是 1k,那么最终会产生的文件数是 1k x 1k = 1m。这肯定是不能被接受的,因此我们需要对动态分区字段做重分区,让包含相同分区值的数据落在同一个分区内,这样 1k 个分区生成的文件数最多也是 1k。但是这样处理后还有有一个潜在的风险点,不同分区值的分布是不均匀的,也就是说可能出现数据倾斜问题。对于这样情况,我们又额外增加了与业务无关的重分区字段,并通过配置的方式帮助用户快速应对不同的业务场景。 单分区处理的数据量过大导致性能瓶颈 成也萧何,败也萧何。把 spark.sql.adaptive.advisoryPartitionSizeInBytes 调大后小文件的问题是解决了,但是过程中每个分区处理的数据量也随之增加,这导致过程中的并发度无法达到预期的要求。因此 stage 级别的配置隔离出现了。我们直接把整个 SQL 配置划分为两部分,最后一个 stage 以及之前的 stage,然后把这两个部分之间的配置做了隔离。拿上面这个配置来说,在最后一个 stage 的样子是 spark.sql.finalStage.adaptive.advisoryPartitionSizeInBytes。在配置隔离的帮助下,我们可以完美解决小文件和计算性能不能兼得的问题,用户可以更加优雅地使用 AQE。 案例分享 多表 Join 倾斜 下面这两张图为 3 表 Join 的执行计划,由于长度的限制我们只截取到 Join 相关的片段,并且没有被优化的任务由于数据倾斜问题没有执行成功。可以明显看到社区版本无法对这类多表 Join 做倾斜优化,而我们在动态插入 shuffle 之后,两次 Join 都成功的被优化。在这个特性的帮助下,Join 倾斜优化的覆盖场景相对于社区有明显提升。 社区版本 内部版本 Stage 配置隔离 在支持了 stage 级别的配置隔离后,我们单独设置了最后一个 stage 的参数,下面两张图是某个线上任务前后两天的执行情况,可以明显看到在配置隔离后,在保证最终产出的文件数一致的情况下,过程中 stage 的并发度得到了提升,从而使任务性能得到提升。 配置隔离前 配置隔离后 任务性能对比 这张图展示了我们部分迁移任务的资源成本以及性能对比,其中蓝线是迁移前的数据,红线是迁移后的数据。可以非常明显看到,在资源成本大幅下降的同时任务性能有不同程度的提升。 总结与展望 首先得感谢一下 Apache Spark 社区,在引入了 AQE 之后,我们的线上任务得到了不同程度的性能提升,也使得我们在遇到问题的时候可以有更多解决问题的思路。在深度实践的过程中,我们也发现了一些可以优化的点: 在优化细节上的角度,可以增加命中 AQE 优化的 case,比如 Join 倾斜优化增强,让用户不用逐个检查不能被优化的执行计划 在业务使用上的角度,可以同时支持 ETL,Add hoc 等侧重点不一样的场景,比如 stage 配置隔离这个特性,让关注写和读的业务都有良好的体验 在完成这个阶段性的优化后,接下来我们会继续深耕在 AQE 的覆盖场景上,比如支持 Union 算子的细粒度优化,增强 AQE 的代价估计算法等。除此之外,还有一些潜在的性能回归问题也是值得我们注意的,比如在做分区合并优化后会放大某些高时间复杂度算子的性能瓶颈。 作为可能是最快在线上使用 Apache Spark 3.1.1 的用户,网易在享受社区技术福利的同时也在反哺社区。这也是网易对技术的思考和理念: 因为开放,我们拥抱开源,深入社区 因为热爱,我们快速接收新的理论,实践新的技术 作者简介:尤夕多,目前就职于网易数帆-有数事业部,专注于开源大数据领域。网易数帆开源项目 Kyuubi Committer / Apache Spark Contributor。 相关阅读: 大数据实战:Kyuubi 与 Spark ThriftServer 的全面对比分析 网易数帆开源Kyuubi:基于Spark的高性能JDBC和SQL执行引擎 拥抱开源,我们是认真的-网易易数2020年Apache Spark贡献总结

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册