python 监控
当我第一次遇到counter
和gauge
以及带有颜色和数字的图表时,我的React是避免使用该图表,这些图表的颜色和数字分别标记为“平均”和“ 90以上”。 就像我看到了它们一样,但是我不在乎,因为我不了解它们或它们如何有用。 由于我的工作不需要我关注它们,因此它们仍然被忽略。
那是大约两年前。 随着我职业的发展,我想更多地了解我们的网络应用程序,也就是当我开始了解指标时。
我到目前为止了解监视的三个阶段是:
我目前处于第二阶段,将分享我到目前为止所学的知识。 我正在逐步进入第3阶段,在本文结尾的那部分旅程中,我将提供一些资源。
让我们开始吧!
docker
和
docker-compose
才能使用它们。
进行监视的主要原因如下:
为了我们的目的, 度量是在给定的时间点上一定数量的观察值。 博客帖子上的点击总数,参加演讲的总人数,在缓存系统中找不到数据的次数,您网站上已登录用户的数量,所有这些都是指标的示例。
它们大致分为三类:
考虑您的个人博客。 您刚刚发布了一条帖子,并希望随时关注它获得的点击次数,这个数字只会增加。 这是计数器的一个示例。 它的值从0开始,并在博客文章的生存期内增加。 图形上,计数器如下所示:
假设您想跟踪每天或每周的点击数,而不是随着时间推移博客帖子的总点击数。 该指标称为仪表 ,其值可以上升或下降。 在图形上,量规如下所示:
仪表的值通常在特定的时间范围内具有上限和下限 。
直方图 (如Prometheus所称)或计时器 (如StatsD所称)是跟踪采样观测值的度量。 与计数器或仪表不同,直方图指标的值不一定显示向上或向下的模式。 我知道这没有多大意义,而且似乎与衡量标准没有什么不同。 与标准表相比,您期望对直方图数据执行的操作有所不同。 因此,监视系统需要知道指标是直方图类型,才能执行这些操作。
演示1是使用Flask框架编写的基本Web应用程序。 它演示了我们如何计算和报告指标。
src
目录在app.py
具有应用程序,其中src/helpers/middleware.py
包含以下内容:
from flask import request
import csv
import time
def start_timer():
request.start_time = time.time()
def stop_timer(response):
# convert this into milliseconds for statsd
resp_time = (time.time() - request.start_time)*1000
with open('metrics.csv', 'a', newline='') as f:
csvwriter = csv.writer(f)
csvwriter.writerow([str(int(time.time())), str(resp_time)])
return response
def setup_metrics(app):
app.before_request(start_timer)
app.after_request(stop_timer)
从应用程序调用setup_metrics()
,它将配置在处理请求之前调用start_timer()
函数,在处理请求之后但发送响应之前配置stop_timer()
函数。 在上面的函数中,我们编写了timestamp
以及处理请求所花费的时间(以毫秒为单位)。
当我们在demo1
目录中运行demo1
docker-compose up
时,它将启动Web应用程序,然后启动一个向Web应用程序发出大量请求的客户端容器。 您将看到一个由两列创建的src/metrics.csv
文件: timestamp
和request_latency
。
查看此文件,我们可以推断出两件事:
没有与度量标准观测值相关联的特征,我们无法说出该度量标准与哪个HTTP端点相关联,或者无法确定该度量标准是从哪个应用程序节点生成的。 因此,我们需要使用适当的元数据对每个指标观察进行限定。
如果我们回想一下高中数学,即使是含糊其词,也应该记住一些统计学术语,包括均值,中位数,百分位数和直方图。 让我们简要回顾一下它们,而不必像在高中时那样判断它们的用处。
平均值或数字列表的平均值是数字的总和除以列表的基数。 3、2和10的平均值是(3+2+10)/3 = 5
。
中位数是另一种平均值,但计算方法有所不同。 它是从最小到最大(反之亦然)排序的数字列表中的中心数字。 在我们上面的列表(2,3,10)中,中位数是3。 这取决于列表中的项目数。
百分位数是一种度量,它使我们有了一个度量,低于该度量的一定百分比( k
)的数字。 从某种意义上说,它给我们的是如何这一措施相做的一个想法 k
我们的数据的百分比。 例如,以上列表的第95个百分值为9.29999。 百分位数度量范围从0到100(不包括在内)。 零个百分点是一组数字中的最低分数。 你们中有些人可能还记得中位数是第50个百分位数,结果是3。
某些监视系统将百分位数度量值称为upper_X
,其中X是百分位数。 高90表示第90个百分位的值。
q分位数是在一组N个数字中对q N进行排名的度量。 q的值在0到1(包括两者)之间。 当q为0.5时,该值为中位数。 分位数与百分位数之间的关系是, q分位数处的度量等于100 q百分位数处的度量。
我们之前了解的度量直方图是监视系统的实现细节 。 在统计数据中,直方图是将数据分组为存储桶的图形。 让我们考虑一个不同的,人为的示例:阅读您的博客的人们的年龄。 如果您掌握了这些数据,并且希望按组粗略地了解读者的年龄,则绘制直方图将显示如下图:
累积直方图是直方图,其中每个桶的计数包括以前桶的数量,故名累积 。 上述数据集的累积直方图如下所示:
在上面的演示1中,我们观察到在报告指标时会生成大量数据。 使用指标时,我们需要统计信息,因为它们太多了。 我们不在乎个人价值观,而是整体行为。 我们期望值显示的行为是所观察系统的行为的代理。
在上面的演示1应用程序中,当我们计算并报告请求延迟时,它指的是由几个特征唯一标识的特定请求。 其中一些是:
如果将这些特征附加到度量标准观察值,则每个度量标准周围会有更多上下文。 让我们探索在示例2中为我们的指标添加特征。
现在,在编写指标时, src/helpers/middleware.py
文件将多个列写入CSV文件:
node_ids = ['10.0.1.1', '10.1.3.4']
def start_timer():
request.start_time = time.time()
def stop_timer(response):
# convert this into milliseconds for statsd
resp_time = (time.time() - request.start_time)*1000
node_id = node_ids[random.choice(range(len(node_ids)))]
with open('metrics.csv', 'a', newline='') as f:
csvwriter = csv.writer(f)
csvwriter.writerow([
str(int(time.time())), 'webapp1', node_id,
request.endpoint, request.method, str(response.status_code),
str(resp_time)
])
return response
由于这是一个演示,因此在报告指标时,我可以自由地报告随机IP作为节点ID。 当我们在demo2
目录中运行docker-compose up
时,它将导致一个包含多列的CSV文件。
pandas
分析指标 现在,我们将使用pandas分析此CSV文件。 运行docker-compose up
将打印一个URL,我们将使用该URL打开Jupyter会话。 一旦将Analysis.ipynb
笔记本上载到会话中,就可以将CSV文件读取到pandas DataFrame中:
import pandas as pd
metrics = pd.read_csv('/data/metrics.csv', index_col=0)
index_col
指定我们要使用timestamp
作为索引。
由于我们添加的每个特征都是DataFrame中的一列,因此我们可以基于以下列执行分组和聚合:
import numpy as np
metrics.groupby(['node_id', 'http_status']).latency.aggregate(np.percentile, 99.999)
请参考Jupyter笔记本以获取有关数据的更多示例分析。
软件系统具有许多变量,其值在其生命周期中会发生变化。 该软件在某种操作系统上运行,并且操作系统变量也会更改。 我认为,您拥有的数据越多,出现问题时就越好。
我建议监视的关键操作系统指标是:
要监视的其他关键指标将取决于您的软件应用程序。
如果您的软件是侦听并处理客户端请求的网络应用程序,则要衡量的关键指标是:
如果您的网络应用程序在满足客户端请求的上下文中向其他服务发出请求,则它应具有度量标准来记录与这些服务的通信行为。 监视的关键指标包括请求数量,请求延迟和响应状态。
HTTP应用程序应监视以上所有内容。 此外,他们应保留有关非200 HTTP状态计数的细化数据,这些计数由所有其他HTTP状态代码分组。 如果您的Web应用程序具有用户注册和登录功能,则它也应该具有这些指标。
尽管不是网络服务器,但运行很长时间的进程(例如Rabbit MQ使用者或任务队列工作器)仍在拾取任务并对其进行处理的模型上工作。 因此,我们应该监视已处理请求的数量以及这些进程的请求延迟。
无论应用程序类型如何,每个指标都应具有与其相关的适当元数据 。
将监视集成到Python应用程序中涉及两个组件:
记录和报告指标的基本思想是:
def work
(
) :
requests +
=
1
# report counter
start_time
=
time .
time
(
)
# < do the work >
# calculate and report latency
work_latency
=
time .
time
(
) - start_time
...
考虑到上述模式,我们经常利用装饰器 , 上下文管理器和中间件 (用于网络应用程序)来计算和报告指标。 在演示1和演示2中,我们在Flask应用程序中使用了装饰器。
本质上,从Python应用程序报告指标有两种模式。 在拉模型中,监视系统在预定义的HTTP端点“刮”应用程序。 在推送模型中,应用程序将数据发送到监视系统。
Prometheus是在拉模型中工作的监视系统的一个示例。 StatsD是监视系统的示例,其中应用程序将度量标准推送到系统。
要将StatsD集成到Python应用程序中,我们将使用StatsD Python客户端 ,然后更新指标报告代码,以使用适当的库调用将数据推送到StatsD中。
首先,我们需要创建一个client
实例:
statsd = statsd.StatsClient(host='statsd', port=8125, prefix='webapp1')
prefix
关键字参数会将指定的prefix
添加到通过此客户端报告的所有指标。
有了客户后,我们可以使用以下方法报告timer
的值:
statsd.timing(key, resp_time)
要增加计数器:
statsd.incr(key)
为了将元数据与度量相关联,将密钥定义为metadata1.metadata2.metric
,其中每个metadataX
都是一个允许聚合和分组的字段。
演示应用程序StatsD是将Python Flask应用程序与statsd
集成的完整示例。
要使用Prometheus监视系统,我们将使用Promethius Python客户端 。 我们将首先创建适当的度量标准类的对象:
REQUEST_LATENCY
= Histogram
(
'request_latency_seconds'
,
'Request latency'
,
[
'app_name'
,
'endpoint'
]
)
上述语句中的第三个参数是与度量标准关联的labels
。 这些labels
定义了与单个指标值关联的元数据。
记录特定的度量观察值:
REQUEST_LATENCY.
labels
(
'webapp'
, request.
path
) .
observe
( resp_time
)
下一步是在我们的应用程序中定义Prometheus可以抓取的HTTP端点。 这通常是一个称为/metrics
的端点:
@app.route('/metrics')
def metrics():
return Response(prometheus_client.generate_latest(), mimetype=CONTENT_TYPE_LATEST)
演示应用程序Prometheus是将Python Flask应用程序与prometheus
集成的完整示例。
下一个自然的问题是:我应该使用StatsD还是Prometheus? 我已经写了一些有关该主题的文章,您可能会发现它们很有用:
我们已经了解了为什么要在应用程序中设置监视,但是现在让我们更深入地研究其中两个:警报和自动缩放。
指标的主要用途是创建警报。 例如,如果过去五分钟内HTTP 500的数量增加,则可能要向相关人员发送电子邮件或寻呼通知。 我们用于设置警报的方式取决于我们的监视设置。 对于Prometheus,我们可以使用Alertmanager ;对于StatsD,我们可以使用Nagios 。
指标不仅可以让我们了解我们当前的基础架构是否配置过多或不足,还可以帮助在云基础架构中实施自动扩展策略。 例如,如果过去五分钟我们服务器上的工作进程使用率通常达到90%,则我们可能需要水平扩展。 我们如何实施扩展取决于云基础架构。 默认情况下,AWS Auto Scaling允许根据系统CPU使用率,网络流量和其他因素来扩展策略。 但是,要使用应用程序指标来按比例放大或缩小,我们必须发布自定义CloudWatch指标 。
当我们超越单一应用程序体系结构(例如,客户端请求可以触发对多个服务的调用,然后再将响应发送回)时,我们需要指标中的更多内容。 我们需要统一的延迟指标视图,以便我们可以看到每个服务花费多少时间来响应请求。 这可以通过分布式跟踪启用。
您可以在我的博客文章通过Zipkin在Python应用程序中介绍分布式跟踪中看到一个Python中的分布式跟踪示例。
总之,请确保记住以下几点:
以上假设您不必管理监视系统。 如果这是您工作的一部分,那么您还有很多事情要考虑!
以下是我发现在监视教育过程中非常有用的一些资源:
当我们学习监控的基础知识时,务必要注意我们不想犯的错误。 这是我遇到的一些有见地的资源:
要了解更多信息,请参加阿米特·萨哈(Amit Saha)的演讲, 计数器,量规,上限90,哦,我的天! ,在PyCon克利夫兰2018年 。
翻译自: https://opensource.com/article/18/4/metrics-monitoring-and-python
python 监控