容量管理:找到完美的平衡

你好 我叫Ivan Davydov,我从事Yandex.Money的性能研究。


想象一下,您拥有功能强大的服务器,每个服务器都承载着许多应用程序。 如果后者的数量不多,则它们不会干扰彼此的工作-它们舒适而舒适。 一旦您进入微服务,并在单独的应用程序中去除了“繁重”功能的一部分。


在这里,您可能会无所适从,并且会有太多的微服务,因此很难管理它们并确保其容错能力。 结果,将在每个服务器上“捆绑”十几个为共享资源而战的应用程序。 事实证明这将是一个“大家庭”,但在大家庭中,请勿单击喙!


一旦我们也面对这个。 我的故事讲述的是沉重而沉睡的夜晚,当我晚上坐在灯下朝产品射击时。 一切始于我们开始注意到战斗服务器上的网络问题的事实。



他们极大地影响了性能并大幅缩水。 同时,事实证明,常规用户流也会发生相同的错误,但程度要小得多。


问题在于TCP套接字的利用率超过100%。 当服务器上的所有插槽不断打开和关闭时,会发生这种情况。 因此,应用程序之间存在网络交互问题,并且会出现各种错误-远程主机不可用,HTTP / HTTPS连接(连接/读取超时,SSL对等错误关闭)和其他情况。


即使您没有自己的电子支付服务,也很难评估任何常规销售中的痛苦程度-流量会增加几倍,并且性能下降可能会导致重大损失。 因此,我们得出了两个结论-我们需要评估电流容量的使用方式,并将应用程序彼此隔离。


为了隔离应用程序,我们决定采用容器化。 为此,我们使用了一个管理程序,其中包含许多带有应用程序的单独容器。 这使您可以隔离处理器,内存,输入/输出设备,网络以及进程树,用户,文件系统等的资源。


使用这种方法,每个应用程序都有自己的环境,该环境提供了灵活性,隔离性,可靠性并提高了整体系统性能。 这是一个优美而优雅的解决方案,但是在此之前,您需要回答一些问题:


  • 一个应用程序实例当前具有什么性能裕度?
  • 应用程序如何缩放以及当前配置中是否存在资源冗余?
  • 是否可以提高一个实例的性能,瓶颈是什么?

带着这样的问题,同事来到了我们-一个绩效研究团队。


我们在做什么


我们竭尽全力确保服务的性能,首先,我们针对生产的业务流程进行研究和改进。 从本质上讲,每个业务流程,无论是在商店里用钱包付款还是在用户之间转账,都代表了系统中的一系列请求。


我们进行实验并准备报告,以评估高强度传入请求时的系统性能。 这些报告包含性能指标以及已发现问题和瓶颈的详细描述。 借助这些信息,我们可以改进和优化我们的系统。


由于使用了所有涉及实例的功能的多个微服务参与了业务流程请求序列的组织,因此评估每个应用程序的潜力变得很复杂。


隐喻地说,我们知道军队的力量,但不知道每架战斗机的潜力。 因此,除了进行中的研究之外,有必要评估用作容量管理过程一部分的资源。 此过程称为容量管理。


我们的研究有助于识别和防止资源短缺,预测铁的购买并获得有关系统当前和潜在功能的准确数据。 作为此过程的一部分,将监视实际的应用程序性能(中位数和最大值),并提供有关当前库存的数据。


容量管理的本质是在消耗的资源和生产率之间找到平衡。


优点:


  • 在任何时候都知道每个应用程序的性能如何。
  • 添加新的微服务时的风险较小。
  • 降低购买新设备的成本。
  • 那些已经存在的容量可以更智能地使用。

容量管理如何工作


让我们回到许多应用程序的情况。 我们进行了一项研究,其目的是评估如何在生产服务器上使用容量。


简而言之,行动计划如下:


  1. 在特定应用程序上定义用户强度。
  2. 制作拍摄资料。
  3. 评估每个应用程序实例的性能。
  4. 评估可伸缩性。
  5. 编写有关战斗环境中每个应用程序所需最少实例数量的报告和结论。

现在更详细。


工具


我们使用Heka和Zabbix来收集自定义强度指标。 Grafana用于可视化收集的指标。


需要Zabbix监视服务器资源,例如:CPU,内存,网络连接,DB和其他资源。 Heka提供有关传入/传出请求的执行次数和时间的数据,内部应用程序队列上度量的收集以及无数其他数据。 Grafana是供不同Yandex.Money团队使用的灵活可视化工具。 我们也不例外。



Grafana可以展示例如这样的东西


Apache JMeter用作流量生成器。 在它的帮助下,可以编译一个射击方案,其中包括请求的实现,监视响应的有效性,对提要流的灵活控制等等。 该工具各有利弊,但请深入探讨“为什么要使用这种特殊产品?” 我不会


除了JMeter之外,还使用yandex-tank框架-用于压力测试和分析Web服务和应用程序性能的工具。 它允许您连接模块以获得任何所需的功能,并在控制台或图形形式中显示结果。 我们发射的结果显示在Lunapark(类似于https://overload.yandex.net )中,在这里我们可以实时观察到它们的详细信息,直到第二个峰值,提供必要和足够的离散性,从而更快地响应突发,由射击引起。 在石墨烷中,也可以调整离散度,但是这种解决方案在物理和逻辑资源方面更昂贵。 有时我们甚至上传原始数据,并通过GUI Jmeter对其进行可视化。 但只有-嘘!


说到退化。 使用Kibana可以快速分析在大量流量下应用程序中发生的几乎所有崩溃。 但这也不是万能药,只有通过删除和分析流量才能分析某些网络问题。


使用Grafana,我们分析了应用程序中的用户强度达数月之久。 我们决定将执行请求的总处理器时间作为度量单位,即考虑了请求的数量和执行时间。 因此,我们汇总了最“繁重”的请求列表,这些请求构成了到应用程序的大部分流程。 正是这个清单构成了射击概况的基础。



每个应用程序的用户强度持续几个月


射击和瞄准简介


我们将触发脚本启动称为实验的一部分。 轮廓由两部分组成。


第一部分是编写查询脚本。 在实施过程中,有必要分析每个传入应用程序请求的用户强度,并在它们之间建立一个百分比比率,以识别最常调用和运行时间最久的请求。 第二部分是流量增长参数的选择:具有什么强度和加载多长时间。


为了更清楚起见,以示例方式最好地演示了编译配置文件的方法。


Grafana构建了一个图表,该图表反映了用户强度以及每个请求在总流程中的份额。 根据每个请求的分配和响应时间,在JMeter中创建组,每个组都是一个独立的流量生成器。 该方案仅基于最“繁重”的请求,因为很难实现所有功能(在某些应用程序中有一百多个),并且由于其强度相对较低,因此并不总是必需的。



查询百分比


这项研究以恒定的流量来检查用户强度,并且经常会私下考虑定期发生的“爆发”。


在我们的示例中,考虑了两个组。 第一组包括比率为1到2的“请求1”和“请求2”。类似地,第二组包括请求3和4。对组件的其余请求的强度要小得多,因此我们不在脚本中包括它们。



在Jmeter中对查询进行分组


基于每个组的中位响应时间,可通过以下公式估算性能:


x = 1000 / t,其中t是中位时间,ms


我们得到计算结果,并随着线程数的增加估算近似强度:


TPS = x * p,其中p是线程数,TPS是每秒事务数,x是上一次计算的结果。


如果请求是在500毫秒内处理的,则在一个流中,我们有2 Tps,在100个线程中,理想情况下应该有200 Tps。 根据获得的结果,可以选择初始生长参数。 在第一次迭代研究之后,通常会调整这些参数。


准备好拍摄场景后,我们便开始拍摄-连续拍摄一分钟。 这样做是为了以恒定的流量检查脚本的可操作性,评估每个组中对请求的响应时间并获得请求的百分比。


运行此概要文件时,我们发现以相同的强度保留了请求的百分比,因为第二组的平均响应时间比第一组的平均响应时间长。 因此,我们为两组设置相同的流速。 在其他情况下,有必要分别通过实验为每个组选择参数。


在此示例中,强度是逐步施加的,即在一定间隔内添加了一定数量的流。



强度增长选择


强度增长参数如下:


  • 目标线程数为100(在观察期间确定)。
  • 生长1000秒(〜16分钟)。
  • 100个步骤。

因此,每10秒我们添加一个流。 添加线程之间的间隔和添加线程的数量根据特定步骤中系统的行为而有所不同。 通常,强度会随着平滑增长而增加,因此您可以跟踪每个阶段的系统状态。


射击


通常,触发从晚上从远程服务器开始。 目前,用户流量很小-这意味着拍摄几乎不会影响用户,并且结果错误也会减少。


根据一次点火的结果,我们调整线程数和增长时间,分析整个系统的行为并发现工作中的偏差。 完成所有调整后,开始重复触发一个实例。 在此阶段,我们确定最高性能,并监视服务器,应用程序及其背后所有组件的硬件资源使用情况。


根据拍摄结果,一个应用程序实例的性能约为1000 Tps。 同时,记录了所有请求的响应时间的增加,而没有增加生产率,也就是说,我们达到了饱和,但没有降级。


在下一阶段,我们将比较从其他实例获得的结果。 这很重要,因为硬件可能不同,这意味着不同的实例可以给出非常不同的指示。 我们也是如此-由于生成和特性,某些服务器的生产力提高了一个数量级。 因此,我们确定了一组效果最佳的服务器,并调查了它们的可扩展性。



服务器性能比较


可伸缩性和瓶颈


下一步是研究实例2、3和4的性能。 从理论上讲,性能应随着实例数量的增加而线性增长。 实际上,通常不是这种情况。


在我们的示例中,事实证明这是一个几乎完美的选择。



生产率增长达到饱和的原因是在随后的后端之前连接器池已用尽。 通过控制输出端和输入端池的大小可以解决此问题,并可以提高应用程序性能。


在其他研究中,我们遇到了更有趣的事情。 实验表明,随着性能的提高,CPU和数据库连接的利用率正在迅速增长。 在我们的例子中,发生这种情况是因为在一个实例的配置中,我们遇到了自己的应用程序池设置,而在两个实例的配置中,我们将该数字加倍,从而使输出流加倍。 数据库尚未准备好用于这样的卷。 因此,数据库池开始被阻塞,消耗的CPU百分比达到了99%的临界水平,请求的处理时间增加了,部分流量完全减少了。 我们已经在两个实例上获得了这样的结果!


为了最终说服我们自己的恐惧,我们开了三枪。 结果几乎与前两个相同,除了它们很快陷入混乱。


还有另一个“插件”的例子,在我看来,这是最痛苦的-这是编写不良的代码。 可以有任何您想要的东西,从几分钟之内运行的数据库查询开始,到以错误地分配Java机器的内存的代码结尾。


总结


结果,在我们的示例应用程序中研究的应用程序裕度具有超过5倍的性能裕度。


为了提高生产率,必须在应用程序设置中计算足够数量的处理器池。 一个特定应用程序有两个实例就足够了,而使用全部15个实例是多余的。


经过研究,获得了以下结果:


  • 确定并监视1个月的用户强度。
  • 已确定一个应用程序实例的性能裕度。
  • 获得有关在大流量下发生的错误的结果。
  • 已经确定了进一步提高生产率的瓶颈。
  • 已经确定了用于应用程序正确操作的最少最少实例数。 结果,显示了容量的过度使用。

研究结果构成了将组件转移到容器中的项目的基础,我们将在以下文章中进行讨论。 现在我们可以确定地说多少个容器,必须具有什么特征,如何合理地使用它们的容量,以及应该采取哪些措施以确保适当的性能。


来到我们舒适的电报聊天室 ,您可以随时征求建议,帮助同事并谈论生产力研究。




今天就这些了。 在评论中提出问题,并订阅Yandex.Money博客-很快我们将讨论网络钓鱼以及如何避免网络钓鱼。

Source: https://habr.com/ru/post/zh-CN437416/


All Articles