微服务版本分支管理与特性开关

在微服务的开发中, 我们会开发很多功能, 并在最短时间内上线, 也就是说经过了单元测试, API 测试, 自动化的集成测试, 以及少量的手动端到端的测试, 新增的改动就会在几天内部署到产品线上.

这样做符合"唯快不破"的理念, 而且很多开发人员也充满自信, 不过毕竟风险太大, 产线出问题, 影响了客户使用可不是闹着玩的. 为稳妥起见, 最好还是做灰度发布, 并且加一个开关, 一旦出问题, 马上对部分或全体用户关闭最新改动. 这个开关, 我们就叫做 Feature Toggle 特性开关.

我所在的开发团队以前采用过一种叫 Train Release 方式来发布产品, 一个大的 Train Release 包含多个组件, 既有PC客户端 (windows/macos/linux), 移动客户端 (ios/android), Web 站点和服务, 后台多种专用服务器.

我们一般分为三个大类

  • Web: 各种 Web 站点以及管理工具
  • Client: PC/Mobile 客户端
  • Server: 各种后台服务

每个大类又分为多个子类, 一个 train release 通常要做大半年, 有专门的 release manager 负责协调, 开发工程师发布新版本后, 还要经历 ATS/BTS/Production 的升级, 部署, 测试, 试用, 最终新版本交付到用户手中经常历时一年, 这就算比较顺利的了, 如果中间出现了什么周折风波, 一年多新版本才能上线.

这个玩法显然没办法满足用户的急迫的需求, 于是新的版本管理方法应运而生. 对于单个微服务来说, 我们希望能随时发布和上线,只要它通过了构建流水线的层层检查和测试, 可是对于整个系统来说, 成千上百个微服务每天不停地升级部署, 难免会在彼此集成的接口和流程方面有所疏漏, 所有我们对主要的几个产品线实施了 monthly release, 即每月发布一个版本. 当然, 重大问题的紧急修复是可以随时发布上线的.

  1. 月初: 主要需要和设计基本就绪
  2. 月中: 主要功能完成, 集成测试开始
  3. 月底: 经项目负责人及主要干系人验收通过, 发布新版本

现代的微服务提倡小迭代, 快修改, 快上线, 每月只能上一个版本, 这显然不能满足快速持续交付的需求, 但是产品的稳定性是必需保证的, 既不能由于频繁部署而导致系统出现问题, 也不能因噎废食限制新版本上线的频率.

如果我们想每天上线新的版本, 我们就必须要做好分支管理, 版本管理和特性开关的控制

分支管理

分支类型 Branch Types:

  • master branch 主分支
  • feature branch 功能分支
  • dev branch 开发分支
  • hot-fix branch 紧急修复分支

分支策略 Branch Strategy :

  • 小步快走, 多个开发分支, 一人一个, 未完成单元测试不准合并到其他分支
  • 采用少量或很短生命周期的 feature branch, 未完成集成测试不准合并到主分支
  • 产品分布只能在主分支上
  • 月度新功能在测试验收之前放在 feature branch 上
    每日从主分支更新改动,并在月底测试验收通过后合并到主分支, 并打上标签 tag
  • 紧急修复放在 hotfix 分支上
    代码审查和测试过后, 立即合并到主分支

版本管理

软件应用都有一个版本, 微服务也是如此, 版本可以用如下形式

mainVersion.minorVersion.microVersion.patchVersion

比如 2.2.0.147, 2.2.1.12, 四个小节够了, 不宜过多

在产品的 API 中, 我们通常还会加上 git commit 信息
比如

GET https://mdd.example.com/mdd/api/v1/build_info

{
    "version": "2.2.1",
    "buildNumber": "247",
    "gitTag": "2.2.1.247",
    "gitCommit": "c8c30d043982c902202d436564b2fd726e61de32",
    "gitBranch": "master"
}

新版本替换旧版本总有一个过程, 如果服务器比较少, 可以快速一次级升级, 但是对于大型 SaaS 服务提供商, 服务器数量至少上千台, 集群上百个, 数据中心遍布全球, 时区都不相同, 不可能一步到位. 同时, 由于对新版本新功能的稳定性,性能和运行效果并非十分有底, 也会采用灰度发布的策略, 逐个集群升级,

  1. 先升级副集群, 再升级主集群
  2. 先升级小客户, 再升级大客户
  3. 先升级亚太区, 再升级欧洲区, 最后升级北美区
    为避免对客户造成影响, 时间一般都在当地时间的凌晨

升级的时候应按以下步骤进行

  1. 先检查度量数据, 确认流量在主集群上运行正常,
  2. 把备份集群设置为 suspend 状态, 也就是在共享的数据存储表中改一下状态, 确保流量不会跑到备份集群上.
  3. 把备份集群中服务器逐个升级到最新版本
  4. 在备份集群上作一些简单的验证测试, 运行若干主要的 TaP 测试用例, 看测试结果是否有问题, 如果有问题, 且不是环境问题, 严重性不容轻视, 则立即回滚, 此次升级取消
  5. 观察度量数据, 确认已经没有活跃的用户在主集群上
  6. 将主集群设为 suspend 状态, GSLB 会根据 Health Check 的响应把流量分派到备份集群, 再重复上述 3, 4步, 升级主集群

由于升级需要一个过程, 产线上总有一段时间存在两个或两个以上的版本, 如果不加区分, 用户会比较困惑, 一会儿界面不一样了, 一会儿功能又变了, 过了一会儿, 可能又变回来了.

在 Sharding 比较严格的系统, 这个问题并不突出, 不同的用户会落在对应的特定集群上, 不会出现上述变来变去的情况.
我们做过的一个系统为了充分利用系统资源, 采用了在数据中心内部根据用量分派流量的设计, 这时就必须要好好考虑这个问题.

于是, 我们就引入了特性开关这个利器

特性开关 Feature Toggle

仅靠版本难以解决上面提到的用户体验因为版本变化造成的功能与界面来回变化的问题, 这时候, 我们应该使用特性开关 Feature Toggle

开关的类型

  1. feature/function toggle 功能开关
  2. release toggle 发布开关
  3. operation toggle 运维开关
  4. Permission toggle 授权开关
  5. Experiment toggle 体验开关

这里, 我们主要讨论功能或特性开关和发布开关

特性开关的层次

  • organization 组织
  • site 站点
  • user 用户
  • device 设备

特性开关的使用

前面我们提到开关有五种类型, 不同类型有不同的应用场景

A/B 测试

在一部分站点上打开开关, 另一部分站点上关闭开关, 互相对照测试, 收集并观察度量数据
也可以直接把开关的设置开放给用户, 用户按自己的喜好选择, 在站点改版常用这一招来看用户是否接受和喜欢新的变化

用户试用

针对特定的用户群体, 打开开关供用户试用和测试

特性发布

待所有所需最低版本都已升级部署完毕, 打开所有的相关特性开关, 正式发布这一新功能

特性开关服务 Feature Service

我们可以开发一个 Feature Service, 可以供开发和运维人员调用它的 API 来设置 Feature Toggle, 其他的 Service 可以调用它的 API 来读取这些 Feature Toggle 来决定应用不同的逻辑和行为, 而所有这些操作无需重启服务进程和更改配置文件.

FeatureToggle 比较简单的就定义一个布尔值 true or false , yes or no, 或者 on or off

比如

{
"enableAutoLogout": true
}

稍微复杂的可以有枚举值: off, test, on, 并且加上失效时间

{
"enableAutoLogout": "test",
"expireTime": "2018-12-31T23:59:59Z"
}

以 user level 的 feature toggle 举例如下

  • 设置 Feature Toggle
POST /featuretoggles/users

{
    "userIds": ["123", "456", "789"],
    "featureToggles":
    [
        {
            "key": "enableAutoLock",
            "value" "true"
        },
        {
            "key": "enableAutoLogin",
            "value" "true"
        }
    ]
}
  • 读取 Feature Toggle
GET /featuretoggles/users/:userId

{
    "featureToggles":
    [
        {
            "key": "enableAutoLock",
            "value" "true"
        },
        {
            "key": "enableAutoLogin",
            "value" "true"
        }
    ]
}

具体的实现很简单, 利用传统DB 或者 Redis, Cassandra 这样的 NOSQL 存储读写就可以了, 存储结构示例如下

Table FeatureToggle:

level Id toggleName toggleValue
org 123 enableRateLimit true
site 456 enableCircuitBreaker true
user 789 enableAutoLock true

相关类库

Java 工具库

  • Togglz
  • FF4J
  • Fitchy
  • Flip

Python 工具库

  • Gargoyle
  • Gutter

.NET, C# 工具库

  • FeatureSwitcher
  • NFeature
  • FlipIt
  • FeatureToggleNET
  • List on NUget
  • FeatureBee

Ruby and Ruby on Rails 工具库

  • rollout
  • feature_flipper
  • flip
  • setler
  • switches
  • FluidFeatures

参考资料

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,681评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,710评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,623评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,202评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,232评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,368评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,795评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,461评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,647评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,476评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,525评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,226评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,785评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,857评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,090评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,647评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,215评论 2 341

推荐阅读更多精彩内容

  • Git 仓库申请流程 1. 开发主管向Git 管理员提交Git 仓库申请【邮件:发送给Git 管理员,抄送给项目经...
    骚包霸天虎阅读 2,068评论 0 0
  • 写作于:2016-09 修改于:2017-12 引言 微服务体系的发展并不是一蹴而就的,经过了2014年前后的低潮...
    巾梵阅读 1,732评论 0 3
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,571评论 18 139
  • 1 Git Flow介绍 我们都知道, 在 git 的分支功能相对 svn 确实方便许多,而且也非常推荐使用分支来...
    七寸知架构阅读 7,815评论 20 68
  • 1点多入睡,5点多醒来,脑海中全是【余歌演说】老师说的课程,感觉自己还在厦门听课没回来。 七月中又要带《晋组团》了...
    蓝天虹阅读 174评论 0 0