[坑] 由 DNS 造成的 ETIMEDOUT 错误
发布于 7 年前 作者 netssfy 4096 次浏览 来自 分享

这几天碰到一个小坑,花了点时间调研了下,希望对后人有帮助 描述: 设想你有一个应用,对外暴露 2 个接口 http://www.my.com/api/77 http://www.my.com/api/88 他们内部各自会依赖第三方的 http 接口 接口 88 依赖: http://www.88.com/api,http 请求超时设置为 5S 接口 77 依赖: http://www.77.com/api,http 请求超时设置为 5S 假设你自己的应用所在的机器设置了一个 DNS SERVER,地址为 66.66.66.66,这台 DNS 更像一个代理, 他对 www.88.com 的解析需要依赖上游的 88.88.88.88 这台 DNS 服务 他对 www.77.com 的解析需要依赖上游的 77.77.77.77 这台 DNS 服务

如果这时候 77.77.77.77 这台 DNS 挂了会发生什么?情况如下

  1. 在 66.66.66.66 这台代理 DNS 代理中,对 www.77.comwww.88.com 的记录缓存都还没过期时一切正常
  2. 当 66 对 www.77.com 的记录过期了,那么所有外部对你的 www.my.com/api/77 的访问都将失败,因为你内部无法访问 www.77.com
  3. 坑的地方来了, 当 66 对 www.88.com 的记录过期了,外部访问你的 www.my.com/api/88 会发生什么?答案是都有可能,既可能正常,也可能失败,原因如下:

正常的原因就不赘述了,因为 88.88.88.88 服务器依然坚挺,即使记录过期了 66.66.66.66 还是可以问 88.88.88.88 拿到 www.88.com 的 IP 那为什么会错误呢!因为 nodejs 的 runtime 默认使用了 4 个 worker 线程去处理 dns 解析请求。如果这 4 个线程都在处理对 77 的解析,那么这些线程都会 pending 在那边,直到 DNS 解析失败发生。(感受了一下好像是 10S,应该是 OS 的一个设置值) 那在 pending 期间所有的对 www.88.com 的请求也都会被 pending 起来(因为 88 此时也需要解析,他在 66 中的记录已经过期了)。又因为 http 请求超时设置的是 5S,最终就都会变成 ETIMEDOUT 或者 ESOCKETTIMEDOUT

此外,该问题还可能引发 v8 out of memory 的问题,原本一个请求花费 50MS,那么他占用的内存在 50MS 后就可以被 GC,但是当这个时间变成 5S 后,他占用的内存也要在 5S 后才能被 GC。如果 5S 内量很大,就有可能造成 OOM

5 回复

意思就是你对88.88.88.88的DNS被挂掉了的77.77.77.77给阻塞起来了,然后http超时时间是5秒,而dns解析时间是10s,在第5秒的时候http没接到响应直接就挂掉了,但是这时候dns解析还没解析完呢,直到10s之后dns解析完毕,但是http都已经挂掉了所以肯定请求失败了。不知道我理解的对不对~ 渣渣一枚,不知道理解的是不是这个意思~

@usercx 在HTTP请求5秒钟这段时间内, 后续其他的需要DNS解析的请求都会pending在那边

@netssfy 对啊,就是一共4个负责解析dns的线程,第一秒来了5个请求,前四个是77的,最后一个是88的,第六秒的时候所有的http请求都挂掉了,但是dns还在解析,第11秒77的dns挂掉了,然后轮到88,第12秒(肯定比这个快)88的dns解析出来了,但是http早就挂掉了~

@usercx 第一秒的88就会pending, 从第一秒到第五秒的所有88都会pending

回到顶部