【转】Yelp是如何实现每天运行数百万个测试的

Yelp每天要运行数百万个测试,确保开发人员提交的代码不会对已有的功能造成破坏。如此巨大规模的测试,他们是怎么做到的呢?以下内容翻译自 Yelp 的技术博客,并已获得翻译授权,查看原文 How Yelp Runs Millions of Tests Every Day 。

开发速度对于一个公司的成败来说是至关重要的。我们总是通过减少测试、部署和监控变更的时间来提升开发效率。为了让开发者能够安全地提交代码,我们每天通过内部的分布式系统 Seagull 运行了超过数百万个测试。

Seagull 是什么?

Seagull 是一个具备容错能力和弹性的分布式系统,我们用它来并行执行我们的测试套件。我们使用了如下技术来构建 Seagull 。

  • Apache Mesos(用于管理 Seagull 集群的资源)
  • AWS EC2(为 Seagull 和 Jenkins 集群提供实例)
  • AWS DynamoDB(保存调度器的元数据)
  • Docker(为测试要用到的服务提供隔离)
  • Elasticsearch(跟踪测试的运行时间和集群数据的使用情况)
  • Jenkins(构建代码并运行 Seagull 调度器)
  • Kibana 和 SignalFx(用于监控和告警)
  • AWS S3(作为测试日志的真实来源)

挑战

在将我们的单体 Web 应用 yelp-main 的新代码部署到生产环境之前,Yelp 的开发人员针对 yelp-main 的特定版本运行了整个测试套件。开发人员通过触发 seagull-run 作业来运行测试,这个作业将会在我们的集群上安排调度以便运行测试用例。这里需要考虑两方面的因素。

  • 性能:每一个 seagull-run 作业都有将近 10 万个测试用例,如果逐个运行它们需要差不多 2 天的时间。
  • 规模:一般情况下,每天会有超过 300 个 seagull-run 作业被触发,高峰期有 30 到 40 个作业并行运行。

我们所面临的挑战是如何在分钟级别运行每一个 seagull-run 作业,而不是按天来运行,同时还能保持较低的成本。

Seagull 的工作原理

首先,开发人员在控制台触发 seagull-run,它会启动一个 Jenkins 作业,用于编译代码,并生成测试清单。这些测试清单被组合在一起,传递给一个调度器,调度器将会在 Seagull 集群上执行测试。最后,测试结果被保存到 Elasticsearch 和 S3 上。

1.一个开发人员为某个版本的代码(基于 git 某个分支的 SHA 值)触发了一个 seagull-job,我们假设 git 分支的名字叫作 test_branch。

2.为 test_branch 生成代码包和测试清单,并上传到 S3 上。

3.Bin Packer 获取测试清单和测试历史时间元数据,用于创建多个包含了测试用例的 bundle。如何进行有效的 bundle 其实是一个装箱问题,我么使用了如下两种算法来解决这个问题。至于使用哪一种算法,由开发人员传给 Seagull 的参数来决定。

  • 贪婪算法(Greedy Algorithm):测试用例先是按照它们的历史测试时长来排序,然后我们开始按照 10 分钟的工作量(测试用例)来填充 bundle。
  • 线性编程(Linear Programming):如果出现了测试依赖,一个测试需要与同一个 bundle 里的另一个测试一起运行。对于这种情况,我们将会使用线性编程。线性编程方程式的目标函数和约束定义如下。

    1. 目标函数:最小化生成 bundle 的数量
    2. 主要的约束

      • 单个 bundle 的运行时长不超过 10 分钟
      • 每个测试只能存在于一个 bundle 里
      • 具有依赖关系的测试需要被放在同一个 bundle 里

我们使用了 Pulp 来解开这个方程式。

# 目标函数:
problem = LpProblem('Minimize bundles', LpMinimize)
problem += lpSum([bundle[i] for i in range(max_bundles)]), 'Objective: Minimize bundles'
# 其中的一个约束:
for i in range(max_bundles):sum_of_test_durations = 0for test in all_tests:sum_of_test_durations += test_bundle[test, i] * test_durations[test]problem += (sum_of_test_durations) <= bundle_max_duration * bundle[i], ''

在这里,bundle 和 test_bundle 是 LpVariable 类型,max_bundles 和 bundle_max_duration 是整数。

一般情况下,我们会在线性编程约束里考虑测试用例的 setup 和 teardown 时长,不过为了简单起见,我们在这里把它们忽略了。

4.在 Jenkins 服务器上启动一个调度器进程,它将会获取 bundle,然后启动一个 mesos 框架。我们为每一个 seagull-run 创建一个新的调度器。每次运行会生成300多个 bundle,每个 bundle 大概需要 10 分钟的运行时间。调度器为每一个 bundle 创建了一个 mesos 执行器,并被安排在 Seagull 集群上执行,只要 Mesos Master 能够提供可用的资源。

5.在执行器被安排到集群上之后,执行器内部将执行如下几个步骤。

每个执行器启动一个沙箱,并从 S3 上下载软件包(它们是在第二步时上传到 S3 上的)。测试服务所依赖的 Docker 镜像被下载下来,用于启动 docker 容器(也就是服务)。在所有的容器都运行起来之后,开始执行测试。最后,测试结果和元数据被保存到 Elasticsearch(ES)和 S3 上。我们使用了内部的代理服务 Apollo 将数据写到 ES 上。

如果你处在一个分布式环境里,那么遭遇主机崩溃是一件不可避免的事情。不过,Seagull 具有容错能力。

例如,假设一个调度器需要调度两个 bundle。Mesos 将代理(A1)的资源分配给调度器。假设调度器认为已经分配到足够的资源,那么两个 bundle 就会被安排在 A1 上。A1 因为某些原因发生崩溃,那么 Mesos 会让调度器知道 A1 已经崩溃了。调度器的任务管理器决定进行重试,或者直接取消任务。如果进行了重试,当 Mesos 提供了足够的资源时(比如 A2),那么 bundle 就会重新被安排执行。如果任务被取消,调度器会将这些 bundle 的测试用例标记为未执行。

6.Seagull UI 通过 Apollo 从 ES 上获取测试结果,并将它们加载到一个 UI 上,让开发人员可以看到结果。如果测试通过,就可以进行部署!

我们所谈论的规模是多大?

我们每天有 300 多个 seagull-run,高峰期每小时有 30 到 40 个。它们为此每天启动超过 200 万个 Docker 镜像。为了应付这些场景,我们的 Seagull 集群在高峰期需要差不多 1 万个 CPU 核心。

这种规模所带来的挑战

为了保持测试套件的及时性,特别是在高峰时期,我们需要确保 Seagull 集群里有数百个可用的实例。我们曾经使用过AWS ASG 和 AWS On-Demand 实例,不过它们对于我们来说太昂贵了。

为了降低成本,我们开始使用一个叫作 FleetMiser 的内部工具来维护 Seagull 集群。FleetMiser 是一个自动扩展引擎,我们用它基于一些信号来扩展集群,比如当前集群的使用情况、管道里运行的工作负荷数量,等等。它有两个主要的组件。

  • AWS Spot Fleet:AWS 的 Spot 实例比 On-Demand 实例要便宜,Spot Fleet 为使用 Spot 实例提供了简单易用的接口。
  • 自动伸缩:我们对集群的使用是动态变化的,主要集中在太平洋时间 10:00 到 19:00,开发人员的主要工作都集中在这段时间。为了能够自动伸缩,FleetMiser 使用了集群的当前和历史数据。每天,Seagull 集群在 1500 个 CPU 核心到 10000 个 CPU 核心之间伸缩。

自动伸缩:几周前的容量数据

FleetMiser 为我们节省了 80% 的集群成本。而在那之前,我们的集群部署在 AWS On-Demand 实例上,无法进行自动伸缩。

我们已经达成了什么样的目标?

Seagull 将测试结果的时间从 2 天降低到 30 分钟,而且减少了大量的运行成本。我们的开发人员能够自信地提交代码,无需等待数个小时甚至数天来验证他们提交的变更没有造成任何破坏。

转载于:https://www.cnblogs.com/wangyayun/p/6828942.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/429317.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

go语言linux下载文件,学习 Go 语言(Golang)PDF

1、简介Go 编程语言是一个使得程序员更加有效率的开源项目。Go 是有表达力、简 洁、清晰和有效率的。它的并行机制使其很容易编写多核和网络应用&#xff0c;而新奇的类型系统允许构建有性的模块化程序。Go 编译到机器码非常快 速&#xff0c;同时具有便利的垃圾回收和强大的运…

数据同步这点事

最近一段时间&#xff0c;在做数据ETL相关的事&#xff0c;结合实践以及自己的思考&#xff0c;记录下来&#xff0c;以做参考。 概述 一般来说&#xff0c;数据团队自己是很少生产数据的&#xff0c;一般都是对业务线的数据进行分析加工&#xff0c;从而让数据产生价值。一方面…

linux下的awk程序在哪里编写,如何编写awk命令和脚本

awk命令是处理或分析文本文件(尤其是按行和列组织的数据文件)的强大方法.您可以从命令行运行简单的awk命令. 应该将更复杂的任务作为awk程序(所谓的awk脚本)写入文件.awk命令的基本格式如下:awkpattern {action}输入文件>输出文件这意味着: 占用输入文件的每一行&#xff1b…

linux中用截取一些信息,Linux如何使用cut命令截取文件信息

在Linux众多命令中&#xff0c;cut命令可用来截取文件信息&#xff0c;截取Linux字符串&#xff0c;下面将针对cut命令的用法做个详细介绍&#xff0c;感兴趣的朋友可以来学习下。cut命令有截取的意思&#xff0c;可从linux文件或者标准输入中读取内容并纵向截取所需信息列的一…

201521123057 《Java程序设计》第12周学习总结

1. 本周学习总结 1.1 以你喜欢的方式&#xff08;思维导图或其他&#xff09;归纳总结多流与文件相关内容。 2. 书面作业 1.字符流与文本文件&#xff1a;使用 PrintWriter(写)&#xff0c;BufferedReader(读) 将Student对象(属性&#xff1a;int id, String name,int age,doub…

tomcat 下载

点project 关闭防火墙才可以让别人访问自己 转载于:https://www.cnblogs.com/feathe/p/6853491.html

linux消息框架,远程处理器消息框架 - 基于Linux 简化 AMP 配置使其更方便更动态地分配资源...

核心的 rpmsg 框架起到开关的作用&#xff0c;根据消息中包含的目的地址将消息传送到相应端点。由于消息报头包含源地址&#xff0c;因此可在不同处理器之间建立专用连接。命名服务处理器可通过向 rpmsg 框架的命名服务发送消息&#xff0c;以动态宣布特定服务。命名服务功能本…

jQuery笔记——选择器

jQuery 最核心的组成部分就是&#xff1a;选择器引擎。它继承了 CSS 的语法&#xff0c;可以对 DOM 元 素的标签名、属性名、状态等进行快速准确的选择&#xff0c;并且不必担心浏览器的兼容性 常规选择器 根据id选择元素就是使用#&#xff0c;还有两种其他选择元素的方式&…

c语言实现NRZ编码,CSC1001-课后笔记

前言&#xff1a;为什么编写此文1. 根据费曼的学习方法Pretend to teach your topic to a classroom. Make sure youre able to explain the topic in simple terms. 假装你在教室里向学生解释这个主题&#xff0c;用尽量简单的词汇去描述它&#xff0c;力求学生能听懂。(听众…

《Java技术》第八次作业

《Java技术》第八次作业 &#xff08;一&#xff09;学习总结 1.用思维导图对本周的学习内容进行总结。 2.通过实验内容中的具体实例说明在执行executeUpdate&#xff08;&#xff09;方法和executeQuery&#xff08;&#xff09;方法中使用动态参数时&#xff0c;为什么要使用…

android 短信 aapp,谈谈App的统一跳转和ARouter

App中每次页面跳转,都需要调用统一导航, 它用的非常频繁, 有必要对它进行一下梳理. 让他能用起来简单方便, 同时能支持各种常用的跳转业务场景.一. Android跳转遇到的问题1.intent-filter跳转不好管理Intent intent new Intent();intent.setAction(Intent.ACTION_SENDTO);inte…

android 自定义spnner弹出框,PopupWindow,ListView实现自定义Spinner

最终的效果图,点击86弹出popup这里写图片描述PupupWindow的布局文件为一个ListView 作为pupup的主体内容android:orientation"vertical"android:layout_width"match_parent"android:layout_height"match_parent">android:id"id/register…

hdu 6026 Deleting Edges(最短路计数)

题目链接&#xff1a;hdu 6026 Deleting Edges 题意&#xff1a; 给你n个点&#xff0c;和一个邻接矩阵&#xff0c;非0表示有边&#xff0c;0表示没边。 现在让你删一些边&#xff0c;构成一棵树&#xff0c;使得每个点到0这个点的距离为没删边之前的最短路。 问有多少棵这样的…

Xamarin XAML语言教程构建进度条ProgressBar

Xamarin XAML语言教程构建进度条ProgressBar Xamarin XAML语言教程构建进度条ProgressBar&#xff0c;ProgressBar被称为进度条&#xff0c;它类似于没有滑块的滑块控件。进度条总是水平放置的。本节将讲解如何使用进度条。注意&#xff1a;进度条在各个平台下基本相同&#xf…

mac删除android sd卡,如何从mac完全删除android及其所有文件?

前一段时间我试图让科尔多瓦工作&#xff0c;但android模拟器永远不会启动。它只是挂着一个黑色的屏幕。如何从mac完全删除android及其所有文件&#xff1f;我原来是用brew install android-sdk安装的。然后我读了一个糟糕的地方。所以我已经删除它并安装了Android Studio。无论…

201521123023《Java程序设计》第13周学习总结

1. 本周学习总结 &#xff08;1&#xff09;网络中为了进行数据交换&#xff08;通信&#xff09;而建立的规则、标准或约定(语义语法规则)称之为协议&#xff08;常用http/ftp&#xff09; &#xff08;2&#xff09;大致熟悉了TCP协议&#xff0c;但是UDP怎么辣么蓝&#xff…

QML与C++交互:登陆界面设计

QML与C交互:登陆界面设计 本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明. 环境&#xff1a; 主机:WIN7 开发环境:Qt5.2.1 说明: QML设计前台界面,C后台负责逻辑 效果图: 源码: 前台qml文件 login.qml /******************************************************…

html怎么在字体中加波浪线,CSS3实现文字波浪线效果

前言css的设计之巧妙&#xff0c;实现之精妙&#xff0c;细细寻味&#xff0c;其妙非凡&#xff0c;妙不可言。这波浪线&#xff0c;取巧的运用了linear-gradient属性&#xff0c;合角度、颜色、位置于一体&#xff0c;配合background-size&#xff0c;background-repeat&#…

NET Core 指令启动

ASP.NET Core 是新一代的 ASP.NET&#xff0c;早期称为 ASP.NET vNext&#xff0c;并且在推出初期命名为ASP.NET 5&#xff0c;但随着 .NET Core 的成熟&#xff0c;以及 ASP.NET 5的命名会使得外界将它视为 ASP.NET 的升级版&#xff0c;但它其实是新一代从头开始打造的 ASP.N…

html文本显示状态代码中,HTML文本显示状态代码中,表示?

文本如何大小判别偏心受压剪力墙的。能源能量然资提供的自是指源&#xff0c;显示如(&#xff0c;显示能、能、能、能、、热等的械能是机生物原子光能化学总称&#xff0c;不可能源然界的一可再生能于自源可源和再生分为存在次能。状态中表并发儿麻体温生的婴幼易发间低醉期症(…