為何要調優
如果說,引入一個技術需要興趣和衝勁,那麼,讓這個技術上線需要的是堅持和執著。 Cloud Native 如是, Istio 如是。
在上線前的效能測試中,Istio 的使用提供了可觀察性、運維上的便利,同時也引入了痛苦:增加了服務響應延時。如何讓痛苦減到最低,成了當下之急。
表現:之前 9ms 的 SERVICE-A,現在要 14 ms 了。SERVICE-A 依賴於 SERVICE-B。
分析之路
腳下有兩條路:
- 直接調整一些認為可疑的配置,禁用一些功能。再壓測看結果。
- 對 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 120
perf 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 v2v8
configured.v2-stats-nullvm_both
Client and server sidecars are present with telemetry v2nullvm
configured by default.v2-sd-full-nullvm_both
Export Stackdriver metrics, access logs and edges with telemetry v2nullvm
configured.v2-sd-nologging-nullvm_both
Same as above, but does not export access logs.
好地地(現在流行粵語)一個效能測試,整那麼多條線幹什麼?翻譯成接地氣的是:
baseline
不使用 sidecarsnone_both
不使用 Istio 的 Filterv2-stats-wasm_both
使用 wasm 實現的 filterv2-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(再照肺)
由於用 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/