写点什么

如何将代码部署时间减少 95%?

  • 2019-09-04
  • 本文字数:2664 字

    阅读完需:约 9 分钟

如何将代码部署时间减少95%?

本文作者所在的公司 Plaid 是一家金融科技公司,该公司搭建了一个技术平台,使应用程序能够与用户的银行账户建立联系。随着公司的发展,基础设施规模在不断扩大。目前,这家公司运行着 20 多个内部服务,每天在核心服务上部署 50 多个代码提交。因此,最小化部署时间对于最大化迭代速度至关重要,一个快速的部署过程能够迅速进行 Bug 修复并运行平稳的连续部署系统



几个月前,我们注意到,银行集成服务部署缓慢正在影响团队发布代码的能力。工程师要花至少 30 分钟才能通过多个过渡环境和生产环境构建、部署和监视变更,这将消耗大量宝贵的工程时间。随着团队越来越大,我们每天发布的代码也越来越多,这一点变得越来越不可接受。


虽然我们计划实现长期改进,比如将基于 Amazon ECS 服务的基础设施迁移到 Kubernetes 上,但是,为了在短期内提高迭代速度,有必要快速解决下这个问题。因此,我们决定实践自定义的“快速部署”机制。

Amazon ECS 部署的高延迟

我们的银行集成服务由 4000 个 Node.js 进程组成,这些进程运行在专用的 Docker 容器上,这些容器托管并部署在 Amazon 的容器编排服务ECS上。在分析了我们的部署过程之后,我们将增加的部署延迟归结到三个不同的组件上:


  • 启动任务会导致延迟。除了应用程序启动时间之外,ECS 健康检查也会导致延迟,它决定容器何时准备好开始处理流量。控制这个过程的三个参数是 interval、retry 和 startPeriod。如果没有对健康检查进行仔细调优,容器可能会卡在“启动”状态,即使它们已经准备好为流量服务。

  • 关闭任务会导致延迟。当我们运行ECS服务更新时,一个 SIGTERM 信号被发送到所有正在运行的容器。为了处理这个问题,我们在应用程序代码中使用了一些逻辑,以便在完全关闭服务之前占用现有资源。

  • 我们启动任务的速度限制了部署的并行性。尽管我们将MaximumPercent参数设置为 200%,但是 ECS start-taskAPI 调用的硬限制是每个调用只能执行 10 个任务,而且速度有限。我们需要调用 400 次才能将所有容器投入生产。

方法探索

我们考虑并试验了一些不同的潜在解决方案,以逐步实现总体目标:


  • 减少生产中运行的容器总数。这当然是可行的,但它涉及到对服务架构进行重大修改,以使其能够处理相同的请求吞吐量,在进行这样的修改之前,还需要进行更多研究。

  • 通过修改健康检查参数来调整 ECS 配置。我们尝试通过减少 interval 和 startPeriod 的值来加强健康检查,但是 ECS 在启动时将健康的容器错误地标记为不健康,导致我们的服务永远无法完全稳定在 100%健康状态。由于根本问题(ECS 部署缓慢)依然存在,对这些参数进行迭代是一个缓慢而费力的过程。

  • 在 ECS 集群中启动更多实例,以便可以在部署期间同时启动更多任务。这样做可以减少部署时间,但不会减少太多。从长远来看,这也不划算。

  • 通过重构初始化和关机逻辑优化服务重启时间。只需要做一些小小的修改,我们就能够在每个容器中节省大约 5 秒的时间。


尽管这些更改将总体部署时间减少了几分钟,但是我们仍然需要将时间提高至少一个数量级,才能认为问题已解决。这将需要一个根本不同的解决方案。

初步解决方案:利用 Node Require Cache“热重载”应用程序代码

Node require cache是一个 JavaScript 对象,它根据需要缓存模块。这意味着多次执行 require(‘foo’)或 import * as foo from 'foo’只会在第一次时请求 foo 模块。神奇的是,删除 require cache 中的条目(我们可以使用全局 require.cache 对象访问)将迫使 Node 在下次导入模块时从磁盘重新读取该模块。


为了绕过 ECS 部署过程,我们尝试使用 Node 的 require cache 在运行时执行应用程序代码的“热重载”。一旦接收到外部触发(我们将其实现为银行集成服务上的gRPC端点),应用程序将下载新代码来替换现有的构建,清除 require cache,从而强制重新导入所有相关模块。通过这种方法,我们能够消除 ECS 部署中存在的大部分延迟,优化整个部署过程。


Plaiderdays(我们的内部黑客马拉松)期间,来自不同团队的一组工程师聚在一起,为我们所谓的“快速部署”实现了一个端到端的概念验证。当我们一起设法构建一个原型时,有一件事似乎出了问题:如果下载新构建的 Node 代码也试图使失效缓存,那么下载器代码本身将如何重新加载就不清楚了。(有一种方法可以解决这个问题,就是使用Node EventEmitter,但是会给代码增加相当大的复杂性)。更重要的是,还存在运行未同步代码版本的风险,这可能导致应用程序意外失败。


由于我们不愿意在银行集成服务的可靠性上妥协,这种复杂性需要重新考虑“热重载”方法。

最终解决方案:重新加载进程

在过去,为了在所有服务中运行一系列统一的初始化任务,我们编写了自己的进程封装器,它的名称非常贴切,叫做 Bootloader。Bootloader 的核心包含设置日志管道、转发信号和读取 ECS 元数据的逻辑。每个服务都是通过将应用程序可执行文件的路径以及一系列标志传递给 Bootloader 来启动的,这些文件在执行初始化步骤之后会作为子进程执行。


我们没有清除 Node 的 require cache,而是在下载预期的部署构建后,使用特殊的退出代码来调用 process.exit 实现服务更新。我们还在 Bootloader 中实现了自定义逻辑,以触发使用此代码退出的任何子进程的进程重载。与“热重载”方法类似,这使我们能够绕过 ECS 部署的成本并快速引导新代码,同时避免“热重载”的陷阱。此外,Bootloader 层的这种“快速部署”逻辑允许我们将其推广到在 Plaid 运行的任何其他服务。


下面是最终解决方案:


  • Jenkins 部署管道向银行集成服务的所有实例发送 RPC 请求,指示它们“快速部署”特定的提交散列。

  • 应用程序接收 gRPC 请求进行快速部署,并根据接收到的提交散列从Amazon S3下载构建好的压缩包。然后,它替换文件系统上的现有构建,并使用 Bootloader 识别的特殊退出代码退出。

  • Bootloader 看到应用程序使用这个特殊的“Reload”退出代码退出,然后重新启动应用程序。

  • 服务运行新的代码。


下面这张图简单说明了这个过程。


结果

我们能够在 3 周内交付这个“快速部署”项目,并将 90%生产容器的部署时间从 30 多分钟减少到 1.5 分钟。



上图显示了我们为银行集成服务部署的容器数量(按提交表示为不同的颜色)。如果注意下黄线,就可以看到它在 12:15 左右增长趋于平稳,这代表我们的容器长尾仍然在占用资源。


这个项目极大提高了 Plaid 集成工作的速度,允许我们更快地发布特性及进行 Bug 修复,并将浪费在上下文切换和监视仪表板上的工程时间最小化。这也证明了我们的工程文化,即通过黑客马拉松得来的想法实现具有实质性影响的项目。


原文链接:


How We Reduced Deployment Times by 95%


2019-09-04 10:118348
用户头像

发布了 768 篇内容, 共 518.2 次阅读, 收获喜欢 1574 次。

关注

评论

发布
暂无评论
发现更多内容

汇聚全球智慧·共绘软件蓝图,2025北京软博会

AIOTE智博会

软博会 世亚软博会 北京软博会

鸿蒙生态崛起,开发者如何抓住这波“红利”?

最新动态

2024年中国IT用户满意度调研结果公布

Geek_2d6073

浅谈运营商政企存量客户运营

鲸品堂

大数据 产品运营 运营商 企业号 2024年10月PK榜

资源成本降低60%,揭秘Serverless的省钱秘籍

华为云开发者联盟

容器 运维 #Serverless CCE

代码审查不足?教你改善流程的策略

爱吃小舅的鱼

代码审查

Java EasyExcel 导出报内存溢出如何解决

不在线第一只蜗牛

Java 内存

Laravel后台极速开发框架 - 集成日历组件

YangGe

laravel

语音识别模型

霍格沃兹测试开发学社

8大主流全生命周期项目管理工具对比

爱吃小舅的鱼

全生命周期项目管理工具

如何选择项目管理软件?8款工具详解

爱吃小舅的鱼

项目管理软件

到底什么学历可以胜任程序员?

秃头小帅oi

阿里巴巴商品搜索API返回值中的关键信息点

技术冰糖葫芦

API 接口 API 测试 API 协议 API 优先

Vector 增加 GreptimeDB 日志写入支持,连接数十种数据源

Greptime 格睿科技

数据库 vector 集成

专业的技术、卓越的服务,为企业提供一体化测试服务,赋能企业发展创新

测吧(北京)科技有限公司

测试

高可用负载均衡实践

俞凡

架构

倒计时1天 | 袋鼠云秋季发布会明日10:00开幕,我们云上见!

袋鼠云数栈

实现员工职业目标与项目目标对齐的策略

爱吃小舅的鱼

目标对齐

掌握数据,赢得市场 —— 淘宝商品详情API让电商运营更精准

技术冰糖葫芦

API 接口 API 测试 API 协议 API 优先

香港 Web3 宣言两周年专访:传统企业转型 Web3 遇阻,香港虚拟资产之路如何走得更远?

TechubNews

团队沟通技巧:管理层与技术人员的协作之道

爱吃小舅的鱼

团队沟通技巧

《一篇就够系列》之HTTP详解,覆盖高频面试考点!

EquatorCoco

面试 网络协议 HTTP

云电脑的性价比高么

青椒云云电脑

云电脑

腾讯云的相关DDoS攻击问题概览

网络安全服务

腾讯云 服务器 DDoS 腾讯云服务器 DDoS 攻击

利用 Vector 将 Kafka 中的日志数据高效写入 GreptimeDB

Greptime 格睿科技

kafka 时序数据库 vector

淘宝商品类目API的获取与应用探索

科普小能手

API 接口 API 测试 淘宝API接口 淘宝数据采集 淘宝评论API

哪些项目管理软件值得一试?9款推荐清单

爱吃小舅的鱼

项目协同进度软件

CQ社区版 v2024.10 | 支持k8s、helm部署!

BinTools图尔兹

k8s Helm 数据安全 数据库管理 CloudQuery

袋鼠云产品功能更新报告12期|让数据资产管理更高效

袋鼠云数栈

深度解读GaussDB逻辑解码技术原理

不在线第一只蜗牛

数据库 oracle

测试外包服务 | 从人员外包到测试工具、测试平台,提供全方位的测试解决方案~

测吧(北京)科技有限公司

测试

如何将代码部署时间减少95%?_文化 & 方法_Evan Limanto_InfoQ精选文章