Spark 灰度发布在十万级节点上的实践

简介:

CI 介绍

持续集成是指,及时地将最新开发的且经过测试的代码集成到主干分支中。

ccc940d3e2c92d574bdff3a31de6c94148193c61

Continuous Integration

持续集成的优点

 ●  快速发现错误  每次更新都及时集成到主干分支中,并进行测试,可以快速发现错误,方便定位错误
 ●  避免子分支大幅偏离主干分支  主干在不断更新,如果不经常集成,会产生后期集成难度变大,甚至难以集成,并造成不同开发人员间不必要的重复开发

 ●  为快速迭代提供保障 持续集成为后文介绍的持续发布与持续部署提供了保证

Spark CI 实践

目前主流的代码管理工具有,Github、Gitlab等。本文所介绍的内容中,所有代码均托管于私有的 Gitlab 中。

鉴于 Jenkins 几乎是 CI 事实上的标准,本文介绍的 Spark CI CD & CD 实践均基于 Jenkins 与 Gitlab。

Spark 源码保存在 spark-src.git 库中。

由于已有部署系统支持 Git,因此可将集成后的 distribution 保存到 Gitlab 的发布库(spark-bin.git)中。

每次开发人员提交代码后,均通过 Gitlab 发起一个 Merge Requet (相当于 Gitlab 的 Pull Request)

每当有 MR 被创建,或者被更新,Gitlab 通过 Webhook 通知 Jenkins 基于该 MR 最新代码进行 build。该 build 过程包含了

 ●  编译 Spark 所有 module
 ●  执行 Spark 所有单元测试
 ●  执行性能测试

 ●  检查测试结果。如果有任意测试用例失败,或者性能测试结果明显差于上一次测试,则 Jenkins 构建失败

Jenkins 将 build 结果通知 Gitlab,只有 Jenkins 构建成功,Gitlab 的 MR 页面才允许 Merge。否则 Gitlab 不允许 Merge

另外,还需人工进行 Code Review。只有两个以上的 Reviewer 通过,才能进行最终 Merge所有测试与 Reivew 通过后,通过 Gitlab Merge 功能自动将代码 Fast forward Merge 到目标分支中

该流程保证了

 ●  所有合并进目标分支中的代码都经过了单元测试(白盒测试)与性能测试(黑盒测试)
 ●  每次发起 MR 后都会及时自动发起测试,方便及时发现问题

 ●  所有代码更新都能及时合并进目标分支

Spark CD 持续交付

CD 持续交付介绍

持续交付是指,及时地将软件的新版本,交付给质量保障团队或者用户,以供评审。持续交付可看作是持续集成的下一步。它强调的是,不管怎么更新,软件都是可随时交付的。

这一阶段的评审,一般是将上文集成后的软件部署到尽可能贴近生产环境的 Staging 环境中,并使用贴近真实场景的用法(或者流量)进行测试。

d2090b79f8f954eaff1fb4639cfc5ac818882664

Continuous Delivery

持续发布的优点

 ●  快速发布  有了持续集成与持续发布,可快速将最新功能发布出来,也可快速修复已知 bug

 ●  快速迭代 由于发布及时,可以快速判断产品是否符合产品经理的预期或者是否能满足用户的需求

Spark CD 持续发布实践

这里有提供三种方案,供读者参考。推荐方案三

方案一:单分支

正常流程

如下图所示,基于单分支的 Spark 持续交付方案如下

 ●  所有开发都在  spark-src.git/dev (即 spark-src.git 的 dev branch) 上进行
 ●  每周一将当前最新代码打包,放进  spark-bin.git/dev  的  spark-${ build # } (如图中第 2 周的 spark-72)文件夹内
 ●  spark-prod 指向当前 spark-dev 指向的文件夹(如图中的 spark-71 )
 ●  spark-dev 指向  spark-${ build # } (如图中的 spark-72)
 ●  自动将 spark-bin.git 最新内容上线到 Staging 环境,并使用 spark-dev 进行测试

 ●  spark-prod 比 spark-dev 晚一周(一个 release 周期),这一周用于 Staging 环境中测试

a628443c81557cbe81244c5affbb024e53f84c9d

Continuous Delivery Solution 1

注:

 ●  蓝色圆形是正常 commit
 ●  垂直虚线是发布时间点,week 1、week 2、week 3、week 4
 ●  最上方黑色粗横线是源码时间线
 ●  下方黄色粗横线是 release 时间线
 ●  绿色方框是每周生成的 release,带 build #
 ●  蓝色方框是开发版本的 symbolic

 ●  橘色方框是线上版本的 symbolic

bug fix

在 Staging 环境中发现 spark-dev 的 bug 时,修复及集成和交付方案如下

 ●  如果在 Staging 环境中发现了 spark-dev 的 bug,且必须要修复(如不修复,会带到下次的 spark-prod 的 release 中),则提交一个 commit,并且 commit message 包含 bugfix 字样(如图中黑色圆形 commit 9 所示)
 ●  该 bugfix 被 Merge 后,Jenkins 得到通知
 ●  Jenkins 发现该 commit 是 bugfix,立即启动构建,生成 spark-${ build # } (如图中的 spark-73)

 ●  spark-dev 指向 spark-${ build # } (如图中的 spark-73 )

a0f2ebf64f19a554834cd2784487207f05d9c332

Continuous Delivery Solution 1 bug fix

hot fix

生产环境中发现 bug 时修复及交付方案如下

 ●  如果发现线上版本(即 spark-prod)有问题,须及时修复,则提交一个 commit,并且 commit message 包含 hotfix 字样 (如图中红色圆形 commit 9 所示)
 ●  该 hotfix 被 Merge 后,Jenkins 得到通知
 ●  Jenkins 发现该 commit 是 hotfix,立即启动构建,生成  spark-${ build # } (如图中的 spark-73)

 ●  spark-dev 与 spark-prod 均指向 spark-${ build # } (如图中的 spark-73 )

1e71bfd4a8cff3819056c91f4ce633ccd91370f2

Continuous Delivery Solution 1 hotfix

Pros.

 ●  spark-src.git 与 spark-bin.git 都只有一个分支,维护方便

 ●  spark-prod 落后于 spark-dev 一周(一个 release),意味着 spark-prod 都成功通过了一周的 Staging 环境测试

Cons.

 ●  使用 spark-prod 与 spark-dev 两个 symbolic,如果要做灰度发布,需要用户修改相应路径,成本较高

 ●  hotfix 时,引入了过去一周多(最多两周)未经 Staging 环境中通过 spark-dev 测试的 commit,增加了不确定性,也违背了所有非 hotfix commit 都经过了一个发布周期测试的原则

方案二:两分支

正常流程

如下图所示,基于两分支的 Spark 持续交付方案如下

 ●  spark-src.git 与 spark-bin.git 均包含两个分支,即 dev branch 与 prod branch

 ●  所有正常开发都在  spark-src.git/dev  上进行

 ●  每周一(如果是 weekly release)从 spark-src.git/dev 打包出一个 release 放进 spark-bin.git/dev 的 spark-${ build # } 文件夹内(如图中第 2 周上方的的 spark-2 )。它包含了之前所有的提交(commit 1、2、3、4)

 ●  spark-bin.git/dev 的 spark 作为 symbolic 指向 spark-${ build # } 文件夹内(如图中第 2 周上方的的 spark-2)

 ●  spark-src.git/prod 通过 fast-forward merge 将 spark-src.git/dev 一周前最后一个 commit 及之前的所有 commit 都 merge 过来(如图中第 2 周需将 commit 1 merge 过来)

 ●  将  spark-src.git/prod  打包出一个 release 放进  spark-bin.git/prod  的  spark-${ build # }  文件夹内(如图中第 2 周下方的的 spark-1 )

 ●  spark-bin.git/prod 的 spark 作为 symbolic 指向spark-${ build # }

dec278dfa6b785c456586f505b7cb13f5638198b

Continuous Delivery Solution 2

bug fix

在 Staging 环境中发现了 dev 版本的 bug 时,修复及集成和交付方案如下

 ●  在  spark-src.git/dev 上提交一个 commit (如图中黑色的 commit 9),且 commit message 包含 bugfix 字样

 ●  Jenkins 发现该 commit 为 bugfix 后,立即构建,从 spark-src.git/dev 打包生成一个 release 并放进 spark-bin.git/dev 的 spark-${ build # } 文件夹内(如图中第二周与第三周之间上方的的 spark-3 )

 ●  spark-bin.git/dev 中的 spark 作为 symbolic 指向 spark-${ build # }

b57c887ca68cee5114a068f57032f2695b05d514

Continuous Delivery Solution 2 bugfix

hot fix

在生产环境中发现了 prod 版本的 bug 时,修复及集成和交付方案如下

 ●  在  spark-src.git/dev  上提交一个 commit(如图中红色的 commit 9),且 commit message 包含 hotfix 字样
 ●  Jenkins 发现该 commit 为 hotfix 后,立即将  spark-src.git/dev  打包生成 release 并 commit 到  spark-bin.git/dev  的  spark-${ build # }  (如图中上方的 spark-3 )文件夹内。 spark 作为 symbolic 指向该  spark-${ build # }
 ●  通过 cherry-pick 将 commit 9 double commit 到  spark-src.git/prod (如无冲突,则该流程全自动完成,无需人工参与。如发生 ●  冲突,通过告警系统通知开发人员手工解决冲突后提交)

 ●  将 spark-src.git/prod 打包生成 release 并 commit 到 spark-bin.git/prod 的 spark-${ build # } (如图中下方的 spark-3 )文件夹内。spark作为 symbolic 指向该spark-${ build # }

ca12ca6c1ab29d2d1092484f861f322463f57bec

Continuous Delivery Solution 2 hotfix

Pros.

 ●  无论是 dev 版还是 prod 版,路径都是 spark。切换版对用户透明,无迁移成本
 ●  方便灰度发布
 ●  hotfix 不会引入未经测试的 commit,稳定性更有保障

 ●  prod 版落后于 dev 版一周(一个 release 周期),即 prod 经过了一个 release 周期的测试,稳定性强

Cons.

 ●  hot fix 时,使用 cherry-pick,但  spark-src.git/dev (包含 commit 1、2、3、4、5) 与  spark-src.git/prod (包含 commit 1) 的 base 不一样,有发生冲突的风险。一旦发生冲突,便需人工介入
 ●  hot fix 后再从  spark-src.git/dev  合并 commit 到  spark-src.git/prod  时需要使用 rebase 而不能直接 fast-forward merge。而该 rebase 可能再次发生冲突
 ●  bug fix 修复的是当前  spark-bin.git/dev 的 bug,即图中的 commit 1、2、3、4 后的 bug,而 bug fix commit 即 commit 9 的 base 是 commit 5,存在一定程度的不一致

 ●  bug fix 后,第 3 周时,最新的 spark-bin.git/dev 包含了 bug fix,而最新的 spark-bin.git/prod 未包含该 bugfix (它只包含了 commit 2、3、4 而不包含 commit 5、9)。只有到第 4 周,spark-bin.git/prod 才包含该 bugfix。也即 Staging 环境中发现的 bug,需要在一周多(最多两周)才能在 prod 环境中被修复。换言之,Staging 环境中检测出的 bug,仍然会继续出现在下一个生产环境的 release 中

 ●  spark-src.git/dev 与 spark-src.git/prod 中包含的 commit 数一致(因为只允许 fast-forward merge),内容也最终一致。但是 commit 顺序不一致,且各 commit 内容也可能不一致。如果维护不当,容易造成两个分支差别越来越大,不易合并

方案三:多分支

正常流程

如下图所示,基于多分支的 Spark 持续交付方案如下

 ●  正常开发在  spark-src.git/master  上进行
 ●  每周一通过 fast-forward merge 将  spark-src.git/master  最新代码合并到  spark-src.git/dev 。如下图中,第 2 周将 commit 4 及之前所有 commit 合并到  spark-src.git/dev
 ●  将  spark-src.git/dev  打包生成 release 并提交到  spark-bin.git/dev  的  spark-${ build # } (如下图中第 2 周的 spark-2) 文件夹内。spark 作为 symbolic,指向该  spark-${ build # }
 ●  每周一通过 fast-forward merge 将  spark-src.git/master  一周前最后一个 commit 合并到  spark-src.git/prod 。如第 3 周合并 commit 4 及之前的 commit
 ●  上一步中,如果 commit 4 后紧临有一个或多个 bugfix commit,均需合并到  spark-src.git/prod  中,因为它们是对 commit 4 进行的 bug fix。后文介绍的 bug fix 流程保证,如果对 commit 4 后发布版本有多个 bug fix,那这多个 bug fix commit 紧密相连,中间不会被正常 commit 分开

 ●  将 spark-src.git/prod 打包生成 release 并提交到 spark-bin.git/prod 的 spark-${ build # }(如下图中第 2 周的 spark-2) 文件夹内。spark 作为 symbolic,指向该 spark-${ build # }

6518ee64154c0fb566172df8bd3328f7bd889ffe

Continuous Delivery Solution 3

bug fix

在 Staging 环境中发现了 dev 版本的 bug 时,修复及集成和交付方案如下

 ●  如下图中,第 2 周与第 3 周之间在 Staging 环境中发现 dev 版本的 bug,在  spark-src.git/dev (包含 commit 1、2、3、4) 上提交一个 commit(如图中黑色的 commit 9),且 commit message 中包含 bugfix 字样
 ●  Jenkins 发现该 bugfix 的 commit 后立即执行构建,将  spark-src.git/dev  打包生成 release 并提交到  spark-bin.git/dev  的  spark-${ build # } (如图中的 spark-3) 文件夹内,spark 作为 symbolic,指向该  spark-${ build # }
 ●  通过  git checkout master  切换到  spark-src.git/master  ,再通过  git rebase dev  将 bugfix 的 commit rebase 到  spark-src.git/master ,如果 rebase 发生冲突,通过告警通知开发人员人工介入处理冲突

 ●  在一个 release 周期内,如发现多个 dev 版本的 bug,都可按上述方式进行 bug fix,且这几个 bug fix 的 commit 在 spark-src.git/dev上顺序相连。因此它们被 rebase 到 spark-src.git/master 后仍然顺序相连

1bed48dd74550e290a24336e81a4292cfbde39a6

Continuous Delivery Solution 3 bugfix

hot fix

在生产环境中发现了 prod 版本的 bug 时,修复及集成和交付方案如下

 ●  在  spark-src.git/prod  中提交一个 commit,且其 commit message 中包含 hotfix 字样
 ●  Jenkins 发现该 commit 为 hotfix,立即执行构建,将  spark-src.git/prod  打包生成 release 并提交到  spark-bin.git/prod  的  spark-${ build # } (如图中的 spark-3) 文件夹内,spark 作为 symbolic,指向该  spark-${ build # }
 ●  通过  git checkout master  切换到  spark-src.git/master ,再通过  git rebase prod  将 hotfix rebase 到  spark-src.git/master

 ●  在一个 release 周期内,如发现多个 prod 版本的 bug,都可按上述方式进行 hot fix

9bff3ea6b6aa598a1b5ceb7f8206053a664b56d4

Continuous Delivery Solution 3 hotfix

灰度发布

本文介绍的实践中,不考虑多个版本(经实践检验,多个版本维护成本太高,且一般无必要),只考虑一个 prod 版本,一个 dev 版本

上文介绍的持续发布中,可将 spark-bin.git/dev 部署至需要使用最新版的环境中(不一定是 Staging 环境,可以是部分生产环境)从而实现 dev 版的部署。将 spark-bin.git/prod部署至需要使用稳定版的 prod 环境中

回滚机制

本文介绍的方法中,所有 release 都放到 spark-${ build \# } 中,由 spark 这一 symbolic 选择指向具体哪个 release。因此回滚方式比较直观

 ●  对于同一个大版本(dev 或者 prod)的回滚,只需将 spark 指向 build # 较小的 release 即可

 ●  如果是将部分环境中的 prod 版迁至 dev 版(或者 dev 版改为 prod 版)后,需要回滚,只需将 dev 改回 prod 版(或者将 prod 版改回 dev 版)即可

Pros.

 ●  正常开发在  spark-src.git/master  上进行,Staging 环境的 bug fix 在  spark-src.git/dev  上进行,生产环境的 hot fix 在  spark-src.git/prod  上进行,清晰明了
 ●  bug fix 提交时的 code base 与 Staging 环境使用版本的 code 完全一致,从而可保证 bug fix 的正确性
 ●  bug fix 合并回  spark-src.git/master  时使用 rebase,从而保证了  spark-src.git/dev  与  spark-src.git/master  所有 commit 的顺序与内容的一致性,进而保证了这两个 branch 的一致性
 ●  hot fix 提交时的 code base 与 生产环境使用版本的 code 完全一致,从而可保证 hot fix 的正确性
 ●  hot fix 合并回  spark-src.git/master  时使用 rebase,从而保证了  spark-src.git/dev  与  spark-src.git/master  所有 commit 的顺序性及内容的一致性,进而保证了这两个 branch 的一致性
 ●  开发人员只需要专注于新 feature 的开发,bug fix 的提交,与 hot fix 的提交。所有的版本维护工作全部自动完成。只有当 bug fix 或 hot fix rebase 回  spark-src.git/master  发生冲突时才需人工介入 

●  spark-bin.git/dev 与 spark-bin.git/prod 将开发版本与生产版本分开,方便独立部署。而其路径统一,方便版本切换与灰度发布

Cons.

 ●  在本地  spark-src.git/master  提交时,须先 rebase 远程分支,而不应直接使用 merge。在本方案中,这不仅是最佳实践,还是硬性要求

 ●  虽然 bug fix 与 hot fix commit 都通过 rebase 进入 spark-src.git/master。但发生冲突时,需要相应修改 spark-src.git/master上后续 commit。如上图中,提交红色 commit 9 这一 hot fix 后,在 rebase 回 spark-src.git/master 时,如有冲突,可能需要修改 commit 2 或者 commit 3、4、5。该修改会造成本地解决完冲突后的版本与远程版本冲突,需要强制 push 回远程分支。该操作存在一定风险

Spark CD 持续部署

持续部署是指,软件通过评审后,自动部署到生产环境中

35e142551fc583d09bb8f592186d18209ea6f314

Continuous Deploy

上述 Spark 持续发布实践的介绍都只到 "将 *** 提交到 spark-bin.git" 结束。可使用基于 git 的部署(为了性能和扩展性,一般不直接在待部署机器上使用 git pull --rebase,而是使用自研的上线方案,此处不展开)将该 release 上线到 Staging 环境或生产环境

该自动上线过程即是 Spark 持续部署的最后一环


原文发布时间为:2018-10-9

本文作者:郭俊 Jason Guo

本文来自云栖社区合作伙伴“大数据架构”,了解相关信息可以关注“大数据架构”。

相关文章
|
4月前
|
SQL 分布式计算 DataWorks
DataWorks on emr 创建spark节点指定dlf的catalog?
DataWorks on emr 创建spark节点指定dlf的catalog?
33 0
|
SQL 分布式计算 Java
五、【计算】Spark原理与实践(下) | 青训营笔记
五、【计算】Spark原理与实践(下) | 青训营笔记
五、【计算】Spark原理与实践(下) | 青训营笔记
|
分布式计算 Spark
|
存储 分布式计算 资源调度
Spark on k8s 在阿里云 EMR 的优化实践
本文整理自阿里云技术专家范佚伦在7月17日阿里云数据湖技术专场交流会的分享。
Spark on k8s 在阿里云 EMR 的优化实践
|
人工智能 分布式计算 Apache
《# Apache Spark系列技术直播# 第八讲 【 微软Azure平台利用Intel Analytics Zoo构建AI客服支持实践 】》电子版地址
# Apache Spark系列技术直播# 第八讲 【 微软Azure平台利用Intel Analytics Zoo构建AI客服支持实践 】
141 0
《# Apache Spark系列技术直播# 第八讲 【 微软Azure平台利用Intel Analytics Zoo构建AI客服支持实践 】》电子版地址
|
弹性计算 分布式计算 资源调度
模拟IDC spark读写MaxCompute实践
现有湖仓一体架构是以 MaxCompute 为中心读写 Hadoop 集群数据,有些线下 IDC 场景,客户不愿意对公网暴露集群内部信息,需要从 Hadoop 集群发起访问云上的数据。本文以 EMR (云上 Hadoop)方式模拟本地 Hadoop 集群访问 MaxCompute数据。
653 0
|
SQL 分布式计算 Hadoop
【小白视角】大数据基础实践(七) Spark的基本操作
目录 1. Spark概述 1.1 背景 1.2 特点 1.3 使用趋势 2. Spark生态系统 2.1 Spark与Hadoop的对比。 2.2 Job 2.3 容错率 2.4 通用性 2.5 实际应用 2.6 Spark生态系统组件的应用场景 2.7 Spark组件 2.7.1 Spark Core 2.7.2 Spark SQL 2.7.3 Spark Streaming 2.7.4 MLlib 2.7.5 Graphx 2.7.6 Cluster Managers 3. Spark运行架构 3.1 基本概念 3.2 架构设计 3.3 Spark 运行基本流程 3.4 Spark 运行
291 0
【小白视角】大数据基础实践(七) Spark的基本操作
|
人工智能 达摩院 分布式计算
阿里云天池Apache Spark落幕:AI医疗进入落地实践深水期,达摩院如何用生态破局?
一次疫情,让阿里达摩院医疗 AI 团队一战成名。 他们利用整个假期,疫情爆发初期迅速将技术落地,率先在「郑州小汤山」落地的第一套 CT 影像识别系统代码和图片已经被分别收藏在中国国家博物馆和中国科技馆。 疫情之后,达摩院医疗 AI 产品迅速进入落地阶段,成长与痛点并存。 面对技术落地面临的普遍困境,达摩院以「数字人体」系列比赛为抓手,逐渐搭建起行业生态。
204 0
阿里云天池Apache Spark落幕:AI医疗进入落地实践深水期,达摩院如何用生态破局?
|
机器学习/深度学习 分布式计算 算法
基于Spark的机器学习实践 (十) - 降维
基于Spark的机器学习实践 (十) - 降维
114 0
|
机器学习/深度学习 分布式计算 算法
基于Spark的机器学习实践 (九) - 聚类算法
基于Spark的机器学习实践 (九) - 聚类算法
117 0