www.9778.com 15

www.9778.comKDevelop 5.4.3 发布,跨平台 IDE

KDevelop 5.4.3 发布了,这是一个 bug 修复版本。主要更新内容如下:

以下内容为本人的学习笔记,如需要转载,请声明原文链接 [englyf]

QML学习心得,qml学习

Qt Quick之于QML,正如Qt 之于 C++,QML是Qt中开发的一个新的语言,而Qt
Quick是这个语言的一个组件库,其中包含了很多用QML写的可以现成使用的组件。

QML Hello World

// 导入语句部分
import QtQuick 2.4
import QtQuick.Window 2.2
//对象声明部分
Window {
   visible: true
    MainForm {
       anchors.fill: parent
       mouseArea.onClicked: {
            Qt.quit();
       }
   }
}

   
正如这段代码所示的,一个QML文档定义了一个QML对象树,由两部分组成:一个import导入部分,一个对象声明部分。

   
import导入语句类似于C++中的#include,只有导入了相关模块,才能使用其中的类型和功能。这里导入了QtQuick模块,这个就是我们前面创建项目时选择的组件集,它包含了创建用户界面所需要的基本类型和功能;而QtQuick.Window模块中提供了Window类型,它可以为Qt
Quick场景创建一个顶层窗口。

   
在Window中的visible是Window的属性,用来设置窗口是否显示,可以在帮助文档中查看一个类型的所有属性及用法。

Qt Quick之于QML,正如Qt 之于
C++,QML是Qt中开发的一个新的语言,而Qt
Quick是这个语言的一个组件库,其中包含了很多用…

作者介绍

kdevelop

  • ProblemNavigationContext:修复带有声明的 file:line
    链接的错误链接目标
    (commit)
  • ProjectManagerView:使带有空图标的项目与带有有效图标的项目具有相同的缩进
    (commit)
  • 欢迎页面:修复 QtQuick.XmlListModel 导入的版本以匹配 Qt 5.7 ff
    (commit)
  • 欢迎页面:修复 QtQuick.Layouts 导入的版本以匹配 Qt 5.7 ff
    (commit)
  • [www.9778.comKDevelop 5.4.3 发布,跨平台 IDE。Grepview] 使用正确的回退图标折叠全部
    (commit)
  • FileManagerListJob:使用 semaphore 进行锁定
    (commit)
  • 修复 DUChain 中的无限递归
    (commit)
  • 缓存每种语言类型的类似于 gcc 的编译器的定义/包含
    (commit)
  • 仅在需要时才写入定义文件
    (commit)
  • 不要在完全匿名的结构上设置超长名称
    (commit)
  • 使用类型名称作为匿名类型定义的结构/联合的回退 ID
    (commit. fixes
    bug #409041)
  • 修复了过滤类列表时崩溃的问题
    (commit. code
    review D22660. fixes
    bug #406931)
  • Gcclikecompiler:正确解析包含符号链接的路径
    (commit. fixes
    bug #405221)

创建一个 QML 文件

QML 文档内部定义了高可读和结构化的对象层次系统。 每个 QML
文档都由两部分组成:导入部分和对象声明部分。通过导入
QtQuick,可以使用到用户界面开发过程中最常用的类型和功能。

郭俊,专注于大数据架构,熟悉Kafka和Flume源码,熟悉Hadoop和Spark原理,精通数据库模型设计和SQL调优。

kdev-php

  • 使用数组常量修复表达式
    (commit. fixes
    bug #405719)
  • 不要将类常量标记为 normal
    members (commit)

更新说明:

(文/开源中国)    

导入和使用 QtQuick 模块

QML 文档在使用 Qt Quick 前必须要先导入它。导入的语法看下面:

import QtQuick 2.3

从这里开始,由 Qt Quick 提供的类型和功能都可以在 QML 文档里直接引用了。

本文转载自大数据架构

定义一个对象层次结构系统

在 QML 文档中声明的对象定义了会被显示到可视场景的内容。Qt Quick
为所有的用户界面提供了基础的构建模块,比如显示图片、文字和处理用户输入的对象,就像盖房子必须要用到的砖头、柱子等等。下面演示一个简单的对象声明,显示出来就是:由绿色的矩形包含着一些字符串在中间,非常经典的问候「Hello,
World!」

Rectangle { width: 300 height: 200 color: "green" Text { anchors.centerIn: parent text: "Hello, World!" }}

上面的代码中定义了一组对象层次结构,有一个根对象 Rectangle
和里面的一个子对象 Text。对象 Text 的父母会被自动设置成根对象
Rectangle,很明显,对象 Text 会被 QML 添加到对象 Rectangle 的属性
children 中。

本文介绍了顶级互联网公司数万节点下 Spark 的 CI 与 CD & CD
灰度发布实践。包含如何维护源代码,如何维护 Release
多版本,开发版与正式版,以及如何实现灰度发布,如何进行 hotfix 等。

完整的一个 QML 文档

上面用到的 Rectangle 和 Text 都是要由 QtQuick
导入才能使用。像下面这样才可以成为一个完整的 QML 文档:

import QtQuick 2.3Rectangle { width: 300 height: 200 color: "green" Text { anchors.centerIn: parent text: "Hello, World!" }}

然后保存这个文档为「HelloWorld.qml」,稍后我们就可以加载和显示它了。

为了提高本文内容的可借鉴性,隐去了公司特有内容,只保留通用部分。

创建 QML 工程,然后跑起来!

可以使用 Qt Creator 加载显示 QML
文档定义的图形场景。对于像上面定义的这种简单 UI 文件,可以在 Qt Creator
中选择 File > New File or Project > Applications > Qt Quick
UI得到。点击绿色高亮的按钮 Run 运行应用。你会看到字符串「Hello,
World!」显示在绿色的矩形中间。如果你想知道更多关于在 Qt Creator
中创建和运行工程的信息,下面的链接里有你需要的:

  • 怎么创建 Qt Quick 工程 ?
  • Building and Running an Example

一、CI 介绍

使用控件创建 QML 应用

虽然 Qt Quick 为我们提供了基础的图形元素,但是也可以在应用中使用 Qt
Quick Controls 提供的现成 QML
控件类型,这样更快捷更方便,大大加速开发过程。为了快速构建一个 QML
可视化应用,可以插入一个 ApplicationWindow 类型。一个 QML
界面有以下图所示的布局:

www.9778.com 1为了搭建一个应用,可以在上图所示的各个区域中添加和连接不同的控件。下面就利用上面的搭建的布局写一个基本的应用:

// 导入相关的模块import QtQuick 2.3import QtQuick.Controls 1.2import QtQuick.Window 2.2//包含应用的窗口ApplicationWindow { //title of the application title: qsTr("Hello World") width: 640 height: 480 //包含两个菜单项的菜单 menuBar: MenuBar { Menu { title: qsTr MenuItem { text: qsTr("&O打开") onTriggered: console.log; } MenuItem { text: qsTr onTriggered: Qt.quit(); } } } //Content Area //按钮,在 Content Area 的中间 Button { text: qsTr("Hello World") anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter }}

点击 Run
运行工程可以看到有两个菜单和一个在中间的按钮。点击「退出」菜单可以关闭应用,如下图所示

www.9778.com 2

当然,也有一些不同的导航方法和控件,例如按键和滑块可供使用。下面的两个例子可以从
Qt Creator 获得,里面演示了使用更多的控件和布局,有兴趣的可以看看:

  • Basic Layouts
  • Touch Gallery你可以将上面链接里提到的代码片段复制并粘贴到 hello
    world 的例子中,看看 QML 的怎么使用。

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

处理用户的输入

使用 QML
来定义用户界面的其中一个巨大的优势就是,允许界面设计者使用简单的
JavaScript 表达式来定义应用如何处理事件。在 QML 里,我们把事件叫做
信号,而且这些信号由 信号处理程序 处理。

Rectangle { width: 200 height: 100 color: "red" Text { anchors.centerIn: parent text: "Hello, World!" } MouseArea { anchors.fill: parent onClicked: parent.color = "blue" }}

把上面这段代码保存到文件「ClickableHelloWorld.qml」中,然后点击 Run 运行
qmlscene,界面会运行起来。当点击窗口的任何地方,矩形会从红色变成蓝色。因为
MouseArea 对触摸事件也会发送 clicked
信号,所以上面这段功能对移动设备也有效。对于键盘输入,我们也可以用一段简单的表达式来处理:

Rectangle { width: 200 height: 100 color: "red" Text { anchors.centerIn: parent text: "Hello, World!" } focus: true Keys.onPressed: { if (event.key == Qt.Key_Return) { color = "blue"; event.accepted = true; } }}

关于上面这段代码,可以看到接收到焦点后,当 return
键被按下时,窗口的颜色也会改变。

www.9778.com 3

属性绑定

对象和它们的属性是 QML 文档中定义的图形界面的组成基础。QML
语言允许以各种方式让属性相互关联,实现了高度动态的用户界面。下面的例子中,各个子矩形的几何大小都被关联到了父矩形的几何大小。由于属性的绑定关系,所以当父矩形的几何大小改变之后,各个子矩形的几何大小也会自动被更新。

Rectangle { width: 450 height: 200 Rectangle { width: parent.width / 2 height: parent.height } Rectangle { width: parent.width / 2 height: parent.height x: parent.width / 2 }}

Continuous Integration

动画

属性也可以通过动画来动态更新。可以使用 QtQuick
提供的各种动画类型来动态改变属性的值。在下面的例子中,一个属性被设置了动画,并且将显示在文本区域:

Rectangle { color: "lightgray" width: 200 height: 200 property int animatedValue: 0 SequentialAnimation on animatedValue { loops: Animation.Infinite PropertyAnimation { to: 150; duration: 1000 } PropertyAnimation { to: 0; duration: 1000 } } Text { anchors.centerIn: parent text: parent.animatedValue }}

运行工程后可以看到,显示的数值会定期循环从0到150,再从150到0地变化。

持续集成的优点:

自定义可重用的 QML 类型

其实 QML
最重要的概念就是类型可重用。一个应用可能包含了多个类似的可视化类型,例如多个按钮等,所以
QML
为了最小化代码拷贝和最大化代码可读性,允许对这些类型进行可重用的定制化。下面看看例子,假如我们定义了一个新的
Button 类型,并且保存为文件 Button.qml:

// Button.qmlimport QtQuick 2.3Rectangle { width: 100; height: 100 color: "red" MouseArea { anchors.fill: parent onClicked: console.log("Button clicked!") }}

现在上面定义了的 Button 类型就可以多次重复使用了,看一下示例:

// application.qmlimport QtQuick 2.3Column { Button { width: 50; height: 50 } Button { x: 50; width: 100; height: 50; color: "blue" } Button { width: 50; height: 50; radius: 8 }}

www.9778.com 4

通过上面的示例,可以看到在应用程序中可以组装和重复调用自定义的类型。这里要注意一下,上面并没有看到显式的导入
Button 类型,因为只要调用和定义在同一路径下就不需要显式的导入。

关于怎么编写自己的可重用组件还有很多的细节和要注意的地方,更多的内容请点击这里
QML 对象的属性。

快速发现错误:每次更新都及时集成到主干分支中,并进行测试,可以快速发现错误,方便定位错误

接下来可以做什么

看完上面的内容,相信已经对 QML
有一定的印象了,但了解得还是很浅,怎么能就这样止步不前?所以请继续大踏步向前吧:

  • QML 应用开发介绍
  • Qt Examples and Tutorials

参考英文资料[Qt]

避免子分支大幅偏离主干分支:主干在不断更新,如果不经常集成,会产生后期集成难度变大,甚至难以集成,并造成不同开发人员间不必要的重复开发

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

二、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 持续交付

1、CD 持续交付介绍

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

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

www.9778.com 5

Continuous Delivery

持续发布的优点:

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

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

Spark CD 持续发布实践

这里有提供三种方案,供读者参考:

方案一:单分支

正常流程

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

www.9778.com 6

Continuous Delivery Solution 1

所有开发都在 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
环境中测试

注:

蓝色圆形是正常 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 )

www.9778.com 7

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

www.9778.com 8

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 持续交付方案如下:

www.9778.com 9

Continuous Delivery Solution 2

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 # }

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 # }

www.9778.com 10

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 # }

www.9778.com 11

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 持续交付方案如下:

www.9778.com 12

Continuous Delivery Solution 3

正常开发在 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 # }

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 后仍然顺序相连

www.9778.com 13

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

www.9778.com 14

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 持续部署

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

www.9778.com 15

Continuous Deploy

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

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