写点什么

如何将代码部署时间减少 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:118413
用户头像

发布了 808 篇内容, 共 555.3 次阅读, 收获喜欢 1588 次。

关注

评论

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

提升数据质量的四大有效方式

树上有只程序猿

数字化 数据质量

已确认!将数据安全管理纳入操作风险管理范畴

原点安全

什么是MES,什么是WMS,MES与WMS有什么区别?

优秀

MES系统 WMS系统

ACM图灵大会开幕,王海峰解读文心大模型3.5最新进展

飞桨PaddlePaddle

人工智能 百度 paddle 飞桨 百度飞桨

一文帮你看懂ChatGPT

永利app贵宾会网址

人工智能 AI 科技 ChatGPT

关于远程直接内存访问技术 RDMA 的高性能架构设计介绍 | 龙蜥技术

OpenAnolis小助手

开源 数据 cpu 龙蜥大讲堂 RDMA

程序员在今年这种行情下如何快速找到合适的工作?

程序员小毕

程序员 后端 面试题 架构师 java面试

亚马逊云科技如何助力中国企业建立“出海”的云端母港?

Lily

openGauss内核分析(三):SQL解析

daydayup

【我和openGauss的故事】openGauss易知易会的几个实用特性

daydayup

基于P2P技术的远距离传输大型文件解决方案

镭速

p2p 文件传输 远距离传输大型文件

龙蜥社区用户案例征集开始啦,欢迎投稿!

OpenAnolis小助手

数据 操作系统 征稿 案例 龙蜥社区

探索运营商渠道佣金数字化运营

鲸品堂

数字化转型 企业 运营商 电信运营商 企业号 7 月 PK 榜

无门槛访问AI智能对话+最强AI绘画的方式

大数据技术指南

AI绘画 ChatGPT

杭州快盈施佳:基于支付宝小程序云的文旅数智新实践

TRaaS

小程序

openGauss获2022年度创新产品奖!

daydayup

openGauss内核分析(四):查询重写(二)

daydayup

活动回顾|阿里云 Serverless 技术实战与创新成都站回放&PPT下载

Serverless Devs

负载均衡 Serverless 云原生 弹性计算 FC

低代码在数智化时代中的应用

力软低代码开发平台

MegEngine Python 层模块串讲(下)

MegEngineBot

深度学习 开源

【我和openGauss的故事】openGauss的WDR报告解读

daydayup

NFTScan | 07.24~07.30 NFT 市场热点汇总

NFT Research

NFT\

低代码平台技术分享官丨日志实时隔离,助力高效发布

inBuilder低代码平台

低代码 低代码平台

⻜桨⼤模型推理部署⾼性能优化

Baidu AICLOUD

大模型推理 AI 框架

SQL 执行计划管理(SPM)

KaiwuDB

KaiwuDB SPM

从0到1!得物如何打造通用大模型训练和推理平台

得物技术

算法 大模型 ChatGPT LLM

最全的3D动画软件介绍来了!良心总结9款3D动画制作必备软件

龙智—DevSecOps解决方案

Unity 虚幻引擎 maya 3D动画软件 Houdini

祝贺!openGauss社区技术委员会主席李国良当选2023 IEEE FELLOW

daydayup

openGauss+Wasm:构建安全高效的UDF执行引擎

daydayup

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