大数跨境
0
0

Golang绕过了系统DNS缓存问题分析与解决方案

Golang绕过了系统DNS缓存问题分析与解决方案 三七互娱技术团队
2025-06-03
0
导读:前言本文介绍了在 AWS EC2 环境中运行的 Golang服务为何未能利用nscd提供的系统级DNS缓存,导

前言

本文介绍了在 AWS EC2 环境中运行的 Golang服务为何未能利用nscd提供的系统级DNS缓存,导致DNS查询频率异常高而引发的请求超时问题。

还介绍了通过启用连接池的优化措施有效降低DNS 查询请求数,缓解网络指标超限问题,解决了请求超时的问题。

01

背景

在实际业务场景中,A业务的EC2机(AWS)向B业务的EC2推送数据,中间通过一个域名解析到负载均衡器转发。在业务高峰期间,客户端(A业务的golang服务)偶尔出现请求超时的报错。

请求链路: EC2(A业务) → 域名(xxin.xxapi.com)→ 负载均衡器 → EC2(B业务)

02

排查经过

定位范围

从A业务的服务请求到B业务的服务器超时,首先需要定位问题出现在哪个环节,经过探测和请求对比,发现超时的请求并未到达负载均衡器,更无法到达后端服务器,初步判断问题出在A业务EC2服务器自身。

定位异常指标

进一步排查服务器自身的CPU、内存、网络、带宽等,均未发现异常,最后发现了该服务器的 linklocal_allowance_exceeded 指标超限[附录1],该指标反映了服务器可能存在请求元数据DNS解析的超限情况。也就是说 请求元数据 + DNS解析请求 > 1024次/秒 [附录2]。

linklocal_allowance_exceeded 指标说明: 

确认根本原因

由于服务器上部署了nscd服务,会对dns解析进行缓存,一开始不认为是dns解析超限,先去排查了程序请求元数据(请求169.254.169.254)是否超限,通过网络抓包并未发现超限。

再次通过网络抓包分析DNS解析,发现每秒的DNS请求超过了1024,最终确认了问题的确出在DNS解析超限上。

因此,请求DNS解析超限才是本次问题的根本原因。

03

问题分析

定位到了golang有大量的dns解析查询,导致了超限。产生了2个问题: 

问题1: 系统部署了nscd缓存dns解析的服务,为什么缓存没有生效?

问题2: golang默认有连接复用,为什么没有用上?


系统部署了nscd缓存dns解析的服务,为什么缓存没有生效? 

先说结论: golang绕过了系统的dns解析,自己实现了一套,自然就无法用上系统的dns缓存服务。

分析golang的代码,业务是用到的xhttp库实际上是封装了原生的go http库来实现的。

进一步分析原生的go http库,发现在DNS解析时直接读取服务器 /etc/resolve.conf 的配置[附录3],自行实现了DNS解析,并没有使用系统的解析



golang默认有连接复用,为什么没有用上?

结论: 控制连接复用是go http库中的参数DisableKeepAlives(默认为false,表示启用)[附录4],而业务代码中设置了DisableKeepAlives=true,禁用了连接复用

分析业务的代码,用到的xhttp库是基于原生的go http库进行了封装,因曾经其他的项目在使用连接复用时与合作商的通讯出现了异常,就禁止了默认的连接复用行为。

 

因此,在 golang自行实现的DNS解析 和 禁用连接复用 情况下,每次请求都触发一次DNS解析,业务高峰期数据量量大时导致DNS查询QPS超过了1024,被AWS限流,从而引发偶发请求超时。

04

问题解决

解决方案

既然找到了问题所在,解决方法也很简单: 

方法1: 让golang使用系统的DNS解析,就可以用上缓存了,修改方法是增加一个GODEBUG=netdns=cgo环境变量强制Go使用系统DNS解析;但此方法是非标操作,容易埋下隐患,未采纳。


方法2: 启用连接复用,设置 DisableKeepAlives=false,或者删除此参数即可。此方法更为合理一些。

解决效果

在启用连接复用之后,DNS解析的请求减少了90%,未再出现 linklocal_allowance_exceeded指标超限的情况,业务也没有再出现请求超时,问题得到了解决。

05

附录

1.如何监控linklocal_allowance_exceeded 超限: https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/monitoring-network-performance-ena.html#view-network-performance-metrics

2.AWS关于超限的说明: https://docs.aws.amazon.com/zh_cn/vpc/latest/userguide/AmazonDNS-concepts.html

3.golang关于读取/etc/resolve.conf后自行实现解析的代码:  
https://go.dev/src/net/dnsclient_unix.go

4.golang关于DisableKeepAlives参数说明   https://pkg.go.dev/net/http#Transport.DisableKeepAlives


END


三七互娱技术团队

扫码关注 了解更多


【声明】内容源于网络
0
0
三七互娱技术团队
三七互娱技术中心
内容 123
粉丝 0
三七互娱技术团队 三七互娱技术中心
总阅读31
粉丝0
内容123