1

真的不是我的锅

起步

这是一个客户问题,经过一番排查发现是 node 版本的问题。记录一下这个奇葩的过程。

排查过程

1. 尝试本地复现

在客户机器上出现的问题由于调试不太方便,优先尝试复刻客户运行环境复现问题。

  • node 版本:10.18.1
  • 运行环境: k8s, docker, 镜像系统 alpine 3.11.3
  • 应用依赖: 向客户要了 package.json

结果,本地命令没卡住。未能复现。

2. 远程客户机器进行排查

客户帮咱们创建一个新的负载,我们通过向日葵进行调试。发现 node 的启动命令会发生 coredump 而非卡住,目录有生成 coredump 文件,使用 gdb 查看可以看到:

00813-spsphv9jya.png

可得的信息较少,使用 strace 进行跟踪:

72648-1xp0hsnep1bi.png

客户内核版本 4.4 ,membarrier 内核调用因参数不支持而失败,之后会发送信号到子线程去,然后发生段错误。

我本地也编译了一份 4.4 内核,使用 strace 进行跟踪:

15010-3f0037rysh2.png

也有发kill,但却没有发生段错误,加载正常的。本地复现再次失败。

3. 进一步排查

从 gdb 入手,我们进入 layout asm 进行调试:

图片.png

图片.png

发现是在加载动态库就发生段错误了,其中有个线程在 tss_set,跟线程的栈内存有点关系。

后来发现用公用镜像也会崩:

63244-7jbuv8s2z5y.png

进一步排查,发现在客户机器上即使不注入探针,仅使用公共镜像也能够复现出这个问题。

85769-1fuj8v3e84i.png

左边图是客户机器上。在客户机器上即使不注入探针,仅使用公共镜像也能够复现出这个问题,导致 coredump。但也不是所有机器上都能出现这个问题(右边图是我本地的没这个问题)。

那么问题就极有可能和我们探针没有关系。

4. 定位问题

排查方向就转向 node 的版本。在新版本正常使用,然后通过二分,最后确定了 node 10.22+ 版本是首次修复。

注意到 node 10.22+ 版本的更新说明哩,有个修复了线程堆栈大小的问题:

32528-k14ctdvryd.png

52690-dsk0ccwypzp.png

线程堆栈太小以至于不能安全地接收信号。

查看对应的 commit 变更,可以看到通过手动修改了 pthread_attr_setstacksize() 解决了问题:

34925-45em4rmdfae.png

5. 确定问题

那么如何确定这个问题就是造成探针无法载入的罪魁祸首呢?

我们参考 https://github.com/nodejs/docker-node/issues/813#issuecomment-407339011 提供的临时解决方案,然后通过设置 ld_preload 多个值方式运行:

图片.png

探针载入正常。
得出问题所在,该 node 版本下创建子线程时给的堆栈太小导致无法启动。

解决

建议客户使用 node 10.22+ 版本,这是 node 版本问题导致的。

参考链接:


陆安
3.2k 声望239 粉丝

宝可梦情怀粉;刀塔手残党;浴室麦霸王。