Lyft如何通过DevOps提升扩展微服务的生产力? - Garrett


该案例研究是关于在完成向微服务的整体迁移以及开发工具中出现的下一个约束之后提高 Lyft 的生产力。
2018 年底,Lyft 工程完成了将我们最初的 PHP 单体分解为 Python 和 Go 微服务的集合。几年后,微服务在允许团队独立运营和交付服务方面取得了很大的成功。
本文由四部分组成的系列将介绍为 Lyft 工程团队提供服务的开发环境,因为它从 100 名工程师和少数服务发展到 1000 多名工程师和数百个服务。我们将讨论导致我们远离大多数这些环境的扩展挑战,以及主要基于大量集成测试(通常接近端到端)的测试方法,支持以本地为中心的方法单独测试组件。

  • 第一部分:开发和测试环境的历史(这篇文章)
  • 第二部分:优化本地快速开发
  • 第三部分:使用覆盖在登台中扩展服务网格
  • 第四部分:使用自动化验收测试控制部署

 
开发和测试环境的历史
我们对综合开发环境的第一次重大投资始于 2015 年,当时我们达到了 100 名工程师。几乎所有的开发仍然发生在 PHP 单体上,一些微服务开始出现用于不同的用例,例如驱动程序载入。
预计我们需要服务的工程师和服务数量会增加,因此迁移到容器很有意义。我们的计划是构建一个基于 Docker 的容器编排环境——当时仍处于起步阶段——首先为开发人员提供测试服务,然后扩展到生产,在那里我们可以从更便宜、扩展速度更快的多租户工作负载中受益。
  • 使用 Devbox 进行本地开发

Devbox——Lyft 的盒装开发环境——于 2016 年初发货,并很快被大多数工程师采用。Devbox 的工作方式是代表用户管理本地虚拟机——无需他们安装或更新软件包、配置runit以启动服务、添加共享文件夹等。虚拟机运行后,只需一个命令和几分钟即可拉取最新版本的映像、创建/种子数据库、启动特使代理sidecar 以及开始发送请求所需的一切。
这是之前的一次精彩升级,我们为每个开发人员和服务组合手动配置 EC2 实例,这使得设置和保持最新变得乏味。我们第一次有了一种一致、可重复且简单的方法来跨多个服务进行开发。
  • 使用 Onebox 进行远程开发

对可以与其他工程师或功能(如设计)共享的更长寿命环境的需求很快变得明显,于是 Onebox 诞生了。Onebox 本质上是 EC2 实例上的 Devbox,具有许多使用户远离 Devbox 的好处。我们将这些托管在具有 16 个 vCPU 和 122GiB 内存的 r3.4xlarge 实例上,这些实例比工程师随身携带的 MacBook Pro 强大得多。Onebox 可以运行更多服务并更快地下载容器镜像(因为在 AWS 中),更不用说避免 VirtualBox 导致笔记本电脑爱好者模仿喷气发动机。
  • 集成测试

除了单元测试之外,Onebox 的云基础架构也非常适合在 CI 上运行集成测试。一个服务将简单地在一个manifest.yaml文件中定义它需要的一组依赖项,一个临时的 Onebox 将启动这些服务并对每个拉取请求执行测试。许多服务,尤其是靠近移动客户端的组合服务,构建了大型集成测试套件以应对中断。事后分析通常以添加新集成测试的操作项结束。有了如此灵活而强大的测试能力,单元测试逐渐退居次席。
  • 暂存环境

Lyft 的临时环境几乎与生产环境相同——除了更小的占用空间和没有生产数据——并且所有服务都在生产的途中部署在那里。尽管不是开发人员环境,但由于它在端到端测试中发挥的作用越来越重要,因此 staging 值得讨论。
在 Devbox 和 Onebox 于 2017 年初发布后不久,我们也在解决一种不同的增长问题:负载测试。导致拼车流量激增的事件(例如新年前夜和万圣节)会暴露我们系统中的瓶颈,这通常会导致中断。为了解决这些问题,我们构建了一个用于大规模模拟游乐设施的框架。该框架针对我们的生产环境,协调了数以万计具有不同配置的模拟用户(例如,经常取消的洛杉矶司机)并将 Lyft 视为黑匣子。
作为在登台中测试模拟框架本身的副产品,我们意识到生成的流量对于一般的端到端测试也很有价值。在登台中不断使用公共端点为部署提供了很好的信号。例如,如果部署破坏了让乘客下车的端点,部署的作者几乎会立即看到错误日志和警报。模拟还不断为用户、乘车、支付等生成最新数据,从而减少了开发过程中所需的大量手动测试设置时间。随着负载测试工作使暂存变得比以往任何时候都更加现实和有用,团队将 PR 分支部署在那里作为获得真实数据反馈的一致地方变得很普遍。
 
需要突破的约束问题
快进到 2020 年——在引入 Devbox 和 Onebox 作为容器化开发环境四年之后——尽管我们尽了最大努力,“Lyft-in-a-box”风格的环境仍在努力跟上。使用这些环境的工程师增加了十倍,现在有数百个微服务支持更复杂的业务。虽然在依赖较小的服务上开发仍然相当有效,但大多数开发发生在已经建立了巨大依赖树的服务上——这使得在 CI 上启动环境或运行测试变得非常缓慢。
虽然这些环境和测试能力是强大和方便,他们到达造成弊大于利的一个点。我们构建了一个为测试少数服务而优化的系统,并且没有重新评估我们的策略,因为服务的数量——由我们的 PHP 单体的分解加速了——从 5 增长到 50、50 到 100,甚至更多。为开发启动大量服务不仅需要大量的努力来维护和扩展,而且还迫使开发人员不断地考虑整个系统而不是一次一个组件,从而削弱了整个开发人员的生产力.
。。。。
 
改变路线
大约一年前开始将我们的开发环境迁移到 Kubernetes 后,工程资源的变化是我们缩小规模并重新审视更大方向的催化剂。维护基础设施以支持这些按需环境已经变得过于昂贵,而且只会随着时间的推移而恶化。解决我们的情况需要对我们开发和测试微服务的方式进行更根本的改变。是时候用对由数百个微服务组成的系统来说可持续的替代方案来取代 CI 上的 Devbox、Onebox 和集成测试了。
仔细观察开发人员如何使用现有环境,我们确定了三个对维护至关重要且需要投资的关键工作流程:
  1. 本地开发:对于任何给定的服务,运行单元测试或启动 Web 服务器并发送请求应该是简单且超快的。
  2. 手动端到端测试:测试给定更改在更大系统中的执行情况是许多工程师依赖的关键工作流程。我们希望扩展暂存功能,使开发人员能够更轻松、更安全地以隔离方式进行测试。
  3. 自动化的端到端测试:尽管过度依赖这种测试,但如果没有自动化 E2E 测试提供的信心,我们就无法继续每天发送数百次更改。我们将保留一小部分有价值的测试作为验收测试——在部署到生产期间运行的测试。

本系列的以下帖子将深入探讨这三个领域中的每一个,以讨论问题领域、我们如何解决这些问题以及我们学到了什么。请留意关于本地开发的下一篇文章,其中将分享更多关于我们在本地开发时用于检查、模拟和改变网络请求的工具的信息。