Ubuntu系统上本地域名解析慢,十有八九是systemd-resolved这个DNS解析服务在捣鬼。直接说结论:关掉它,换成传统的resolvconf或者直接配置静态DNS,解析速度立刻从几秒降到毫秒级。具体操作就是停止systemd-resolved服务,删除/etc/resolv.conf里的软链接,然后手动写一个真正的resolv.conf文件,指向你信任的DNS服务器,比如114.114.114.114或者公司内网DNS。这套操作下来,本地域名解析问题基本就解决了。

很多Ubuntu运维人员在部署服务器或者开发环境时都会遇到一个头疼的问题:明明网络通的,ping外网IP没问题,但一解析域名就卡好几秒,甚至超时。你以为是网络问题,其实是systemd-resolved这个服务在本地做了一层DNS缓存和转发,而它默认的上游DNS配置往往不靠谱,或者缓存策略太保守,导致每次解析都要走一遍完整的递归查询流程。今天这篇文章就把这个问题从根上讲透,给你一套完整的排查和解决方案。

一、systemd-resolved到底是什么,为什么它会拖慢解析

systemd-resolved是Ubuntu 18.04之后默认启用的DNS解析服务,它是systemd体系的一部分,用来统一管理系统的DNS配置。它的工作方式是在本地127.0.0.53这个地址上起一个DNS缓存代理,然后把/etc/resolv.conf做成一个指向这个本地地址的软链接。所有应用程序的DNS请求都会先打到这个本地代理上,再由它去向上游DNS服务器查询。

问题出在哪呢?第一,它默认的上游DNS服务器可能是你路由器分配的,而路由器的DNS转发能力很弱;第二,它的缓存策略有时候不够激进,TTL设置不合理,导致本来可以直接命中缓存的请求还要重新查;第三,在某些网络环境下,127.0.0.53这个本地地址的响应本身就有延迟,特别是当系统同时跑着NetworkManager和systemd-resolved两套网络管理时,配置冲突会让解析变得更慢。

你可以用下面这条命令快速确认你的系统是不是在用systemd-resolved:

ls -la /etc/resolv.conf

如果输出显示是指向127.0.0.53的软链接,那就是它在干活。正常情况下,/etc/resolv.conf应该是一个普通文件,里面直接写着nameserver那一行。

二、快速诊断:确认解析慢的根因

在动手改之前,先做几步诊断,确认问题确实出在systemd-resolved上,而不是其他地方。打开终端,依次执行以下命令:

# 查看当前DNS解析配置
resolvectl status

# 测试直接用指定DNS解析的速度
time nslookup example.com 114.114.114.114

# 测试走systemd-resolved的速度
time nslookup example.com

# 查看systemd-resolved的日志有没有报错
journalctl -u systemd-resolved --no-pager -n 50

如果直接指定DNS服务器解析很快,但走默认解析很慢,那基本可以锁定是systemd-resolved的问题。resolvectl status的输出会告诉你当前用的是哪个网卡、哪个DNS服务器、DNSSEC状态等信息,这些都是排查的关键线索。

另外还有一个容易忽略的点:检查/etc/systemd/resolved.conf这个配置文件,看看里面有没有DNS=和DNSStubListener=这两个配置项。如果DNS=后面跟的是一个很慢的上游DNS,或者DNSStubListener=no但实际上还在监听,都会导致问题。

三、解决方案一:优化systemd-resolved配置(不关服务)

如果你不想完全关掉systemd-resolved,只是想让它跑得快一点,可以通过修改配置来优化。编辑/etc/systemd/resolved.conf文件:

[Resolve]
DNS=114.114.114.114 223.5.5.5
FallbackDNS=8.8.8.8
DNSStubListener=yes
DNSSEC=no
Cache=yes
CacheFromLocalhost=no

这里的关键改动有几个:第一,把DNS换成国内速度快的公共DNS,114.114.114.114和阿里的223.5.5.5都是不错的选择;第二,关掉DNSSEC验证,这个功能在国内环境下基本用不上,关掉能省不少时间;第三,CacheFromLocalhost=no这个设置很重要,它告诉systemd-resolved不要把本地回环地址的请求也走一遍缓存逻辑,避免额外开销。

改完之后重启服务:

sudo systemctl restart systemd-resolved

然后再测试解析速度,一般会有明显改善。但说实话,这种优化只是治标,systemd-resolved本身的架构决定了它在高负载场景下还是不如直接用传统DNS解析来得干脆。

四、解决方案二:彻底禁用systemd-resolved(推荐)

这是最彻底的方案,也是大多数运维人员最终会选择的做法。步骤如下:

第一步,停止并禁用systemd-resolved服务:

sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved

第二步,删除/etc/resolv.conf的软链接,创建一个真正的配置文件:

sudo rm /etc/resolv.conf
sudo nano /etc/resolv.conf

在文件里写入你的DNS服务器:

nameserver 114.114.114.114
nameserver 223.5.5.5
nameserver 8.8.8.8

第三步,防止NetworkManager或者其他服务把/etc/resolv.conf重新改回去。如果你的系统用的是NetworkManager,需要编辑/etc/NetworkManager/conf.d/dns.conf:

[main]
dns=none

或者直接在NetworkManager的连接配置里把IPv4的DNS设成手动,不要选自动。如果你用的是netplan管理网络,就在/etc/netplan/下面的yaml文件里直接配nameservers字段,然后执行sudo netplan apply。

第四步,重启网络服务或者直接重启系统验证:

sudo systemctl restart NetworkManager
# 或者直接重启
sudo reboot

重启之后再用nslookup或者dig测试,解析速度应该是立竿见影的提升。

五、解决方案三:用resolvconf管理DNS(折中方案)

如果你的Ubuntu系统上同时有多个网络接口,或者经常切换网络环境,直接写死/etc/resolv.conf可能不太方便。这时候可以装一个resolvconf包,让它来统一管理DNS配置:

sudo apt install resolvconf
sudo dpkg-reconfigure resolvconf

安装过程中会问你是否让resolvconf管理/etc/resolv.conf,选yes。然后编辑/etc/resolvconf/resolv.conf.d/head文件,在里面加你的DNS服务器:

nameserver 114.114.114.114
nameserver 223.5.5.5

这样做的好处是,不管你怎么切换网络,DNS配置都不会被覆盖,而且resolvconf会自动处理多网卡的情况。不过要注意,装了resolvconf之后要确保systemd-resolved是禁用状态,不然两套系统会打架。

六、进阶优化:本地hosts文件和DNS缓存

除了改DNS解析服务本身,还有两个辅助手段可以进一步提升本地域名解析速度。第一个是合理使用/etc/hosts文件,把你经常访问的本地域名或者内网域名直接写进去:

sudo nano /etc/hosts
127.0.0.1 localhost
192.168.1.100 myserver.local
192.168.1.101 dbserver.local

这样这些域名根本不需要走DNS查询,直接就能解析。第二个是如果你确实需要一个本地DNS缓存来加速重复查询,可以考虑装dnsmasq,它比systemd-resolved轻量得多,配置也简单:

sudo apt install dnsmasq
sudo nano /etc/dnsmasq.conf
server=114.114.114.114
server=223.5.5.5
cache-size=1000

然后把/etc/resolv.conf的nameserver改成127.0.0.1,让所有请求先过dnsmasq。这个方案在有大量重复DNS查询的场景下效果非常好。

七、常见踩坑和注意事项

在实际操作中,有几个坑是很多人会踩的。第一个是禁用systemd-resolved之后发现DNS不工作了,这通常是因为NetworkManager又把/etc/resolv.conf改回去了,解决办法就是前面说的设置dns=none或者在netplan里固定配置。第二个是在云服务器上,比如阿里云、腾讯云的Ubuntu镜像,它们可能有自己的DNS管理机制,直接改/etc/resolv.conf可能会被覆盖,需要在云控制台或者cloud-init里配置。第三个是如果你的系统跑着Docker,Docker会自己管理DNS配置,可能会和你的系统级配置冲突,需要在Docker的daemon.json里单独配dns字段。

还有一个容易忽略的点:修改完DNS配置后,建议清空一下systemd-resolved的缓存(如果你没完全禁用它的话),或者直接重启一下系统,确保所有服务都拿到新的配置。用resolvectl flush-caches可以手动清缓存。

八、总结:到底该选哪种方案

如果你是个人开发机或者小型服务器,直接禁用systemd-resolved、手写resolv.conf是最简单最有效的。如果你在企业环境里需要统一管理DNS,用resolvconf或者netplan来集中配置更合适。如果你对解析速度有极致要求,dnsmasq加本地缓存是最优解。不管哪种方案,核心思路都是一样的:绕开systemd-resolved这个中间层,让DNS解析走最短的路径。

Ubuntu的DNS解析问题说大不大,说小不小,但它确实会影响日常运维效率和服务响应速度。搞清楚systemd-resolved的工作原理,掌握这几套解决方案,以后再遇到类似问题就能快速定位、快速解决,不用再对着慢吞吞的域名解析干着急了。