为何要调优

如果说,引入一个技术须要趣味和冲劲,那么,让这个技术上线须要的是保持和执着。 Cloud Native 如是, Istio 如是。
在上线前的性能测试中,Istio 的应用提供了可察看性、运维上的便当,同时也引入了苦楚:减少了服务响应延时。如何让苦楚减到最低,成了当下之急。

体现:之前 9ms 的 SERVICE-A,当初要 14 ms 了。SERVICE-A 依赖于 SERVICE-B。

剖析之路

脚下有两条路:

  1. 间接调整一些认为可疑的配置,禁用一些性能。再压测看后果。
  2. 对 sidecar 做 cpu profile,定位可疑的中央。进行绝对有依据的调优

我抉择了 2。

Sidecar CPU Profile(照肺)

Istio 作为一个比拟成熟的开源产品,有其官网的 benchmark 我的项目:

https://github.com/istio/tool...

我参考了:https://github.com/istio/tool... 。

装置 perf

在 container 中运行 linux 的 perf 工具来对 sidecar 作 profile。其中有一些难点,如 Istio-proxy container 默认全文件系统只读,我批改了为可写。须要以 root 身份进入 container。如果感觉麻烦,自行基于原 image 制作定制 Image 也可。具体方法不是本文重点,不说了。之后能够用包工具(如 apt)来装置 perf了。

这是一个 istio-proxy container 配置的例子:

spec:  containers:  - name: istio-proxy    image: xyz    securityContext:      allowPrivilegeEscalation: true      capabilities:        add:        - ALL      privileged: true      readOnlyRootFilesystem: false      runAsGroup: 1337      runAsNonRoot: false      runAsUser: 1337

执行 profile 、生成 Flame Graph

以 root 身份进入 istio-proxy container(是的,root能够省点事)

perf record -g  -F 19 -p `pgrep envoy` -o perf.data -- sleep 120perf script --header -i perf.data > perf.stacks

perf.stacks 复制到开发机后,生成 Flame Graph。是的,须要用到一个 perl 脚本:https://github.com/brendangre... (由我的偶像 Brendan Gregg 荣誉出品)

export FlameGraph=/xyz/FlameGraph$FlameGraph/stackcollapse-perf.pl < perf.stacks | $FlameGraph/flamegraph.pl --hash > perf.svg

最终生成了 perf.svg

上图只是一个 envoy worker线程,还有一个线程与之相似。所以下面的 proxy_wasm::ContextBase::onLog 应用了全过程的 14% CPU。从上图看出,这大略是一个 Envoy 扩大 Filter。问题来了,这是什么 Filter,为何有局部 stack 信息会获取不到(上图中的 perf-18.map)。

Envoy Filter - wasm 的乌托邦

我晓得的是,wasm 是一个 vm 引擎(类比 jvm 吧)。Envoy 反对 Native 形式实现扩大,也反对 wasm 形式实现扩大。当然了,vm 擎和 Native 相比肯定有性能损耗了。

还好,某哥搜寻带我找到这文档:

https://istio.io/v1.8/docs/op...

其中一个图,与一段话给予了我提醒:

  • baseline Client pod directly calls the server pod, no sidecars are present.
  • none_both Istio proxy with no Istio specific filters configured.
  • v2-stats-wasm_both Client and server sidecars are present with telemetry v2 v8 configured.
  • v2-stats-nullvm_both Client and server sidecars are present with telemetry v2 nullvm configured by default.
  • v2-sd-full-nullvm_both Export Stackdriver metrics, access logs and edges with telemetry v2 nullvm configured.
  • v2-sd-nologging-nullvm_both Same as above, but does not export access logs.

好地地(当初风行粤语)一个性能测试,整那么多条线干什么?翻译成接地气的是:

  • baseline 不应用 sidecars
  • none_both 不应用 Istio 的 Filter
  • v2-stats-wasm_both 应用 wasm 实现的 filter
  • v2-stats-nullvm_both 应用 Native 实现的 Filter

这几句话想说什么?老外有时还是比拟宛转的,接地气地说,就是咱们想推广应用 wasm 技术,所以默认就应用这个了。如果你介意那 1ms 的延时,和那么一点点CPU 。还请用回 Native 技术吧。好吧,我抵赖,我介意。

注:起初我发现,官网规范版本的 Istio 1.8 应用的是 Native 的 Filter。而咱们的环境中是个外部定制版本,默认应用了 wasm Filter(或者也是基于平安、隔离性、可移植性大于性能的乌托邦)。所以,可能对于你来说,Native Filter 曾经是默认配置。

累坏的 Worker Thread 与 隔岸观火的 core

上面是 enovy 过程的线程级 top 监控。是的,pthread说了,线程命名,不是 Java 世界的专利。COMMAND 一列是线程名字。

top -p `pgrep envoy` -H -btop - 01:13:52 up 42 days, 14:01,  0 users,  load average: 17.79, 14.09, 10.73Threads:  28 total,   2 running,  26 sleeping,   0 stopped,   0 zombie%Cpu(s): 42.0 us,  7.3 sy,  0.0 ni, 46.9 id,  0.0 wa,  0.0 hi,  3.7 si,  0.1 stMiB Mem : 94629.32+total, 67159.44+free, 13834.21+used, 13635.66+buff/cacheMiB Swap:    0.000 total,    0.000 free,    0.000 used. 80094.03+avail Mem    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND    42 istio-p+  20   0  0.274t 221108  43012 R 60.47 0.228 174:48.28 wrk:worker_1    41 istio-p+  20   0  0.274t 221108  43012 R 55.81 0.228 149:33.37 wrk:worker_0    18 istio-p+  20   0  0.274t 221108  43012 S 0.332 0.228   2:22.48 envoy

同时发现, client 的并发压力进步,并不能明显提高这个 2 worker thread 的 envoy 的间线程 CPU 应用到 100%。民间始终流传的 超线程 CPU core 不能达到 core * 2 性能的状况来了。怎么办?加 worker 试试啦。

一个字:调

Istio 通过 EnvoyFilter 能够定制 Filter,所以我这样玩了:

kubectl apply -f - <<"EOF"apiVersion: networking.istio.io/v1alpha3kind: EnvoyFiltermetadata:  ...  name: stats-filter-1.8spec:  configPatches:  - applyTo: HTTP_FILTER    match:      context: SIDECAR_OUTBOUND      listener:        filterChain:          filter:            name: envoy.http_connection_manager            subFilter:              name: envoy.router      proxy:        proxyVersion: ^1\.8.*    patch:      operation: INSERT_BEFORE      value:        name: istio.stats        typed_config:          '@type': type.googleapis.com/udpa.type.v1.TypedStruct          type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm          value:            config:              configuration:                '@type': type.googleapis.com/google.protobuf.StringValue                value: |                  {                  }              root_id: stats_outbound              vm_config:                allow_precompiled: true                code:                  local:                    inline_string: envoy.wasm.stats                runtime: envoy.wasm.runtime.null                vm_id: stats_outbound...EOF
kubectl apply -f - <<"EOF"apiVersion: networking.istio.io/v1alpha3kind: EnvoyFiltermetadata:  name: metadata-exchange-1.8spec:  configPatches:  - applyTo: HTTP_FILTER    match:      context: SIDECAR_INBOUND      listener:        filterChain:          filter:            name: envoy.http_connection_manager      proxy:        proxyVersion: ^1\.8.*    patch:      operation: INSERT_BEFORE      value:        name: istio.metadata_exchange        typed_config:          '@type': type.googleapis.com/udpa.type.v1.TypedStruct          type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm          value:            config:              configuration:                '@type': type.googleapis.com/google.protobuf.StringValue                value: |                  {}              vm_config:                allow_precompiled: true                code:                  local:                    inline_string: envoy.wasm.metadata_exchange                runtime: envoy.wasm.runtime.null...EOF
注:起初我发现,官网规范版本的 Istio 1.8 应用的是 Native 的 Filter,即 envoy.wasm.runtime.null。而咱们的环境中是个外部定制版本,默认应用了 wasm Filter(或者也是基于平安、隔离性、可移植性大于性能的乌托邦)。所以,下面的的优化,可能对于你来说,是默认配置曾经实现了。即,你能够疏忽……

上面是批改 envoy 的线程数:

kubectl edit deployments.apps my-service-deploymentspec:  template:    metadata:      annotations:        proxy.istio.io/config: 'concurrency: 4'

Sidecar CPU Profile(再照肺)

因为用 native envoy filter 代替了 wasm filter。上图可见,stack 失落状况没了。实测 CPU 使用率降落约 8%,提早缩小了 1ms。

总结

与其谴责坑爹的定制版本的默认 wasm envoy filter 配置、线程配置,不如想想本人为何付出数天的代价,才定位到这个问题。当咱们很兴奋地坐上某新技术船上时,除了记得带上救生圈,还不能遗记:你是船长,除了会驾驶,你更应该理解船的工作原理和培修技术,才能够应答突发,不负所托。

原文:https://blog.mygraphql.com/zh/posts/cloud/istio/istio-tunning/istio-filter-tunning-thread/