前几天,举行了第66号莫斯科Python聚会-社区继续讨论相关工具,以增强该语言并将其适应不同的环境。 包括在会议上,我都作了报告。 我的名字叫Nail,我在做Yandex.Connect。

我准备的故事是关于uWSGI的。 这是一个多功能的Web应用程序服务器,每个现代应用程序都附带指标。 我试图展示uWSGI的功能如何帮助收集指标。
-大家好,我很高兴欢迎大家来到Yandex。 很高兴有这么多人来查看我的报告和其他报告,并且有如此多的人感兴趣并生活在Python中。 我的报告是关于什么的? 它称为“ uWSGI以帮助度量”。 我会告诉你一些关于我自己的事。 在过去的六年中,我一直在使用Python。在Yandex.Connect团队中,我们正在编写一个业务平台,为外部用户(即每个人)提供内部开发的Yandex服务。 任何个人或组织都可以出于自己的目的,自行使用Yandex开发的产品。
我们将讨论指标,如何获取这些指标,我们如何在团队中使用uWSGI作为获取指标的工具,它如何帮助我们。 然后,我会告诉您一些优化的故事。
关于指标的几句话。 如您所知,没有测试就不可能开发现代应用程序。 如果有人在没有测试的情况下开发其应用程序,这很奇怪。 同时,在我看来,如果没有指标,现代应用程序的操作是不可能的。 我们的应用是活生物体。 一个人可以采取一些指标,例如压力,心率,-该应用程序还具有我们感兴趣并希望观察的指标。 与通常在感到不适时通常采用这些重要指标的人不同,在应用程序中,我们总是可以采用它们。

我们为什么要采用指标? 顺便说一下,谁在使用指标? 我希望在我的报告之后,会有更多的人参与,人们会感兴趣并开始收集指标,他们将理解这是必要且有用的。
那么为什么我们需要指标? 首先,我们了解系统的情况,突出显示系统的一些规范指标,并了解我们在应用过程中是否超出了这些指标。 您可以看到系统的某些异常行为,例如,错误数量增加,在我们的用户之前了解系统中的问题以及从用户那里而不是从监视系统接收有关事件的消息。 根据指标,我们可以根据需要设置警报并接收短信,信件,电话。

通常,指标是什么? 这些是一些数字,也许是一个单调增长的计数器。 例如,请求数。 一些随时间变化的单位值会增加或减少。 一个示例是队列中的任务数。 或直方图-落入一定间隔的值,即所谓的篮子。 通常,读取与时间相关的数据并找出在哪个时间间隔内适合多少个值是很方便的。

我们可以采用哪种指标? 我将专注于Web应用程序的开发,因为它离我很近。 例如,我们可以拍摄请求的数量,端点,端点的响应时间,相关服务的响应代码(如果我们转到它们并且拥有微服务架构)。 如果使用缓存,则可以了解未命中或命中的缓存的有效性,了解两个第三方服务器(例如数据库)的响应时间的分布。 但是为了查看指标,您需要以某种方式收集它们。

我们如何收集它们? 有几种选择。 我想告诉您第一种选择-推送方案。 它由什么组成?
假设我们收到了用户的请求。 在本地,通过我们的应用程序,我们安装了某种形式,通常是推送代理。 假设我们有一个Docker,其中有一个应用程序,而push agent仍然并行。 推送代理从本地接收我们的指标值,以某种方式缓冲它们,进行批量处理并将其发送到指标存储系统。
使用推送方案的好处是什么? 我们可以将一些度量标准直接从应用程序发送到度量标准系统,但是与此同时,我们获得了某种网络交互,延迟和收集度量标准的开销。 如果是本地推送客户端,则将其级别化。

另一种选择是拉动方案。 使用拉取方案,我们有相同的情况。 用户提出要求后,我们便将其保留在家里。 然后以适合您的特定频率-每秒一次,每分钟一次-指标收集系统到达我们应用程序的特殊端点并获取这些指标。

另一个选择是日志。 我们都写日志并将其发送到某个地方。 没有什么可以阻止我们获取这些日志,以某种方式处理它们并基于日志获取度量。
例如,我们将用户请求的事实写在日志中,然后我们对日志进行跳跳计数。 一个典型的例子是ELK(Elasticsearch,Logstash,Kibana)。

它如何与我们合作? Yandex拥有自己的基础架构和指标收集系统。 她期望对实现拉动方案的手柄进行标准化响应。 另外,我们还有一个内部云用于启动应用程序。 所有这些都集成到一个系统中。 上传到云中,我们只需指出:“转到这支笔并获取指标”。

这是我们的指标收集系统期望的对拉取方案的示例响应。
对于团队中的我们自己,我们决定选择一种更适合自己的方式,以突出几个标准,以便我们为自己选择最佳选择。 效率是我们可以在度量系统中以多快的速度显示任何操作的事实。 依赖性-我们是否需要安装其他工具或以某种方式配置基础结构以获取指标。 多功能-这种方法如何适合不同类型的应用程序。

那就是我们最终得到的。 尽管根据效率和多功能性的标准,推送方案将获胜。 但是我们正在开发一个Web应用程序,并且我们的云已经有了现成的基础架构来处理此任务,因此我们决定为自己选择一种拉方案。 我们将谈论她。
为了对拉式方案有所帮助,我们需要将其预先聚集在某个位置,然后保存。 我们的监控系统每五秒钟进入一次拉手。 我们可以在哪里保存? 在您的内存或第三方存储中本地。

如果我们在本地保存,那么通常这适用于具有一个进程的情况。 我们在uWSGI中并行运行多个流程。 或者我们可以使用某种共享存储。 “共享存储”一词让我们想到了什么? 这是某种Redis,Memcached,关系或非关系数据库,甚至是文件。

关于uWSGI。 让我想起那些很少或很少使用它的人:uWSGI是一个应用程序Web服务器,它使您可以在自己下运行Python应用程序。 它实现了uWSGI协议接口。 PEP 333中描述了此协议,有兴趣的读者可以阅读。

它还将帮助我们选择最佳的Yandex.Tank解决方案。 这是一个负载测试工具,可让您使用各种负载配置文件来封装我们的应用程序并构建精美的图形。 或者,它可以根据需要在控制台中工作。

实验。 我们将为合成测试创建一个合成应用程序,并用一个水箱将其封装。 uWSGI应用程序将与10名工作人员发生简单冲突。

这是我们的Flask应用程序。 应用程序执行的有效负载,我们将模拟一个空循环。

我们解雇了,Yandex.Tank给了我们这些图之一。 他在显示什么? 响应时间的百分数。 斜线是不断增长的RPS,直方图是我们的Web服务器在这种负载下所能容纳的百分位数。
我们将以该选项为参考,并查看用于存储指标的不同选项如何影响性能。

最简单的选择是使用PostgreSQL。 因为我们使用PostgreSQL,所以有了它。 让我们使用已经准备好的东西。
假设我们在PostgreSQL中有一个标签,我们在其中简单地增加计数器。

在少量RPS上,我们已经看到性能大幅下降。 可以说是巨大的。

下一个选项是Redis。 但是在这里,我们做得更聪明:我们将其安装在本地,而不是通过网络而是通过Unix套接字进行安装。 还要增加计数器。

我们在输出处获得响应时间的直方图。 我们看到这里的情况会更好,但是在某个时候我们遇到了麻烦,然后生产力不再增长。 此选项似乎更理想,但我们希望做得更好。

在这里,uWSGI是真正的结合体,对我们有帮助。 有许多不同的模块。 用于运行子流程,缓存框架,cron,指标子系统和警报系统的子。 “子系统指标系统”-听起来很有希望。

她知道如何添加某种指标,增加计数器,减少计数器,相乘,除法-随心所欲。
唯一的度量子系统无法完全提供内置的度量。
为什么这对我们很重要? 如您先前所见,我们有一个以特定格式提供统计信息的句柄,并且有多个工作程序正在运行。 我们不知道哪个工作人员会收到请求,但是为了返回所有指标,我们需要创建某种名称的注册表,并以某种方式在流程之间进行打乱。 这很重要,我想避免这种情况。 我们还有什么?

当然是缓存子系统。 在这里,我们看到:他几乎可以做同样的事情,并且还可以给出存储在缓存中的键的名称。 这就是你所需要的。

缓存子系统是uWSGI中内置的缓存。 快速且线程安全的模块,它是普通的键值存储。

但是由于这是一个缓存,所以存在一个众所周知的第二个问题:如何命名变量以及如何使缓存无效? 在我们的例子中,让我们看看默认的缓存设置是什么。 它对密钥的长度有限制。 在我们的例子中,这就是指标的名称。 默认值为2048字节。 并且您可以根据需要增加配置。 默认情况下,它存储的元素数为65,536,似乎此值对于每个人都足够。 任何人都不太可能从他们的应用程序中收集到如此众多的指标。
默认情况下,ttl是0。也就是说,存储的缓存的值不是时间无效的。 因此,我们可以从缓存中获取它们并将其发送到指标系统。

同样,该选项是使用uWSGI框的应用程序。

这是外壳程序应用程序的结果。

如果没有uWSGI,则没有度量的结果看起来几乎是相同的。

如您所见,对于uWSGI,相对于没有指标的“原始”版本,我们仅损失了5%的性能。 其他选择具有相当大的缩编,因此,由于观众投票,uWSGI获胜。

我们如何应用呢? 我们写了一个小图书馆,一个围绕uWSGI的包装。 例如,我们安装了一个库实例,然后在此处添加度量“数据库查询时间”作为示例。

我们也有兴趣跟踪缓存的工作方式。 我们只需重新定义客户端内存的方法,节省接收数据的时间,下载时间以及缓存命中和缓存未命中的次数。

我们如何在图书馆内部做到这一点? 为了发送这些值,我们获取存储在缓存中的键的名称,遍历它们,然后将它们以所需的格式简单地提供给端点。

结果,我们得到一个图,在这种情况下,它是高速缓存访问时间(读取和写入)的百分之九十九。

或者,作为一种选择,是对我们的API的第三方服务请求的数量。

我们有失败和成功的故事。 我们开始添加越来越多的指标,并且性能下降。 指标本身对我们有所帮助。 如果收集指标,则可以看到出了点问题。 因此,我还建议您回顾一下一周,一个月,六个月中累积的指标。 并查看您的应用程序在哪些指标中显示了什么趋势。 我们意识到,我们开始依靠指标的计算。

分析可以帮助我们。 在这里,您可以看到一个火焰图,它直观地向我们展示了在执行过程中对各种函数的调用次数,这些调用在时间上做出了最大的贡献。 我们意识到在使用pickle的第一个版本中我们做得并不好。 在我们图书馆里,她花了很多时间腌制。

我们拒绝酸洗,转移到Cashe Inc,进行所有测量,速度变得更快。

在新的实现中,我们将大部分时间用于缓存而不是酸洗。

我为什么要告诉你呢? 我敦促您开始收集指标,观察指标并关注指标。 在选择一个可能的度量标准收集选项时,请比较这些选项,看看哪个最适合您。 并且,当然,进行概要分析是很好的。 如果您发现有问题,则说明速度有所下降-配置文件。
谢谢大家! 正如我所承诺的,引用: