数两次,按标签付费
目标
在部署了 Prometheus 插件的真实网格中,用 PromQL 查询标准指标,并通过 Telemetry API 增加标签、删除标签、关闭指标、过滤访问日志,然后从 sidecar 的指标和日志中确认其效果。
为什么重要
网格的可观测性看似免费,但每多一个标签、每多一个直方图,时间序列的数量就会成倍增长。反过来,业务所需的维度在标准标签中并没有。决定增加什么、舍弃什么的机制就是 Telemetry API,而它的效果不能看配置,必须看实际累积起来的指标和日志。
步骤
- 用
kubectl apply -f /opt/fixtures/istlab/telemetry-app.yaml部署材料,等待就绪。在 client 中访问http://web/10 次、http://web/broken3 次之后,向 Prometheus(服务istio-system/prometheus,端口 9090)查询sum by (response_code) (istio_requests_total{reporter="destination",destination_workload="web",destination_workload_namespace="shop"}),把响应 JSON 原样保存到/root/istlab-telemetry/01-prom.json。抓取周期是 15 秒,所以要等到两个状态码都能看到之后再保存。 - 在 Prometheus 中,把
destination_workload="web"且response_code="503"的istio_requests_total按reporter分别求和,以source_503=、destination_503=两行写入/root/istlab-telemetry/02-reporters.txt。 - 在
/root/istlab-telemetry/telemetry.yaml中写入并应用命名空间shop的Telemetryshop-telemetry——metrics的 provider 为prometheus,override 针对REQUEST_COUNT、CLIENT_AND_SERVER,通过tagOverrides把tenant设为request.headers['x-tenant']来添加。应用后,带上x-tenant: acme访问三次,并把向 Prometheus 查询sum by (tenant) (istio_requests_total{tenant="acme"})得到的响应保存到/root/istlab-telemetry/03-tenant.json。 - 在
/root/istlab-telemetry/telemetry.yaml中,往同一个 override 的tagOverrides里加入request_protocol: {operation: REMOVE}并重新应用。应用后,带x-tenant: beta发出的请求所产生的新时间序列中不应再有request_protocol标签。 - 在
/root/istlab-telemetry/telemetry.yaml中再加一个 override,把REQUEST_DURATION(CLIENT_AND_SERVER)用disabled: true关闭,并重新应用。应用后,即使发送请求,client sidecar 的istio_request_duration_milliseconds_count的总和也不应再增加(istio_requests_total则应继续增加)。 - 在
/root/istlab-telemetry/telemetry.yaml中加入accessLogging并重新应用——provider 为envoy,filter.expression: "response.code >= 400"。应用后,client 的 200 请求不应出现在 client sidecar 的访问日志中,只应留下/broken(503)请求。 - 在
/root/istlab-telemetry/07-error-ratio.promql中写入一条 PromQL,返回 web 所接收的(reporter 为 destination)请求中 5xx 所占的比率,并把向 Prometheus 查询该语句得到的值以ratio=写入/root/istlab-telemetry/07-ratio.txt。 - 在
/root/istlab-telemetry/08-report.md中写入五行——requests_503_destination=(第 2 步的 destination_503)、counted_twice=(第 2 步中 source 与 destination 计数相同则为 yes)、tenant_label=(第 3 步中附加的 tenant 值)、duration_counting=(现在 duration 指标仍在增长则为 yes)、logged_only_errors=(第 6 步的结果成立则为 yes)——并在其下写出学到的内容,至少四行。
参考
- 这台 VM 的准备需要 3–5 分钟。Prometheus 运行在
istio-system/prometheus(9090)——用kubectl -n istio-system get svc prometheus -o jsonpath='{.spec.clusterIP}'获取地址。 - Prometheus 每 15 秒抓取一次。如果查询结果为空,请稍等一会儿再查。
- sidecar 现在持有的指标,可以用
kubectl -n shop exec client -c istio-proxy -- pilot-agent request GET stats/prometheus直接查看。 - Telemetry 在同一个文件(
telemetry.yaml)中逐步追加,每一步都重新应用。 - 常见错误——等着计数器消失。已经累积的时间序列会保留,配置变更只体现在新产生的时间序列上。
发送请求并向 Prometheus 查询
用 kubectl apply -f /opt/fixtures/istlab/telemetry-app.yaml 部署材料,等待就绪。在 client 中访问 http://web/ 10 次、http://web/broken 3 次之后,向 Prometheus(服务 istio-system/prometheus,端口 9090)查询 sum by (response_code) (istio_requests_total{reporter="destination",destination_workload="web",destination_workload_namespace="shop"}),把响应 JSON 原样保存到 /root/istlab-telemetry/01-prom.json。抓取周期是 15 秒,所以要等到两个状态码都能看到之后再保存。
sidecar 会对每个请求累加 istio_requests_total 之类的标准指标,Prometheus 则根据 Pod 的注解抓取 sidecar 的 15020 端口。所以请求发出后不会立即看到,而是晚大约一个周期才会出现。查询要像 curl -s http://<ClusterIP>:9090/api/v1/query --data-urlencode 'query=…' 那样通过 HTTP API 进行。
一个请求由谁来计数——reporter
在 Prometheus 中,把 destination_workload="web" 且 response_code="503" 的 istio_requests_total 按 reporter 分别求和,以 source_503=、destination_503= 两行写入 /root/istlab-telemetry/02-reporters.txt。
在 sidecar 模式下,一个请求由发送方(source)的 sidecar 和接收方(destination)的 sidecar 分别计数。两个值相同才是正常的,在仪表板上不过滤 reporter 就直接相加,请求数会看起来翻倍。也请记住:接收方在网格之外时只剩 source 一侧,发送方在网格之外时只剩 destination 一侧。
给指标加上我们自己的标签——tagOverrides
在 /root/istlab-telemetry/telemetry.yaml 中写入并应用命名空间 shop 的 Telemetry shop-telemetry——metrics 的 provider 为 prometheus,override 针对 REQUEST_COUNT、CLIENT_AND_SERVER,通过 tagOverrides 把 tenant 设为 request.headers['x-tenant'] 来添加。应用后,带上 x-tenant: acme 访问三次,并把向 Prometheus 查询 sum by (tenant) (istio_requests_total{tenant="acme"}) 得到的响应保存到 /root/istlab-telemetry/03-tenant.json。
Telemetry API 在命名空间(或工作负载)级别修改 sidecar 的指标配置。tagOverrides 的值是请求属性表达式,所以可以把请求头、路径之类的请求信息变成标签。不过,如果把取值无限增长的东西(比如用户 ID)做成标签,时间序列会爆炸,要小心。sidecar 附加的内容可以用 kubectl -n shop exec client -c istio-proxy -- pilot-agent request GET stats/prometheus 直接查看,在 Prometheus 中则要晚大约一个周期才会出现。
删除不用的标签
在 /root/istlab-telemetry/telemetry.yaml 中,往同一个 override 的 tagOverrides 里加入 request_protocol: {operation: REMOVE} 并重新应用。应用后,带 x-tenant: beta 发出的请求所产生的新时间序列中不应再有 request_protocol 标签。
即使一个标签总是同一个值(http),它也会附加到所有时间序列上占用存储空间。把不用的标准标签删掉,是降低基数(cardinality)最便宜的方法。已经生成的时间序列是计数器,不会被删除而是保留,所以请用新产生的时间序列(新的 tenant 值)来确认。
关闭不用的指标
在 /root/istlab-telemetry/telemetry.yaml 中再加一个 override,把 REQUEST_DURATION(CLIENT_AND_SERVER)用 disabled: true 关闭,并重新应用。应用后,即使发送请求,client sidecar 的 istio_request_duration_milliseconds_count 的总和也不应再增加(istio_requests_total 则应继续增加)。
延迟直方图的每个桶都会产生时间序列,是标准指标中最重的。可以通过 Telemetry API 做出这样的选择:只在网关处查看,在 sidecar 上关闭。关闭并不会让旧的值消失,所以要以“不再增长”来确认——请在请求前后各测一次总和并比较。
只把错误留在访问日志中
在 /root/istlab-telemetry/telemetry.yaml 中加入 accessLogging 并重新应用——provider 为 envoy,filter.expression: "response.code >= 400"。应用后,client 的 200 请求不应出现在 client sidecar 的访问日志中,只应留下 /broken(503)请求。
这个网格在安装时通过 meshConfig 打开了所有访问日志。Telemetry 的 accessLogging 可以在命名空间级别覆盖它,只留下符合条件表达式(CEL)的请求。把成功的请求也全部留下的话,日志成本会随请求数成比例增长,所以在生产中往往只留下错误和慢请求。请带上请求 ID 发送,并在 kubectl -n shop logs client -c istio-proxy 中查找。
用一行 PromQL 算出错误率
在 /root/istlab-telemetry/07-error-ratio.promql 中写入一条 PromQL,返回 web 所接收的(reporter 为 destination)请求中 5xx 所占的比率,并把向 Prometheus 查询该语句得到的值以 ratio= 写入 /root/istlab-telemetry/07-ratio.txt。
比率是 sum(5xx 카운터) / sum(전체 카운터)(占位符依次为 5xx 计数器、全部计数器)。如果不把 reporter 固定为一个,就会拿被计数两次的请求互相相除;如果有来自网格之外的请求,分母和分子数的就是不同的东西。生产仪表板会用 rate(…[5m]) 看最近的比率,但本实验的请求只有几次,所以直接用计数器本身相除。查询文件中的换行,用 --data-urlencode "query=$(cat 파일)"(占位符为查询文件)发送就可以原样保留。
写下统计了什么、舍弃了什么
在 /root/istlab-telemetry/08-report.md 中写入五行——requests_503_destination=(第 2 步的 destination_503)、counted_twice=(第 2 步中 source 与 destination 计数相同则为 yes)、tenant_label=(第 3 步中附加的 tenant 值)、duration_counting=(现在 duration 指标仍在增长则为 yes)、logged_only_errors=(第 6 步的结果成立则为 yes)——并在其下写出学到的内容,至少四行。
说明行中请用自己的话写下“增加标签时的成本(基数)”以及“不过滤 reporter 就求和为什么是错的”。