在线服务的目标应该是提供与业务需求匹配的可用服务。此流程的关键部分应该涉及组织中的不同团队,例如,从业务开发团队到工程团队。
要验证一个服务如何符合这些目标,可以用这些目标可衡量的“成就”来定义“阈值”,例如,“服务必须在99.9%的时间内可用”,这应该与用户的期望和业务连续性相匹配。
已经有很多关于这些话题的文章,如果你不熟悉这些术语,我强烈建议你先阅读谷歌关于SLO(服务级别目标)的SRE书籍中的文章。
总而言之:
99%的可用性意味着什么?它不是1%的错误率(失败的http响应的百分比),而是在一个预定义的时间段内可用服务的时间百分比。
在上面的仪表板中,服务在1小时内的错误率超过0.1% (y轴为0.001)(错误峰值顶部的红色小水平段),从而在7天内提供99.4%的可用性:
这一结果中的一个关键因素是你选择度量可用性的时间跨度(在上面的示例中为7天)。较短的周期通常用作工程团队(例如SRE和SWE)的检查点,以跟踪服务的运行情况,而较长的周期通常用于组织/更广泛的团队的评审目的。
例如,如果你设置了99.9%的SLO,那么服务可以停机的总时间如下:
另一个无关紧要的“数字事实”是,给SLO多加一个9都会产生明显的指数级影响。以下是1年的时间跨度的时间组成部分:
在服务可以停机的允许时间内,上面的数字可能被认为是错误预算,你可以从以下事件中消耗这些错误预算:
实际的结果是,上面的任何一种情况都将消耗服务的错误预算,例如,意外的停机可能会耗这些预算,从而在此期间阻止进一步的维护工作。
从上面可以清楚地看出,必须有服务指标来告诉我们什么时候认为服务可用/不可用。有几种方法可以做到这一点:
让我们举一个具体的例子,遵循RED方法(因为我们现有的度量标准更适合这种方法):通过Prmoetheus和Grafana等监控工具创建警报和dashboard,以支持Kubernetes API的目标SLO。
此外,我们将使用jsonnet来构建规则和仪表盘文件,充分利用现有的库助手。
本文不是解释如何在服务超出阈值时发出信号,而是重点介绍如何记录服务处于这种情况的时间。
本文的其余部分将着重于创建Prometheus规则,以根据特定度量标准(SLI)的阈值捕获“超出SLO的时间”。
让我们定义一个简单的目标:
以jsonnet的形式编写上述规范(参见[spec-kubeapi.jsonnet]):
slo:: { target: 0.99, error_ratio_threshold: 0.01, latency_percentile: 90, latency_threshold: 200,},
Kubernetes API公开了几个我们可以作为SLIs使用的指标,使用Prometheus rate()
函数在短时间内 (这里我们选择5min,这个数字应该是抓取间隔的几倍):
verb
、code
、resource
对所有请求进行计数,例如,获得最近5分钟的总错误率:sum(rate(apiserver_request_count{code=~\u0026quot;5..\u0026quot;}[5m])) /sum(rate(apiserver_request_count[5m]))
上面的公式放弃了所有的指标标签(例如,通过httpverb
、code
)。如果你想保留一些标签,你需要做如下的事情:
sum by (verb, code) (rate(apiserver_request_count{code=~\u0026quot;5..\u0026quot;}[5m])) / ignoring (verb, code) group_leftsum (rate(apiserver_request_count[5m]))
histogram_quantile ( 0.90, sum by (le, verb, instance)( rate(apiserver_request_latencies_bucket[5m]) )) / 1e3
在这里了解更多的:
PromQL是一种非常强大的语言,尽管截至2018年10月,它还不支持范围的嵌套子查询。我们需要能够计算error ratio
或超出阈值的latency
的time ratio
。
另外,作为一种良好的实践,为了减少查询Prometheus资源使用的时间,建议在诸如sum(rate(…))
之类的预计算表达式中添加记录规则。
举一个例子来说明如何做到这一点,下面的一组记录规则是从我们的[bitnami-labs/kubernetes-grafana-dashboards]存储库中构建的,用于捕获上面的time ratio
:
创建一个新的kubernetes: job_verb- code_instance:apiserver_requests:rate5m
指标来记录请求速率:
record: kubernetes:job_verb_code_instance:apiserver_requests:rate5mexpr: | sum by(job, verb, code, instance) (rate(apiserver_request_count[5m]))
kubernetes: job_verb-code_instance:apiserver_requests:ratio_rate5m
:record: kubernetes:job_verb_code_instance:apiserver_requests:ratio_rate5mexpr: | kubernetes:job_verb_code_instance:apiserver_requests:rate5m / ignoring(verb, code) group_left() sum by(job, instance) ( kubernetes:job_verb_code_instance:apiserver_requests:rate5m )
code
和verb
),创建一个新的指标来捕获错误率:record: kubernetes:job:apiserver_request_errors:ratio_rate5mexpr: | sum by(job) ( kubernetes:job_verb_code_instance:apiserver_requests:ratio_rate5m {code=~\u0026quot;5..\u0026quot;,verb=~\u0026quot;GET|POST|DELETE|PATCH\u0026quot;} )
kubernetes::job:apiserver_latency:pctl90rate5m
,用于记录过去5分钟内的第90个百分位延迟,为简单起见,未在上面显示),最后创建一个布尔指标来记录SLO遵从性情况:record: kubernetes::job:slo_kube_api_okexpr: | kubernetes:job:apiserver_request_errors:ratio_rate5m \u0026lt; bool 0.01 * kubernetes::job:apiserver_latency:pctl90rate5m \u0026lt; bool 200
上述kubernetes::job:slo_kube_api_ok
最终指标对于仪表板和SLO遵从性的解释非常有用,但是我们应该警惕上面哪个指标导致SLO消失,如下面的Prometheus警报规则所示:
alert: KubeAPIErrorRatioHighexpr: | sum by(instance) ( kubernetes:job_verb_code_instance:apiserver_requests:ratio_rate5m {code=~\u0026quot;5..\u0026quot;,verb=~\u0026quot;GET|POST|DELETE|PATCH\u0026quot;} ) \u0026gt; 0.01for: 5m
alert: KubeAPILatencyHighexpr: | max by(instance) ( kubernetes:job_verb_instance:apiserver_latency:pctl90rate5m {verb=~\u0026quot;GET|POST|DELETE|PATCH\u0026quot;} ) \u0026gt; 200for: 5m
请注意,Prometheus来自已经显示的jsonnet输出,阈值可以分别从$.slo.error_ratio_threshold
和$.slo.latency_threshold
中评估得出。
创建Grafana仪表板通常是通过与UI交互来完成的。这对于简单的和/或“标准”仪表板(例如,从https://grafana.com/dashboards )下载)来说是很好的,但是如果你想要实现最好的devops实践,特别是对于gitops工作流,就变得很麻烦了。
社区正在通过各种努力来解决这个问题,例如针对jsonnet、python和Javascript的Grafana库。考虑到我们的jsonnet
实现,我们选择了grafonnet-lib。
使用jsonnet
来设置SLO阈值和编码Prometheus规则的一个非常有用的结果是,我们可以再次使用它们来构建Grafana仪表板,而不必复制和粘贴它们,也就是说,我们为这些保留了一个真实的来源。
例如:
关于$.slo.error_ratio_threshold
,在我们的Grafana仪表板中设置error_ratio_threshold来设置Grafana图形面板的阈值
属性,就像我们在前面为Prometheus警报规则所做的那样。
记录metric.rules.requests_ratiorate_job_verb_code.record
使用情况(而不是’kubernetes: job_verb_code_instance:apiserver_requests:ratio_rate5m'
):
// Graph showing all requests ratiosreq_ratio: $.grafana.common { title: 'API requests ratios', formula: metric.rules.requests_ratiorate_job_verb_code.record, legend: '{{ verb }} - {{ code }}',},
你可以在dash-kubeapi.jsonnet上了解我们的实现情况,下面是生成的仪表板的屏幕截图:
我们在jsonnet
文件夹下的bitnami-labs/ kubernets-grafana -dashboards存储库中实现了上述想法。
我们构建的Prometheus规则和Grafana仪表盘文件来自jsonnet,如下所示:
[spec-kubeapi.[jsonnet]:尽可能多的数据规范(阈值、规则和仪表板公式)
自从我们开始这个项目以来,社区已经创建了许多其他有用的Prometheus规则。点击 srecon17_americas_slides_wilkinson查看有关这方面的更多信息。如果我们必须从头开始,我们可能会使用kubernetes-mixin和jsonnet-bundler。