记一次 Istio 冲刺调优

为何要调优

如果说,引入一个技术需要兴趣和冲劲,那么,让这个技术上线需要的是坚持和执着。 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/tools/tree/release-1.8/perf/benchmark

我参考了:https://github.com/istio/tools/tree/release-1.8/perf/benchmark/flame#setup-perf-tool-envoy

安装 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 120
perf script --header -i perf.data > perf.stacks

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

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

最终生成了 perf.svg

image-20210702223021403.png

上图只是一个 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/ops/deployment/performance-and-scalability/

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

image-20210702224710409.png
  • 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 -b

top - 01:13:52 up 42 days, 14:01,  0 users,  load average: 17.79, 14.09, 10.73
Threads:  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 st
MiB Mem : 94629.32+total, 67159.44+free, 13834.21+used, 13635.66+buff/cache
MiB 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/v1alpha3
kind: EnvoyFilter
metadata:
  ...
  name: stats-filter-1.8
spec:
  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/v1alpha3
kind: EnvoyFilter
metadata:
  name: metadata-exchange-1.8
spec:
  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-deployment

spec:
  template:
    metadata:
      annotations:
        proxy.istio.io/config: 'concurrency: 4'

Sidecar CPU Profile(再照肺)

image-20210702232528945.png

由于用 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/

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容