Beyla 指标基数
Beyla 指标的基数高度依赖于被插桩环境的大小和复杂性,因此无法提供一个简单准确的公式。
本文档试图提供 Beyla 默认安装可能产生的指标基数近似值。文档按 Beyla 可生成的每种指标类型分为几个部分,因为每种指标族都可以选择性地启用或禁用。
为简单起见,下面的公式假设只有一个集群。您应该将基数乘以您的集群数量。
术语
在继续之前,我们应澄清一些可能模糊或容易引起误解的术语
- Instance:是每个插桩目标。在应用程序级别指标中,它是服务或客户端实例。在 Kubernetes 中,它是 Pod。在进程级别指标中,每个实例是每个报告的进程。一个应用程序实例可能运行在多个进程中。在网络级别指标中,每个实例是 Beyla 实例,它负责插桩给定主机中的所有网络流。
- Instance Owner:在 Kubernetes 中,大多数实例 (Pod) 都有一个所有者资源。有时您可能更喜欢报告有关所有者而非实例的数据,以控制基数。实例所有者的示例包括 Deployments、DaemonSets、ReplicaSets 和 StatefulSets,但如果 Pod 没有所有者(独立 Pod),则 Pod 本身被报告为所有者。
- URL Path:是 URL 请求的原始路径,由客户端发送并由服务器接收,例如:
/clients/348579843/command/833
。 - URL Route:是 URL 请求的聚合路径,进行语义分组以控制基数。它通常模仿某些 Web 框架允许您在代码中定义 HTTP 请求的方式,例如:
/clients/{clientId}/command/{command_num}
。 - Operation:描述了请求的功能
- HTTP:所有 HTTP 动词,例如
GET
,后跟 URL 路由 - gRPC:服务的路径
- SQL:SQL 命令,例如
SELECT
、UPDATE
或其他命令,后跟目标表 - Kafka:Produce/Fetch
- HTTP:所有 HTTP 动词,例如
- Server:是接收和处理 HTTP 或 gRPC 请求的任何实例。服务器也可以是客户端。
- Client:是提交 HTTP、gRPC、数据库或 MQ 请求的任何实例。客户端也可以是服务器。
- Service:在 Kubernetes 上下文中,是由一组服务器提供的功能,通过公共主机名和端口进行访问。
- Endpoint:是标识服务、服务器或客户端的 IP 或主机名和端口。
- Return code:由每次服务调用返回,描述了一些关于执行的元信息。对于 HTTP,它们是 HTTP 状态码,对于其他协议,通常是 0(成功)或 1(错误)。
进程级别指标
进程级别指标是最容易计算的指标,因为进程之间没有连接,并且进程实例属于唯一的应用程序实例。
基数,根据 Beyla 中默认启用的属性集
#Instances * #Metrics * #AttributeValues
- Instances 是被插桩进程的数量
- Metrics 是每个进程报告的指标数量,而 AttributeValues 是需要乘以每个指标实例的一些实例级属性
process.cpu.utilization
cpu.mode={用户, 系统, 等待}
Process.cpu.time
cpu.mode={用户, 系统, 等待}
Process.memory.usage
Process.memory.virtual
process.disk.io
disk.io.direction={读取, 写入}
process.network.io
network.io.direction={接收, 发送}
总而言之,计算进程基数的公式为
#ProcessInstances * 12
其中 12
是上面列举的所有 #Metrics * #AttributeValues
的总数。
应用程序级别指标
对于应用程序级别指标,我们不能像进程级别指标那样遵循简单的乘法公式,因为有多个因素影响基数,并且它们之间不是线性关系。
例如,HTTP 路由的数量和服务器地址都会增加基数,但我们不能简单地将它们相乘,因为并非所有服务器实例都接受相同的 HTTP 路由。
下面的公式可以提供一个非常粗略的最大上限,但在我们的测量中,实际基数比计算结果低了两个数量级。因此,我们建议采用以测量为主的方法,而不是事先尝试计算基数。
但是,以下是可能影响总体基数的一些因素列表
- Instances:被插桩实体的数量。它们可以是服务,也可以是客户端。
- MetricNames:应用程序级别指标名称的数量。这取决于 Beyla 插桩的应用程序类型。为将要报告的每个指标计数。
- 客户端指标,当 Beyla 插桩执行对其他应用程序请求的应用程序时
http.client.request.duration
http.client.request.body.size
rpc.client.duration
sql.client.duration
redis.client.duration
messaging.publish.duration
messaging.process.duration
- 服务器端指标,当 Beyla 插桩分发来自其他应用程序请求的应用程序时
http.server.request.duration
http.server.request.body.size
rpc.server.duration
- HistogramBuckets 需要被计算并乘以每个指标,因为每个应用程序级别指标都是一个直方图。桶的数量可以在 Beyla 中配置,但默认数量是持续时间指标 15 个,请求体大小指标 11 个,再加上另外 2 个指标(直方图总和和计数)。
- Operations 等同于被调用的功能。在 HTTP 服务中,它将分组 HTTP 方法和 HTTP 路由,在 RPC 中是 RPC 方法名。
- Endpoints 是服务器地址和端口的计数。
- ReturnCodes 是操作可能结果的数量。通常在 GRPC 中是 Ok/Err,或 HTTP 状态码。
示例计算
显示的基数公式中的操作数可能会重叠。例如,一个被插桩的客户端应用程序可能会发送 /foo
和 /bar
HTTP 请求,并连接到服务 A 和服务 B,所以
- Operations: 2
- Endpoints: 2
Operations * Endpoints
的商会将基数乘以 4。然而,如果 /foo
路由是服务 A 独有的,而 /bar
路由是服务 B 独有的,则实际基数乘数将仅为 2。
在计算基数时,为您的计算设置乐观和悲观界限。
以下示例说明如何计算示例系统的基数。客户端和后端都由 Beyla 插桩。其他组件是外部的
悲观计算结果为
#Instances * #MetricNames * #HistoBuckets * #Operations * #Endpoints * #ReturnCodes =
= 2 * 5 * 177/3 * 37/3 =2771
作为参考的数字
- 2 个实例,客户端和后端
- 5 种指标类型,根据它们的角色和协议
- 客户端
rpc.client.duration
- 作为 RPC 服务器的后端
rpc.server.duration
- 作为 SQL 和 HTTP 客户端的后端
http.client.request.duration
http.client.request.body.size
sql.client.duration
- 客户端
- 17 个直方图指标,因为大多数指标都是基于持续时间的
- 7 个操作:RPC Add/List/Delete,HTTP PUT,SQL Insert/Select/Delete
- 3 个端点:后端,身份提供者和数据库
- 7 个返回码:RPC OK/Err,HTTP 200/401/500,SQL OK/Err
看起来基数不应超过 163。但是,这个数字既不现实也不准确,因为并非所有乘数都适用于整个系统。例如,SQL 方法不应与 RPC 和 HTTP 指标相乘。
在这个简单的场景中,我们可以手动计算最大基数,结果是 396,这远低于初始计算的 2771
# | 实例 | 指标 | 端点 | 操作 | 代码 |
---|---|---|---|---|---|
1 | 客户端 | rpc.client.duration | 后端 | Add | Ok |
2 | 客户端 | rpc.client.duration | 后端 | Add | Err |
3 | 客户端 | rpc.client.duration | 后端 | List | Ok |
4 | 客户端 | rpc.client.duration | 后端 | List | Err |
5 | 客户端 | rpc.client.duration | 后端 | Delete | Ok |
6 | 客户端 | rpc.client.duration | 后端 | Delete | Err |
7 | 后端 | rpc.server.duration | Add | Ok | |
8 | 后端 | rpc.server.duration | Add | Err | |
9 | 后端 | rpc.server.duration | List | Ok | |
10 | 后端 | rpc.server.duration | List | Err | |
11 | 后端 | rpc.server.duration | Delete | Ok | |
12 | 后端 | rpc.server.duration | Delete | Err | |
13 | 后端 | http.client.request.duration | 身份提供者 | PUT /login | 200 |
14 | 后端 | http.client.request.duration | 身份提供者 | PUT /login | 401 |
15 | 后端 | http.client.request.duration | 身份提供者 | PUT /login | 500 |
16 | 后端 | http.client.request.body.size | 身份提供者 | PUT /login | 200 |
17 | 后端 | http.client.request.body.size | 身份提供者 | PUT /login | 401 |
18 | 后端 | http.client.request.body.size | 身份提供者 | PUT /login | 500 |
19 | 后端 | sql.client.duration | 数据库 | Insert | Ok |
20 | 后端 | sql.client.duration | 数据库 | Insert | Err |
21 | 后端 | sql.client.duration | 数据库 | Select | Ok |
22 | 后端 | sql.client.duration | 数据库 | Select | Err |
23 | 后端 | sql.client.duration | 数据库 | Delete | Ok |
24 | 后端 | sql.client.duration | 数据库 | Delete | Err |
为简洁起见,我们尚未计算直方图桶。接下来我们将指标实例乘以直方图桶,再加上直方图 _count
和 _sum
- 3 个请求体大小指标实例 x 13 = 39
- 21 个持续时间指标实例 x 17 = 357
总计基数:396
以上示例说明了提供一个公式来计算基数影响的难度。我们成功计算了一个非常简单的示例的精确基数,其中所有信息都是已知的。在大型 Kubernetes 集群中,我们对应用程序以及它们如何相互连接的信息很少或根本没有,这种计算将是不可能的。
网络级别指标
网络级别指标比应用程序级别指标更容易计算,因为 Beyla 只提供一个计数器:beyla.network.flow.bytes
。但是,基数也取决于您的应用程序相互连接的程度。
beyla.network.flow.bytes
的默认属性是
- 方向(请求/响应)
- Kubernetes 中的源和目标端点所有者:
k8s_src_owner_name
、k8s_dst_owner_name
、k8s_src_owner_type
、k8s_dst_owner_type
、k8s_src_namespace
、k8s_dst_namespace
k8s_cluster_name
:每个集群唯一。我们假设只有一个集群,与其他指标一样。
简化的悲观计算公式为
#Directions * #SourceOwners * #DestinationOwners
我们假设所有源所有者都连接到所有目标所有者。更实际的做法是应用一个连接因子,例如一个有 100 个 Deployments/DaemonSets/StatefulSets 的集群,其中每个所有者平均连接到另外 2 个所有者,其基数将为
2 个方向 x 100 个源所有者 x 2 个目标所有者 = 400
服务图指标
服务图指标针对可以使用应用程序指标(例如 HTTP、RPC、SQL、Redis 和 Kafka)插桩的实例生成。网络指标针对任何具有网络流量的实例生成,无论其使用何种协议。
服务图指标生成以下指标
traces_service_graph_request_client
:具有 15 个桶的直方图traces_service_graph_request_server
:具有 15 个桶的直方图traces_service_graph_request_failed_total
:计数器traces_service_graph_request_total
:计数器
每个指标还具有以下属性
source
:Beylaclient
和client_namespace
server
和server_namespace
计算类似于网络指标,但基数更高
- 我们报告的是一组指标/直方图,总基数为 36,包括两个 15+2 直方图 + 2 个计数器,而不是单个计数器指标。
- 服务图指标通常忽略内部 Kubernetes 流量或任何来自未在应用程序级别插桩的实例的流量,而不是按实例的所有者(例如 Deployment)进行聚合。
测量结果为
traces_spanmetrics_latency
:带有 15 + 2 个桶的直方图traces_spanmetrics_calls_total
:计数器traces_spanmetrics_size_total
:计数器traces_spanmetrics_response_size_total
:计数器
可能增加每个指标基数的属性有:
- 服务/服务命名空间/实例 ID
- Span 类型:客户端/服务端/内部
- Span 名称:通常是操作的名称,可能具有高基数
- 返回码
最大基数可以粗略计算为:
19 metric buckets * 3 span kinds * #Instances * #Operations * #ReturnCodes
正如前面关于应用程序指标计算的示例所示,我们假设大量的 HTTP 返回码只会影响到 HTTP 服务,或者某些实例组只包含总路由的子集。
案例研究:OpenTelemetry Demo 的基数
在本节中,我们将计算部署在由 3 个节点组成的本地集群中的 OpenTelemetry Demo 的基数。我们禁用了示例应用程序中所有捆绑的 OpenTelemetry 仪表,并部署了 Beyla 来执行仪表。
衡量进程级别指标
除非您对应用程序的内部结构有深入了解,否则很难确定正在运行的进程数。我们通过实验测量得出 OpenTelemetry demo 大约运行 140 个进程。
按照公式:
#实例 #指标 #属性值
已知所有进程指标和属性值的总和为 12,我们理论上预期进程级别指标的基数为:
141 * 12 = 1680
这与我们通过 PromQL 测量的基数值非常接近:count({__name__=~"process_.*"})
:~1,600
衡量应用程序级别指标
由于大多数被监控的实例既是客户端又是服务,为了更准确,我们在公式中忽略 #实例 这个参数。
#MetricNames * (#HistoBuckets+2) * #Operations * #Endpoints * #ReturnCodes
为了最小化属性对最终基数非线性影响,我们分开计算所有指标类型(HTTP、gRPC 和 Kafka)的基数。
HTTP 指标
- 4 个指标:客户端、服务端、请求大小和时间
- 平均 15 个直方图桶
- 已知操作:75 个,通过运行中的 OTEL Demo 使用 PromQL 查询测量:
group by (http_request_method, http_route)({__name__=~"http_.*"})
- 26 个端点,通过运行中的 OTEL Demo 使用 PromQL 查询测量:
group by (server_address, server_port)({__name__=~"http_.*"})
- 6 种响应状态码:200、301、308、403、408 和 504,从运行中的 OTEL demo 中提取
HTTP 指标的总最大计算限制是:
4 x 15 x 75 x 26 x 6 =~ 702,000
这表明该公式对于应用程序级别指标是多么无效,因为测得的数值要低得多,即使包含了所有已知的应用程序指标类型:
count({__name__=~"http_.*|rpc_.*|sql_.*|redis_.*|messaging_.*"})
→ 9,600
衡量网络级别指标
对于网络级别指标,如果我们假设 2 个方向(请求/响应)以及 21 个部署向所有 21 个部署请求信息,我们将得到以下基数:
2×21×21 = 882
如果了解架构,并且只计算架构图中的箭头并假设它们是双向的,我们可以得到一个较低的估算值:
2x29 = 58
网络指标衡量 OpenTelemetry Demo 的连接、其他内部集群连接以及仪表流量,因此实际基数更高:
count(beyla_network_flow_bytes_total)
→ 330
我们可以通过以下查询按命名空间对流量进行分组,以便更好地了解哪些部分属于 OpenTelemetry demo:
count(beyla_network_flow_bytes_total) by (k8s_src_namespace, k8s_dst_namespace)
这将返回以下信息:
k8s_源命名空间 | k8s_目标命名空间 | 计数 |
---|---|---|
default | default | 156 |
kube-system | default | 47 |
default | kube-system | 47 |
default | 14 | |
default | 14 | |
kube-system | 13 | |
kube-system | 13 | |
gmp-system | 3 | |
gmp-system | 3 | |
default | gmp-system | 1 |
gmp-system | default | 1 |
OpenTelemetry demo 为 demo 组件之间的流量生成的网络指标数量为 156。default
命名空间既是源也是目标。还有其他到 kube-system
、gmp-system
或根本没有命名空间的流量,这些流量属于外部连接、遥测或 Kubernetes 管理。
衡量服务图指标
网络指标通常用于构建服务图,但实际的服务图指标会有不同的形态。
- 除了单个计数器指标,我们还有 2 个计数器指标和另外 2 个带有 16+2 个桶的直方图指标。
- 服务图指标通常忽略内部 Kubernetes 流量或任何来自未在应用程序级别插桩的实例的流量。
测量结果为
count({__name__=~".*service_graph.*"})
→ 2300
测量 Span 指标
在应用程序级别指标计算中,我们演示了由于涉及的参数数量众多,尝试获得分析数字是很困难的。我们可以通过 PromQL 测量来获得基数的正确测量值
count({__name__=~".*spanmetrics.*"})
→ 3900