0%

如何调试 envoy

envoy 是目前高性能数据平面的基本标准了,虽然有些看着笨重,但是社区牛逼,其次性能也很高,目前大部分公司的mesh基本都是通过envoy构建的,所以学习是很重要的,本人主要是介绍如何debug envoy,本人也是踩坑了大半天!

背景

envoy 是目前高性能数据平面的基本标准了,虽然有些看着笨重,但是社区牛逼,其次性能也很高,目前大部分公司的mesh基本都是通过envoy构建的,所以学习是很重要的,本人主要是介绍如何debug envoy,本人也是踩坑了大半天!

C++的代码最难的就是主流的IDE工具对代码阅读、调试难度比较大,这几本就挡住了大部分人的学习动力,其中clion对于cmake支持度很好,vscode是比较方便和灵活,可以远程直接debug,一般debug c++的流程就是先要编译成一个二进制产物,通过 gdb/lldb 进行debug。envoy 默认在linux上构建是用clang编译的,debug的话最好用lldb!

环境

  1. 本地开发环境是 Mac
  2. 远程开发环境是 Linux(Debian10, 8C+16G, 公司有32c+64g的啥时候我申请个,真的是不好意思😬)【如果你本地机器性能高可以不用远程,直接本地起个docker就行了】
  3. 编译环境是远程的Docker (vscode remote 也在这里运行)
  4. envoy - v1.26.0 (构建环境是 clang/lldb 14.0.0,clang比gcc构建要快很多….)
  5. 本地 vscode

注意:

  1. envoy这种大型项目它对于环境依赖太重了,所以千万别用本地环境去构建,基本行不通!

  2. c++ debug对于环境一致性要求很高

  3. 我本来想试试 lldbserver/gdbserver 用 clion 进行 remote debug,发现人家产物1.4个G,下载elf太墨迹了,所以还是直接在docker容器内调试算了

调试流程

修改脚本

  1. run_envoy_docker.sh
  • 配置 http代理,不然拉代码太墨迹了,自己找http/https代理
  • 配置docker run 添加参数 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined 支持调试
  • docker 最好限制下 cpu,防止编译把电脑cpu打满了,直接挂了!
  • 修改bazel cache的挂载目录: DEFAULT_ENVOY_DOCKER_BUILD_DIR=${HOME}/.cache/bazel_docker (默认是在/temp 目录下重启电脑就没了)
  1. build_setup.sh 脚本注释掉 (防止把构建产物给删了)
1
2
#cleanup
#trap cleanup EXIT

3.do_ci.sh 注释掉 bazel_binary_build 的一些内容

image-20230819180443981

进入容器

1
./ci/run_envoy_docker.sh '/bin/bash'

构建

执行./ci/do_ci.sh bazel.debug.server_only 即可, 首次构建基本上得两个小时左右,后面增量构建基本上2分钟左右!

1
2
# 这里可以看到 --config=libc++ 实际上就是clang
/usr/local/bin/bazel --output_user_root=/build/tmp/output build --verbose_failures --experimental_generate_json_trace_profile --test_output=errors --repository_cache=/build/repository_cache --experimental_repository_cache_hardlinks --action_env=CLANG_FORMAT --test_tmpdir=/build/tmp --config=libc++ --remote_download_toplevel -c dbg //source/exe:envoy-static

image-20230819181542656

最后自己把 cache 文件压缩一下,备份一份,防止手残给删了。。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
envoybuild@a66c8f90a687:/source$ ls -al bazel-bin/source/exe/
total 1381592
drwxrwxrwx 4 envoybuild envoybuild 4096 Aug 19 15:05 .
drwxrwxrwx 6 envoybuild envoybuild 4096 Aug 19 13:18 ..
-r-xr-xr-x 1 envoybuild envoybuild 56844 Aug 19 13:18 envoy_common_lib.cppmap
-r-xr-xr-x 1 envoybuild envoybuild 2096 Aug 19 13:18 envoy_main_common_lib.cppmap
-r-xr-xr-x 1 envoybuild envoybuild 1954 Aug 19 13:18 envoy_main_entry_lib.cppmap
-r-xr-xr-x 1 envoybuild envoybuild 1413995968 Aug 19 15:05 envoy-static
-r-xr-xr-x 1 envoybuild envoybuild 632368 Aug 19 10:40 envoy-static-2.params
drwxrwxr-x 3 envoybuild envoybuild 4096 Aug 19 15:03 envoy-static.runfiles
-r-xr-xr-x 1 envoybuild envoybuild 141 Aug 19 10:41 envoy-static.runfiles_manifest
-r-xr-xr-x 1 envoybuild envoybuild 3546 Aug 19 13:18 main_common_lib.cppmap
drwxrwxr-x 8 envoybuild envoybuild 4096 Aug 19 15:04 _objs
-r-xr-xr-x 1 envoybuild envoybuild 1501 Aug 19 14:36 platform_header_lib.cppmap
-r-xr-xr-x 1 envoybuild envoybuild 1613 Aug 19 13:18 platform_impl_lib.cppmap
-r-xr-xr-x 1 envoybuild envoybuild 1803 Aug 19 14:36 platform_impl_lib_linux.cppmap
-r-xr-xr-x 1 envoybuild envoybuild 2275 Aug 19 13:18 process_wide_lib.cppmap
-r-xr-xr-x 1 envoybuild envoybuild 1264 Aug 19 13:18 scm_impl_lib.cppmap
-r-xr-xr-x 1 envoybuild envoybuild 1863 Aug 19 13:18 terminate_handler_lib.cppmap

调试

envoy 核心用的libevent,所以大量回掉代码,阅读调试比较困难!

  1. 支持调试本地代码

image-20230819231050653

  1. 支持调试依赖代码

image-20230819231126863

  1. 本地下载 vscode 插件
  • Remote - SSH 可以连接远程虚拟机
  • Dev Containers 连接连接服务器内的docker容器
  1. 远程连接后下载vscode插件 CodeLLDB

  2. 配置 /.vscode/launch.json 文件中配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Launch",
"program": "/source/bazel-bin/source/exe/envoy-static",
"args": [],
"cwd": "/source",
"sourceMap":{
"/proc/self/cwd": "/source",
"/proc/self/cwd/external": "/build/tmp/output/b570b5ccd0454dc9af9f65ab1833764d/execroot/envoy/external",
}
}
]
}
  1. 挂载点是,自行查看自己的挂载点 bazel-source 目录就是bazel的构建目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
envoybuild@82990b41dce5:/source$ ls -al
total 464
drwxr-xr-x 29 envoybuild envoybuild 4096 Aug 19 10:08 .
drwxr-xr-x 1 root root 4096 Aug 19 10:23 ..
drwxr-xr-x 9 envoybuild envoybuild 4096 Aug 19 05:23 api
-rw-r--r-- 1 envoybuild envoybuild 6 Aug 19 05:23 API_VERSION.txt
drwxr-xr-x 3 envoybuild envoybuild 4096 Aug 19 05:23 .azure-pipelines
-rw-r--r-- 1 envoybuild envoybuild 2298 Aug 19 05:23 BACKPORTS.md
drwxr-xr-x 8 envoybuild envoybuild 4096 Aug 19 05:23 bazel
lrwxrwxrwx 1 envoybuild envoybuild 86 Aug 19 06:08 bazel-bin -> /build/tmp/output/b570b5ccd0454dc9af9f65ab1833764d/execroot/envoy/bazel-out/k8-dbg/bin
drwxr-xr-x 2 envoybuild envoybuild 4096 Aug 19 05:23 .bazelci
-rw-r--r-- 1 envoybuild envoybuild 152 Aug 19 05:23 .bazelignore
lrwxrwxrwx 1 envoybuild envoybuild 75 Aug 19 06:08 bazel-out -> /build/tmp/output/b570b5ccd0454dc9af9f65ab1833764d/execroot/envoy/bazel-out
-rw-r--r-- 1 envoybuild envoybuild 19921 Aug 19 05:23 .bazelrc
lrwxrwxrwx 1 envoybuild envoybuild 65 Aug 19 06:08 bazel-source -> /build/tmp/output/b570b5ccd0454dc9af9f65ab1833764d/execroot/envoy
lrwxrwxrwx 1 envoybuild envoybuild 91 Aug 19 06:08 bazel-testlogs -> /build/tmp/output/b570b5ccd0454dc9af9f65ab1833764d/execroot/envoy/bazel-out/k8-dbg/testlogs
-rw-r--r-- 1 envoybuild envoybuild 6 Aug 19 05:23 .bazelversion
-rw-r--r-- 1 envoybuild envoybuild 1454 Aug 19 05:23 BUILD
  1. 调试官方demo https://www.envoyproxy.io/docs/envoy/latest/start/quick-start/run-envoy
  • 下载配置
1
wget https://www.envoyproxy.io/docs/envoy/latest/_downloads/92dcb9714fb6bc288d042029b34c0de4/envoy-demo.yaml
  • 配置启动参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Launch",
"program": "/source/bazel-bin/source/exe/envoy-static",
"args": [
"-c",
"/source/envoy-demo.yaml"
],
"cwd": "/source",
"sourceMap":{
"/proc/self/cwd": "/source", // cwd可以理解为编译的根路径(死的), 需要改成你的项目路径
"/proc/self/cwd/external": "/build/tmp/output/b570b5ccd0454dc9af9f65ab1833764d/execroot/envoy/external", // bazel下载的一些依赖挂载点
}
}
]
}
  • 调试, 浏览器可以打开 http://localhost:10000/ (vscode yyds 支持转发端口)

bazel 基本用法

  1. 这里我用的clang,不太喜欢用gcc, bazel的话直接下载 https://github.com/bazelbuild/bazelisk ,他可以自动下载对应的bazel版本,根据项目里的.bazelversion
1
2
3
4
5
~ which clang++
/usr/lib/llvm-13/bin/clang++

~ which bazel # https://github.com/bazelbuild/bazelisk/releases
/home/fanhaodong.516/go/bin/bazel
  1. 脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.PHONY: fastbuild optbuild debug clean

all: fastbuild

fastbuild: # 快速构建
bazel build --config clang //:main

optbuild: # 优化构建
bazel build --config clang -c opt //:main
bazel build --config clang -c opt //:main.dwp
ls -al bazel-bin/

clean: # 清理bazel此项目的构建缓存
bazel clean

debug: # debug构建, --subcommands 可以查看构建参数,非常有用排查问题。 make debug 2>&1 | tee out.log
rm -rf bazel-bin
bazel build --config clang -c dbg //:main --subcommands
bazel build --config clang -c dbg //:main.dwp --subcommands
ls -al bazel-bin/
  1. .bazelrc 文件配置构建参数
1
2
3
4
5
6
build --cxxopt=-std=c++14 --host_cxxopt=-std=c++14
build:linux --features=per_object_debug_info
build:linux --fission=dbg,opt

build:clang --config=linux
build:clang --action_env=CC=clang --action_env=CXX=clang++
  1. .bazelversion 配置bazel版本
1
6.2.1
  1. CodeLLDB 配置 lldb脚本 .vscode/launch.json 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
{
"version": "0.2.0",
"configurations": [
{
"type": "lldb", // 下同
"request": "custom",
"name": "Custom launch",
"targetCreateCommands": [
"target create /home/fanhaodong.516/go/src/github.com/anthony-dong/bazel_simple/bazel-bin/main",
"setting append target.source-map /proc/self/cwd /home/fanhaodong.516/go/src/github.com/anthony-dong/bazel_simple",
"setting append target.source-map /proc/self/cwd/external /home/fanhaodong.516/.cache/bazel/_bazel_fanhaodong.516/a3fbbe1bc80076bc1aaa5a9834db2f5d/execroot/bazel_simple/external"
],
"processCreateCommands": [
"settings set target.run-args 1 '2 3' '4 5'",
"process launch"
]
},
{
"type": "lldb",
"request": "launch",
"name": "Launch",
"program": "/home/fanhaodong.516/go/src/github.com/anthony-dong/bazel_simple/bazel-bin/main", // 执行文件路径
"args": [ // 配置执行文件启动参数
"ls",
"-al"
],
"cwd": "/home/fanhaodong.516/go/src/github.com/anthony-dong/bazel_simple", // 代码路径
"sourceMap": {
"/proc/self/cwd": "/home/fanhaodong.516/go/src/github.com/anthony-dong/bazel_simple", // 文件map,第一个必须(bazel在linux下构建 PWD=/proc/self/cwd,强制的)
"/proc/self/cwd/external": "/home/fanhaodong.516/.cache/bazel/_bazel_fanhaodong.516/a3fbbe1bc80076bc1aaa5a9834db2f5d/execroot/bazel_simple/external", // 次要配置,看看你需不需要debug依赖,可以配置多个
}
}
]
}

bazel - fission模式

这个比较坑,需要深入了解下,不然debug的话会是噩梦,可以自己写个小项目试试!

  1. bazel 构建模式:https://bazel.build/docs/user-manual#compilation-mode , 默认是fastbuild
  2. bazel 调试模式:https://bazel.build/docs/user-manual#strip
1
2
# 还可以手动再精简 。。。
strip bazel-bin/main -o ./main
  1. fission 模式 https://bazel.build/docs/user-manual#fission
1
2
3
4
5
# --features=per_object_debug_info 可选可不选了现在 (我的版本是 6.x)
# fission 支持 dbg,opt,fastbuild,yes(all),no(none)
# 只有开启了 fission 才能够支持 bazel build //:xxx.dwp
build:linux --features=per_object_debug_info
build:linux --fission=dbg,opt
  1. 构建文件
1
2
3
bazel build --config clang -c dbg  //:main
# 没开启 fission 这个执行了也没啥用... //:xxx.dwp 只在开启fission下生效
bazel build --config clang -c dbg //:main.dwp
  1. 未开启 fission (dbg) 构建
1
2
3
4
5
6
7
8
9
10
drwxr-xr-x 5 fanhaodong.516 fanhaodong.516    4096 Aug 19 22:56 .
drwxr-xr-x 4 fanhaodong.516 fanhaodong.516 4096 Aug 19 22:56 ..
drwxrwxrwx 4 fanhaodong.516 fanhaodong.516 4096 Aug 19 22:56 external
-r-xr-xr-x 1 fanhaodong.516 fanhaodong.516 1274544 Aug 19 22:56 main
-r-xr-xr-x 1 fanhaodong.516 fanhaodong.516 3513 Aug 19 22:56 main-2.params
-r-xr-xr-x 1 fanhaodong.516 fanhaodong.516 674 Aug 19 22:56 main.cppmap
-r-xr-xr-x 1 fanhaodong.516 fanhaodong.516 0 Aug 19 22:56 main.dwp
drwxr-xr-x 3 fanhaodong.516 fanhaodong.516 4096 Aug 19 22:56 main.runfiles
-r-xr-xr-x 1 fanhaodong.516 fanhaodong.516 162 Aug 19 22:56 main.runfiles_manifest
drwxr-xr-x 3 fanhaodong.516 fanhaodong.516 4096 Aug 19 22:56 _objs
  1. 开启 fission (opt) 明显能看出来可执行文件大小降低了不少 1274544 -> 396626
1
2
3
4
5
6
7
8
9
10
11
12
ls -al bazel-bin/
total 1676
drwxr-xr-x 5 fanhaodong.516 fanhaodong.516 4096 Aug 19 23:00 .
drwxr-xr-x 4 fanhaodong.516 fanhaodong.516 4096 Aug 19 23:00 ..
drwxr-xr-x 4 fanhaodong.516 fanhaodong.516 4096 Aug 19 23:00 external
-r-xr-xr-x 1 fanhaodong.516 fanhaodong.516 396626 Aug 19 23:00 main
-r-xr-xr-x 1 fanhaodong.516 fanhaodong.516 3411 Aug 19 23:00 main-2.params
-r-xr-xr-x 1 fanhaodong.516 fanhaodong.516 674 Aug 19 23:00 main.cppmap
-r-xr-xr-x 1 fanhaodong.516 fanhaodong.516 1285592 Aug 19 23:00 main.dwp
drwxr-xr-x 3 fanhaodong.516 fanhaodong.516 4096 Aug 19 23:00 main.runfiles
-r-xr-xr-x 1 fanhaodong.516 fanhaodong.516 162 Aug 19 23:00 main.runfiles_manifest
drwxr-xr-x 3 fanhaodong.516 fanhaodong.516 4096 Aug 19 23:00 _objs
  1. 开启fission (dbg) 1274544 -> 834808
1
2
3
4
5
6
7
8
9
10
11
total 1808
drwxr-xr-x 5 fanhaodong.516 fanhaodong.516 4096 Aug 19 23:00 .
drwxr-xr-x 4 fanhaodong.516 fanhaodong.516 4096 Aug 19 23:00 ..
drwxr-xr-x 4 fanhaodong.516 fanhaodong.516 4096 Aug 19 23:00 external
-r-xr-xr-x 1 fanhaodong.516 fanhaodong.516 834808 Aug 19 23:00 main
-r-xr-xr-x 1 fanhaodong.516 fanhaodong.516 3529 Aug 19 23:00 main-2.params
-r-xr-xr-x 1 fanhaodong.516 fanhaodong.516 674 Aug 19 23:00 main.cppmap
-r-xr-xr-x 1 fanhaodong.516 fanhaodong.516 980664 Aug 19 23:00 main.dwp
drwxr-xr-x 3 fanhaodong.516 fanhaodong.516 4096 Aug 19 23:00 main.runfiles
-r-xr-xr-x 1 fanhaodong.516 fanhaodong.516 162 Aug 19 23:00 main.runfiles_manifest
drwxr-xr-x 3 fanhaodong.516 fanhaodong.516 4096 Aug 19 23:00 _objs
  1. 总结 最好别开,支持度不太好,所以看到 --fission 参数 或者 bazelrc 文件中配置了,请立马注释掉关闭了!!!

bazel - .bazelrc

一旦修改这个文件就得重新构建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 配置c++版本
build --cxxopt=-std=c++14 --host_cxxopt=-std=c++14

# 配置 build 的构建参数(当config为linux时)
# 可以看上面解释
build:linux --features=per_object_debug_info
# build:linux --fission=dbg,opt
build:linux --fission=no

# --config=linux 继承配置linux的,可以配置多个 --config 。
build:clang --config=linux

# config=clang时 cc/gcc 为 clang / clang++
# --action_env 主要clang 构建时传递的env参数
build:clang --action_env=CC=clang --action_env=CXX=clang++
# 可配可不配吧,假如clang路径下有ld.lld既不需要配置
# build:clang --linkopt=-fuse-ld=lld

# config=gcc的构建
build:gcc --action_env=CC=gcc --action_env=CXX=g++

参考

本人坚持原创技术分享,如果你觉得文章对您有用,请随意打赏! 如果有需要咨询的请发送到我的邮箱!