💂 关于封面:
相信很多人听过《London Bridge Is Falling Down》这个儿歌,有人也知道这个是英国传统的儿童游戏歌曲。但很多人和我一样,以为 “London Bridge” 就是封面中的塔桥。直到今天,我才知道,“London Bridge” 并不是 “Tower Bridge”。所以,封面不是 “London Bridge”。无论喜欢与否,一个时代的符号走到了终点,愿安宁。
📚 摘录说明:
本文摘自一本我在写作中的开源书《Istio & Envoy 内幕》 中 Istio 与 Envoy 指标 一节。如果说你看到的转载图片不清,可回到原书。
Istio 与 Envoy 指标概述
指标监控,可能是 DevOps 监控最重要的一环。但同时也可能是最难的一环。你可以从网上找到各种系统和中间件的 Grafana 监控仪表盘,它们大都设计得很漂亮得体,让人感觉监控已经完美无缺。
但是,不知道你是否与我有同样的经历:在系统遇到问题时,手头有一大堆指标和监控仪表盘。
- 却不知道哪个指标才是问题相关的。
- 或者是,问题已经有个方向定位,却发现这个方向上,根本没有记录指标。
事情终究是要人来解决,再多的数据,如果:
- 不去理解这些数据背后的意义
- 不去主动分析自己的应用场景和部署环境需要什么数据,只是系统默认给什么就用什么
那么指标越多,越让人迷失在茫茫指标的海洋中。
作为一个混后端江湖多年的老程(老程序员),总有很多东西不懂,却难以启齿的。其中一个就是一些具体指标的意义。举个两个例子:
- 我之前定位一个 Linux 下的网络问题,用了一个叫
nstat
的工具,它输出了非常多的指标,但很多会发现,有些指标是死活找不到说明文档的。这也是开源软件一直以来的问题,变化快,文档跟不上,甚至错误或过时未更新。 - 我之前定位一个 Linux 下的 TCP 连接问题,用了一个叫
ss
的工具,它输出的神指标,也是搜索引擎也无能为力去解释。最后不得不看原码。还好,我把调查结果记录到 Blog 中:《可能是最完整的 TCP 连接健康指标工具 ss 的说明》,希望对后来人有一些参考作用吧。
故事说完了,回到本书的主角 Istio 与 Envoy 上。它们的指标说明文档比上面的老爷车开源软件好一些。起码基本每个指标都有一行文字说明,虽然文字一样非常短且模糊。
Istio 的 istio-proxy 的数据面指标是 基于 Envoy 的指标构架实现的。所以,后面我将先说 Envoy 的指标架构。
如果你和我一样,是个急性子。那么下图就是 Istio & Envoy 的指标地图了。它说明了指标产生在什么地方。后面内容会一步步推导出这个地图。
Envoy 指标
Envoy 指标概述
Envoy 的主要目标之一是使网络易于理解。 Envoy 会根据其配置方式产生大量统计信息。一般来说,统计数据(指标)分为三类:
- Downstream:Downstream 指标与外来的连接/请求有关。它们由
listener
、HTTP connection manager(HCM)
、TCP proxy filter
等产生。 - Upstream:Upstream 指标与外向的连接/请求有关。它们由
connection pool
、router filter
、tcp proxy filter
等产生。 - Server:
Server
指标信息描述 Envoy 服务器实例的运作情况。服务器正常运行时间或分配的内存量等统计信息。
在最简单场景下,单个 Envoy Proxy 通常涉及 Downstream
和 Upstream
统计数据。这两种指标反映了取该 网络节点
的运行情况。来自整个网格的统计数据提供了每个 网络节点
和整体网络健康状况的非常详细的汇总信息。Envoy 的文档对这些指标有一些简单的说明。
Tag
Envoy 的指标还有两个子概念,支持在指标中使用: 标签(tags)
/维度(dimensions)
。这里的 tags
对等于 Prometheus 指标的 label。意义上,可以理解为:分类维度。
Envoy 的 指标
由规范的字符串来标识。这些字符串的动态部分(子字符串)被提取成为 标签(tag)
。可以通过指定 tag 提取规则(Tag Specifier configuration.) 来定制 tag 。
举个例子:
|
|
指标数据类型
Envoy 发出三种类型的值作为统计信息:
- 计数器(Counters):无符号整数,只会增加而不会减少。例如,总请求。
- 仪表(Gauges):增加和减少的无符号整数。例如,当前活动的请求。
- 直方图(Histograms):作为指标流的一部分的无符号整数,然后由收集器聚合以最终产生汇总的百分位值(percentile,即平常说的 P99/P50/Pxx)。例如,
Upsteam
响应时间。
在 Envoy 的内部实现中,Counters 和 Gauges 被分批并定期刷新以提高性能。Histograms 在接收时写入。
指标释义
从指标的产出地点来划分,可以分为:
- cluster manager : 面向
upstream
的 L3/L4/L7 层指标 - http connection manager(HCM) : 面向
upstream
&downstream
的 L7 层指标 - listeners : 面向
downstream
的 L3/L4 层指标 - server(全局)
- watch dog
下面我只选择了部分关键的性能指标来简单说明。
cluster manager
Envoy 文档:cluster manager stats
上面文档已经说得比较详细了。我只补充一些在性能调优时需要关注的方面。那么,一般需要关注什么指标?
我们从著名的 Utilization Saturation and Errors (USE) 方法学来分析。
利用率(Utilization):
upstream_cx_total
(Counter): 连接数upstream_rq_active
饱和度(Saturation):
upstream_rq_time
(Histogram): 响应时间upstream_cx_connect_ms
(Histogram)upstream_cx_rx_bytes_buffered
upstream_cx_tx_bytes_buffered
upstream_rq_pending_total
upstream_rq_pending_active
(Gauge)
错误(Error):
upstream_cx_connect_fail
(Counter): 连接失败数upstream_cx_connect_timeout
(Counter): 连接超时数upstream_cx_overflow
(Counter): 集群连接断路器溢出的总次数upstream_cx_pool_overflow
upstream_cx_destroy_local_with_active_rq
upstream_cx_destroy_remote_with_active_rq
upstream_rq_timeout
upstream_rq_retry
upstream_rq_rx_reset
upstream_rq_tx_reset
其它:
upstream_rq_total
(Counter): TPS (吞吐)upstream_cx_destroy_local
(Counter): Envoy 主动断开的连接计数upstream_cx_destroy_remote
(Counter): Envoy 被动断开的连接计数upstream_cx_length_ms
(Histogram)
http connection manager(HCM)
Envoy 文档:http connection manager(HCM) stats
可以认为,这是面向 downstream
& 部分 upstream
的 L7 层指标
利用率(Utilization):
downstream_cx_total
downstream_cx_active
downstream_cx_http1_active
downstream_rq_total
downstream_rq_http1_total
downstream_rq_active
饱和度(Saturation):
downstream_cx_rx_bytes_buffered
downstream_cx_tx_bytes_buffered
downstream_flow_control_paused_reading_total
downstream_flow_control_resumed_reading_total
错误(Error):
downstream_cx_destroy_local_active_rq
downstream_cx_destroy_remote_active_rq
downstream_rq_rx_reset
downstream_rq_tx_reset
downstream_rq_too_large
downstream_rq_max_duration_reached
downstream_rq_timeout
downstream_rq_overload_close
rs_too_large
其它:
downstream_cx_destroy_remote
downstream_cx_destroy_local
downstream_cx_length_ms
listeners
可以认为,这是 downstream 的 L3/L4 层的指标。
利用率(Utilization):
downstream_cx_total
downstream_cx_active
饱和度(Saturation):
downstream_pre_cx_active
错误(Error):
downstream_cx_transport_socket_connect_timeout
downstream_cx_overflow
no_filter_chain_match
downstream_listener_filter_error
no_certificate
其它:
downstream_cx_length_ms
server
Envoy 基础信息指标
利用率(Utilization):
concurrency
错误(Error):
days_until_first_cert_expiring
watch dog
Envoy 还包括一个可配置的看门狗系统,它可以在 Envoy 没有响应时增加统计数据并选择性地终止服务器。 系统有两个独立的看门狗配置,一个用于主线程,一个用于工作线程; 因为不同的线程有不同的工作负载。 这些统计数据有助于从高层次上理解 Envoy 的事件循环是否因为它正在做太多工作、阻塞或没有被操作系统调度而没有响应。
饱和度(Saturation):
watchdog_mega_miss
(Counter): mega 未命中数watchdog_miss
(Counter): 未命中数
如果你对 watchdog 机制的兴趣,可以参考:
https://github.com/envoyproxy/envoy/issues/11391
https://github.com/envoyproxy/envoy/issues/11388
Event loop
Envoy 架构旨在通过在少量线程上运行事件循环来优化可扩展性和资源利用率。 “main”
线程负责控制面处理,每个 “worker”
线程分担数据面的一部分任务。 Envoy 公开了两个统计信息来监控所有这些线程事件循环的性能。
跑一轮循环的耗时:事件循环的每次迭代都会执行一些任务。任务数量会随着负载的变化而变化。但是,如果一个或多个线程具有异常长尾循环执行耗时,则可能存在性能问题。例如,负责可能在工作线程之间分配不均,或者插件中可能存在长时间阻塞操作阻碍了任务进度。
轮询延迟:在事件循环的每次迭代中,事件调度程序都会轮询 I/O 事件,并在某些 I/O 事件就绪
或 发生 超时
时 “唤醒” 线程,以先发生者为准。在 超时
的情况下,我们可以测量轮询后预期唤醒时间与实际唤醒时间的差值;这种差异称为 “轮询延迟
”。看到一些小的 轮询延迟
是正常的,通常等于内核调度程序的 “时间片(time slice”)” 或 “量子(quantum)” ——这取决于运行 Envoy 的操作系统 —— 但如果这个数字大大高于其正常观察到的基线,它表示内核调度程序可能发生延迟。
可以通过将 enable_dispatcher_stats 设置为 true
来启用这些统计信息。
main
线程的事件调度器有一个以server.dispatcher.
为根的统计树。- 每个
worker
线程的事件调度器都有一个以listener_manager.worker_<id>.dispatcher.
为根的统计树。
每棵树都有以下统计信息:
Name | Type | Description |
---|---|---|
loop_duration_us | Histogram | 以微秒为单位的事件循环持续时间 |
poll_delay_us | Histogram | 以微秒为单位的轮询延迟 |
请注意,此处不包括任何辅助(非 main 与 worker)线程。
Watch Dog 和 Event loop 都是解决与监控事件处理延迟与时效的工具,这里有很多细节和故事,甚至可以说到 Linux Kernel。希望本书后面有时间,可以和大家一起学习和分析这些有趣的细节。
配置说明
如果你认真看过本书的前言中的 {ref}`index:本书不是什么` ,说好的不是“使用手册”,为何又讲起配置来了?好吧,我只能说,从了解使用方法入手,再学实现,比直接一来就源码的方法更好让人类入门。
本节参考:
[Envoy 文档](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/metrics/v3/stats.proto)
config.bootstrap.v3.Bootstrap
Envoy 文档:config.bootstrap.v3.Bootstrap proto
|
|
什么是 `stats sink`? 本书不作说明。Istio 默认没定制相关配置。以下只说关注的部分配置。
-
stats_config
(config.metrics.v3.StatsConfig) 用于内部处理统计信息的配置。 -
stats_flush_interval
(Duration) 刷新stats sink
的时间间隔。。出于性能原因,Envoy 不会实时刷新 counter ,仅定期刷新 counter 和 gauge 。 如果未指定,则默认值为 5000 毫秒。stats_flush_interval
或stats_flush_on_admin
只能设置之一。 Duration 必须至少为 1 毫秒,最多为 5 分钟。 -
stats_flush_on_admin
(bool) 仅当在管理界面(admin interface)
上查询时才将统计信息刷新到sink
。 如果设置,则不会创建刷新计时器。 只能设置stats_flush_on_admin
或stats_flush_interval
之一。
config.metrics.v3.StatsConfig
Envoy 文档:config-metrics-v3-statsconfig
|
|
-
stats_tags - 维度提取规则(对应 Prometheus 的 label 提取)
(多个 config.metrics.v3.TagSpecifier ) 每个指标名称字符串
都通过这些标签规则独立处理。 当一个标签匹配时,第一个捕获组不会立即从名称中删除,所以后面的 TagSpecifiers 也可以重复匹配同一部分。在完成所有标签匹配后,再剪裁指标名称字符串
的匹配部分,并作为stats sink
的指标名,例如 Prometheus的指标名。 -
use_all_default_tags
(BoolValue) 使用 Envoy 中指定的所有默认标签正则表达式。 这些可以与 stats_tags 中指定的自定义标签结合使用。 它们将在自定义标签之前进行处理。Istio 默认为 false. -
stats_matcher
(config.metrics.v3.StatsMatcher) 指定 Envoy 要产出哪些指标。支持包含
/排除
规则指定。 如果未提供,则所有指标都将产出。 阻止某些指标集的统计可以提高一点 Envoy 运行性能。
config.metrics.v3.StatsMatcher
Envoy 文档:config-metrics-v3-statsmatcher
用于禁用/开启统计指标计算与产出的配置。
|
|
-
reject_all
(bool) 如果reject_all
为 true ,则禁用所有统计信息。 如果reject_all
为 false,则启用所有统计信息。 -
exclusion_list
(type.matcher.v3.ListStringMatcher) 排除列表 -
inclusion_list
(type.matcher.v3.ListStringMatcher) 包含列表
本节参考了: https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/observability/statistics
下一节,将以 Istio 如何使用上面的配置为例,举例说明。
Istio 指标
Istio 自己的 Metrics
标准指标说明
参考:https://istio.io/latest/docs/reference/config/metrics/
Metrics
对于 HTTP、HTTP/2 和 GRPC 流量,Istio 默认生成以下指标:
- Request Count (
istio_requests_total
): This is aCOUNTER
incremented for every request handled by an Istio proxy. - Request Duration (
istio_request_duration_milliseconds
): This is aDISTRIBUTION
which measures the duration of requests. - Request Size (
istio_request_bytes
): This is aDISTRIBUTION
which measures HTTP request body sizes. - Response Size (
istio_response_bytes
): This is aDISTRIBUTION
which measures HTTP response body sizes. - gRPC Request Message Count (
istio_request_messages_total
): This is aCOUNTER
incremented for every gRPC message sent from a client. - gRPC Response Message Count (
istio_response_messages_total
): This is aCOUNTER
incremented for every gRPC message sent from a server.
对于 TCP 流量,Istio 生成以下指标:
- Tcp Bytes Sent (
istio_tcp_sent_bytes_total
): This is aCOUNTER
which measures the size of total bytes sent during response in case of a TCP connection. - Tcp Bytes Received (
istio_tcp_received_bytes_total
): This is aCOUNTER
which measures the size of total bytes received during request in case of a TCP connection. - Tcp Connections Opened (
istio_tcp_connections_opened_total
): This is aCOUNTER
incremented for every opened connection. - Tcp Connections Closed (
istio_tcp_connections_closed_total
): This is aCOUNTER
incremented for every closed connection.
Prometheus 的 Labels
-
Reporter: This identifies the reporter of the request. It is set to
destination
if report is from a server Istio proxy andsource
if report is from a client Istio proxy or a gateway. -
Source Workload: This identifies the name of source workload which controls the source, or “unknown” if the source information is missing.
-
Source Workload Namespace: This identifies the namespace of the source workload, or “unknown” if the source information is missing.
-
Source Principal: This identifies the peer principal of the traffic source. It is set when peer authentication is used.
-
Source App: This identifies the source application based on
app
label of the source workload, or “unknown” if the source information is missing. -
Source Version: This identifies the version of the source workload, or “unknown” if the source information is missing.
-
Destination Workload: This identifies the name of destination workload, or “unknown” if the destination information is missing.
-
Destination Workload Namespace: This identifies the namespace of the destination workload, or “unknown” if the destination information is missing.
-
Destination Principal: This identifies the peer principal of the traffic destination. It is set when peer authentication is used.
-
Destination App: This identifies the destination application based on
app
label of the destination workload, or “unknown” if the destination information is missing. -
Destination Version: This identifies the version of the destination workload, or “unknown” if the destination information is missing.
-
Destination Service: This identifies destination service host responsible for an incoming request. Ex:
details.default.svc.cluster.local
. -
Destination Service Name: This identifies the destination service name. Ex: “details”.
-
Destination Service Namespace: This identifies the namespace of destination service.
-
Request Protocol: This identifies the protocol of the request. It is set to request or connection protocol.
-
Response Code: This identifies the response code of the request. This label is present only on HTTP metrics.
-
Connection Security Policy: This identifies the service authentication policy of the request. It is set to
mutual_tls
when Istio is used to make communication secure and report is from destination. It is set tounknown
when report is from source since security policy cannot be properly populated. -
Response Flags: Additional details about the response or connection from proxy. In case of Envoy, see
%RESPONSE_FLAGS%
in Envoy Access Log for more detail. -
Canonical Service: A workload belongs to exactly one canonical service, whereas it can belong to multiple services. A canonical service has a name and a revision so it results in the following labels.
1 2 3 4
source_canonical_service source_canonical_revision destination_canonical_service destination_canonical_revision
-
Destination Cluster: This identifies the cluster of the destination workload. This is set by:
global.multiCluster.clusterName
at cluster install time. -
Source Cluster: This identifies the cluster of the source workload. This is set by:
global.multiCluster.clusterName
at cluster install time. -
gRPC Response Status: This identifies the response status of the gRPC. This label is present only on gRPC metrics.
使用
istio-proxy 与应用的 Metrics 整合输出
图:istio-proxy 与应用的 Metrics 整合输出。用 Draw.io 打开
参考:https://istio.io/v1.14/docs/ops/integrations/prometheus/#option-1-metrics-merging
Istio 能够完全通过 prometheus.io
annotations 来控制抓取。虽然 prometheus.io
annotations 不是 Prometheus 的核心部分,但它们已成为配置抓取的事实标准。
此选项默认启用,但可以通过在 安装 期间传递 --set meshConfig.enablePrometheusMerge=false
来禁用。启用后,将向所有数据平面 pod 添加适当的 prometheus.io
annotations 以设置抓取。如果这些注释已经存在,它们将被覆盖。使用此选项,Envoy sidecar 会将 Istio 的指标与应用程序指标合并。合并后的指标将从 /stats/prometheus:15020
中抓取。
此选项以明文形式公开所有指标。
定制:为 Metrics 增加维度
如,增加端口、与 HTTP HOST 头 维度。
|
|
- 使用以下命令将以下 annotation 应用到所有注入的 pod,其中包含要提取到 Prometheus 时间序列 的维度列表:
仅当您的维度不在 [DefaultStatTags 列表] 中时才需要此步骤(https://github.com/istio/istio/blob/release-1.14/pkg/bootstrap/config.go)
|
|
要在网格范围内启用额外 Tag
,您可以将 extraStatTags
添加到网格配置中:
|
|
参考 : https://istio.io/latest/docs/reference/config/proxy_extensions/stats/#MetricConfig
定制:加入 request / response 元信息维度
可以把 request 或 repsonse 里一些基础信息 加入到 指标的维度。如,URL Path,这在需要为相同服务分隔统计不同 REST API 的指标时,相当有用。
参考 : https://istio.io/latest/docs/tasks/observability/metrics/classify-metrics/
工作原理
istio stat filter 使用
Istio 在自己的定制版本 Envoy 中,加入了 stats-filter 插件,用于计算 Istio 自己想要的指标:
|
|
istio stat Plugin 实现
https://github.com/istio/proxy/blob/release-1.14/extensions/stats/plugin.cc
内置的 Metric:
|
|
https://github.com/istio/proxy/blob/release-1.14/extensions/stats/plugin.cc#L591
|
|
关于 Istio 的指标原理,这是一个很好的参考文章:https://blog.christianposta.com/understanding-istio-telemetry-v2/
Envoy 内置的 Metrics
Istio 默认用 istio-agent 去整合 Envoy 的 metrics。
而 Istio 默认打开的 Envoy 内置 Metrics 很少:
见:https://istio.io/latest/docs/ops/configuration/telemetry/envoy-stats/
cluster_manager
listener_manager
server
cluster.xds-grpc
定制 Envoy 内置的 Metrics
参考:https://istio.io/latest/docs/ops/configuration/telemetry/envoy-stats/
如果要配置 Istio Proxy 以记录 其它 Envoy 原生的指标,您可以将 ProxyConfig.ProxyStatsMatcher
添加到网格配置中。 例如,要全局启用断路器、重试和上游连接的统计信息,您可以指定 stats matcher,如下所示:
代理需要重新启动以获取统计匹配器配置。
|
|
您还可以使用 proxy.istio.io/config
annotation 为个别代码指定配置。 例如,要配置与上面相同的统计信息,您可以将 annotation 添加到 gateway proxy 或 workload,如下所示:
|
|
原理
下面,看看 Istio 默认配置下,如何配置 Envoy。
|
|
输出:
|
|
这时,如果修改 pod 的定义为:
|
|
产生新的 Envoy 配置:
|
|
总结:Istio-Proxy 指标地图
要做好监控,首先要深入了解指标原理。而要了解指标原理,当然要知道指标是产生流程中的什么位置,什么组件。看完上面关于 Envoy 与 Istio 的指标说明后。可以大概得到以下结论:
本节的实验环境说明见于: https://istio-insider.mygraphql.com/zh_CN/latest/appendix-lab-env/appendix-lab-env-base.html