Yandex的所有新员工几乎都对我们产品所承受的巨大压力感到惊讶。 成千上万的主机每秒处理数十万个请求。 这只是服务之一。 同时,我们必须在一秒钟内响应请求。 即使产品稍有变化也会对性能产生重大影响,因此测试和评估代码对服务的影响非常重要。
在我们的广告技术服务中,测试是在持续集成方法的框架内进行的,我们将在内部从 10月25日的Yandex活动中更详细地讨论关于组织组织的方式,今天,我们将与Habr读者分享自动评估与服务性能相关的重要产品指标的经验。 您将学习如何将分析委托给机器,而不是在图形上关注它们。 走吧

这与如何测试网站无关。 有很多在线工具可以做到这一点。 今天,我们将讨论高负载的内部后端服务,该服务是大型系统的一部分,并为外部服务准备信息。 就我们而言,适用于搜索结果页面和合作伙伴网站。 如果我们的组件没有时间响应,那么来自该组件的信息将不会被提供给用户。 这样,公司就会赔钱。 因此,及时响应非常重要。
哪些重要的服务器指标可以突出显示?
- 每秒请求数(RPS) 。 当然,一个用户的幸福对我们很重要。 但是,如果不是一个,而是成千上万的用户来找您,该怎么办? 您的服务器每秒可以承受多少个请求而不会下降?
- 每个请求的时间 。 网站内容应尽快呈现,以使用户不厌倦等待,也不要去商店购买爆米花。 对于我们而言,他不会在页面上看到信息的重要部分。
- 居民集大小(RSS) 。 确保监视程序消耗了多少内存。 如果服务耗尽了所有内存,则几乎不可能谈论容错。
- HTTP错误 。
因此,让我们按顺序进行处理。
每秒请求
我们从事负载测试很长时间的开发人员喜欢谈论系统的关键资源。 让我们看看它是什么。
每个系统都有自己的配置特征,这些特征决定了操作。 例如,队列长度,响应超时,线程工作池等。 因此,您的服务能力可能取决于这些资源之一。 您可以进行实验。 依次增加每个资源。 资源的增加对您至关重要,资源的增加将增加您的服务容量。 在配置良好的系统中,为了增加容量,您将不必增加一种资源,而应增加多种资源。 但这仍然可以是“感觉”。 如果您可以配置您的系统,使所有资源充分发挥作用,并且服务适合指定的时间范围,那就太好了。
要估计您的服务器每秒可以承受多少个请求,您需要将请求流定向到该服务器。 由于我们已将此流程内置到CI系统中,因此我们使用功能有限的非常简单的“枪支”。 但是来自开源软件Yandex.Tank可以完美地完成此任务。 他有详细的文档 。 给Tank的礼物是查看结果的服务 。
小小的台面。 Yandex.Tank具有相当丰富的功能,不仅限于自动执行脱壳请求。 它还将帮助收集服务指标,构建图形并使用所需的逻辑固定模块。 一般来说,我们强烈建议您认识他。
现在,您需要向坦克提供请求,以便他们可以向我们提供服务。 用来封装服务器的请求可以是相同的类型,可以人为创建和传播。 但是,如果您可以收集一段时间内来自用户的真实请求池,则测量将更加准确。
容量可以通过两种方式进行测量。
开放负载模型(压力测试)
创建“用户”,即几个线程,这些线程将向系统发送请求。 我们不会给您的负载是恒定的,但会不断增加甚至不断增加。 然后它将使我们更接近现实生活。 我们提高了RPS,抓住了带壳服务“突破” SLA的地步。 因此,您可以找到系统的限制。
要计算用户数量,您可以使用Little公式(您可以在此处阅读有关内容)。 省略理论,公式如下所示:
RPS = 1000 / T *工人,其中
•T-请求处理的平均时间(以毫秒为单位);
•worker-线程数;
•每秒1000个/ T请求-该值将由单线程生成器生成。
封闭负载模型(负载测试)
我们采用固定数量的“用户”。 您需要对其进行配置,以便始终阻塞与您的服务配置相对应的输入队列。 同时,使线程数大于队列限制是没有意义的,因为我们将停留在该数目上,而其余请求将被服务器丢弃,并出现5xx错误。 我们查看设计每秒可以发出多少个请求。 在一般情况下,这种方案与请求的真实流程不同,但是它将有助于显示系统在最大负载下的行为并评估其当前吞吐量。
对于绝大多数系统(关键资源与处理连接无关),结果将是相同的。 同时,封闭模型的噪声较小,因为系统一直处于测试所关注的负载区域。
在测试我们的服务时,我们使用封闭模型。 射击后,这把枪告诉我们我们的服务每秒能够发出多少个请求。 Yandex.Tank这个指标也很容易分辨。
每个请求的时间
如果我们回到上一段,很明显,使用这种方案,评估对请求的响应时间是没有意义的。 我们加载系统的能力越强,退化的程度就越大,响应时间也就越长。 因此,要测试响应时间,方法应该有所不同。
为了获得平均响应时间,我们将使用相同的Yandex.Tank。 直到现在,我们才将RPS设置为与生产中系统的平均指标相对应。 脱壳之后,我们将获得每个请求的响应时间。 根据收集的数据,可以计算响应时间的百分位数。
接下来,您需要了解我们认为重要的百分比。 例如,我们以生产为基础。 我们可以保留1%的错误请求,无答案,调试请求,这些请求可以解决很长时间,网络问题等。 因此,我们认为响应时间很长,可以容纳99%的请求。
居民集大小
我们的服务器通过mmap直接处理文件。 通过测量RSS索引,我们想知道程序在运行期间从操作系统中占用了多少内存。
在Linux上,将写入文件/ proc / PID / smaps-这是一个基于映射的扩展,显示了每个进程映射的内存消耗。 如果您的进程使用tmpfs,则匿名和非匿名内存都将进入smap。 非匿名存储器包括例如加载到存储器中的文件。 这是smap中的示例条目。 指定了一个特定文件,其参数Anonymous = 0kB。
7fea65a60000-7fea65a61000 r--s 00000000 09:03 79169191 /place/home/.../some.yabs Size: 4 kB Rss: 4 kB Pss: 4 kB Shared_Clean: 0 kB Shared_Dirty: 0 kB Private_Clean: 4 kB Private_Dirty: 0 kB Referenced: 4 kB Anonymous: 0 kB AnonHugePages: 0 kB Swap: 0 kB KernelPageSize: 4 kB MMUPageSize: 4 kB Locked: 0 kB VmFlags: rd mr me ms
这是匿名内存分配的示例。 当一个进程(相同的mmap)向操作系统请求分配一定大小的内存时,将为其分配一个地址。 而该过程仅占用虚拟内存。 此时,我们尚不知道将分配哪个物理内存。 我们看到了一个无名的记录。 这是分配匿名内存的示例。 系统要求提供24572 kB的大小,但他们没有使用它,实际上仅使用RSS = 4 kB。
7fea67264000-7fea68a63000 rw-p 00000000 00:00 0 Size: 24572 kB Rss: 4 kB Pss: 4 kB Shared_Clean: 0 kB Shared_Dirty: 0 kB Private_Clean: 0 kB Private_Dirty: 4 kB Referenced: 4 kB Anonymous: 4 kB AnonHugePages: 0 kB Swap: 0 kB KernelPageSize: 4 kB MMUPageSize: 4 kB Locked: 0 kB VmFlags: rd wr mr mw me ac
由于在进程停止后分配的非匿名内存将不会到达任何地方,因此该文件不会被删除,因此我们对此类RSS不感兴趣。
在开始在服务器上射击之前,我们从/ proc / PID / smaps总结RSS,分配给匿名内存,并记住它。 我们执行脱壳,类似于每个请求的测试时间。 完成后,再次考虑RSS。 初始状态和最终状态之间的差异将是您的进程在操作期间使用的内存量。
HTTP错误
不要忘记遵循服务在测试期间返回的响应代码。 如果测试或环境设置出现问题,并且服务器针对您的所有请求返回了5xx和4xx错误,则说明这种测试没有什么意义。 我们正在监控不良反应的比例。 如果有很多错误,则认为测试无效。
关于测量精度的一点
现在最重要的是。 让我们回到前面的段落。 事实证明,我们计算出的指标的绝对值对我们而言并不那么重要。 不,当然,考虑到所有因素,误差和波动,您可以实现指标的稳定性。 同时,就该主题写一篇科学著作(顺便说一句,如果有人正在寻找一个,那可能是个不错的选择)。 但这不是我们感兴趣的。
对于我们而言,影响相对于系统先前状态的代码上的特定提交很重要。 也就是说,从提交到提交的度量之间的差异很重要。 在这里,有必要建立一个可以比较此差异的过程,同时确保此间隔内绝对值的稳定性。
环境,请求,数据,服务状态-我们可以使用的所有因素都应固定。 这个系统对我们来说是持续集成的一部分,它为我们提供了有关每次提交中发生的各种更改的信息。 尽管如此,仍无法修复所有问题,会有噪音。 显然,我们可以通过增加样本来减少噪声,即进行多次射击。 此外,在进行15次迭代射击后,我们可以计算所得样本的中位数。 另外,有必要在噪点和拍摄时间之间找到平衡。 例如,我们将误差定为1%。 如果您想根据自己的需求选择更复杂,更准确的统计方法,我们建议您选择一本书 ,其中列出了有关使用时间和使用方式的说明。
噪音还能做什么?
请注意,进行测试的环境在此类测试中起着重要的作用。 测试平台应可靠,不应运行其他程序,因为它们可能导致服务质量下降。 此外,结果可以而且将取决于负载曲线,环境,数据库和各种“电磁风暴”。
作为单个提交测试的一部分,我们在不同的主机上执行多次迭代。 首先,如果您使用云,那么那里什么都可能发生。 即使像我们一样,云是专门的,服务流程仍然在那里工作。 因此,您不能依靠一台主机的结果。 而且,如果您有一个铁主机,没有像在云中那样的用于提高环境的标准机制,那么您甚至可能会意外地将其破坏一次,然后就这样离开。 他将永远骗你。 因此,我们在云中进行测试。
没错,由此引起了另一个问题。 如果每次都是在不同的主机上进行测量,则结果可能会产生一点噪音,并且由于此原因。 然后,您可以将读数归一化到主机。 也就是说,根据历史数据,收集“宿主系数”并在分析结果时将其考虑在内。
历史数据分析表明,硬件有所不同。 这里的“硬件”一词包括内核版本和正常运行时间的后果(显然,内存中没有可移动的内核对象)。
因此,对于每个“主机”(重新启动后,主机“死亡”,并且出现“新”),我们将一个校正与关联,在聚合之前将RPS乘以一个校正。
我们以一种非常笨拙的方式来考虑和更新这些修订,可疑地使人联想到一些强化训练的选择。
对于给定的posthost校正向量,我们考虑目标函数:
- 在每个测试中,我们都会考虑获得的“校正后” RPS结果的标准偏差
- 取权重相等的平均值 ,
- 我们有tau = 1周。
然后,我们将一个校正(对于这些权重之和最大的主机)固定为1.0,并寻找所有其他校正的值,这些校正给出最小的目标函数。
为了验证历史数据的结果,我们考虑对旧数据的更正,考虑对新鲜数据的更正,并与未校正的结果进行比较。
调整结果和降低噪声的另一种选择是将其标准化为“合成”。 在启动要测试的服务之前,请在主机上运行“综合程序”,从中可以评估主机的状态并计算校正因子。 但是在我们的案例中,我们使用基于主机的更正,但是这个想法仍然是一个想法。 也许你们中的一个会喜欢她。
尽管具有自动化及其所有优点,但不要忘记指示器的动态。 重要的是要确保服务不会随时间降级。 您可能不会注意到小的亏损,它们会累积,并且在很长一段时间内,指标可能会下垂。 这是我们在RPS上查看的图表示例。 它显示了每个检查的提交的相对值,其编号以及查看从何处分配发布的功能。


如果您阅读了这篇文章,那么看到有关Yandex.Tank 的报告以及负载测试结果的分析绝对会很有趣。
我们还提醒您,关于持续集成的组织的更多详细信息,我们将在内部从 10月25日开始在Yandex活动中谈论。 来参观!