Loading... # Linux systemd-resolved DNS 缓存失效问题排查 # 一、事件概述 ## 1. 事件背景 在 Linux 系统上使用 dnscache 工具检查 DNS 缓存状态时,发现缓存统计数据异常,缓存条目始终为 0,命中率极低。 ## 2. 影响范围 ### A. 影响功能 DNS 查询无法利用本地缓存,每次查询都需要访问网络,增加延迟和网络负载。 ### B. 影响程度 - 缓存命中率仅 4.85% - 所有 DNS 查询均走网络请求 ## 3. 问题表现 - Total Entries 始终为 0 - Cache Hits 不增加 - Cache Misses 持续增长 - resolvectl query 显示 Data from: network # 二、事件时间线 ## 1. 问题发现 ### A. 现象描述 执行 `dnscache -stats` 命令,观察到以下异常输出: ``` DNS Cache Statistics ==================== Total Entries: 0 Cache Hits: 3551 Cache Misses: 69660 Hit Rate: 4.85% ``` ### B. 初步判断 缓存条目为 0 但有历史命中记录,说明缓存曾经工作过但当前无法保留条目。 ## 2. 深入排查 ### A. 验证缓存刷新 执行 `dnscache -flush` 后再次查看统计,Misses 继续增加但 Entries 仍为 0。 ### B. 系统级验证 使用 `resolvectl statistics` 确认系统级 DNS 缓存状态: ``` Cache Current Cache Size: 0 Cache Hits: 3551 Cache Misses: 69685 ``` ## 3. 配置检查 ### A. resolved 配置文件 检查 `/etc/systemd/resolved.conf`: ``` #Cache=no-negative #CacheFromLocalhost=no ``` 配置项被注释,使用默认值(Cache=yes),排除配置禁用缓存的可能。 ## 4. 根因定位 ### A. 查询来源验证 执行 `resolvectl query google.com`,输出显示: ``` -- Data from: network ``` 确认 DNS 查询结果来自网络而非缓存,即使刚刚查询过同一域名。 ```mermaid sequenceDiagram participant U as 用户 participant D as dnscache 工具 participant R as systemd-resolved participant N as 网络 DNS U->>D: dnscache -stats D->>R: 获取统计信息 R-->>D: Entries=0, Hits=3551 D-->>U: 显示统计结果 U->>R: resolvectl query google.com R->>N: DNS 查询请求 N-->>R: 返回 IP(TTL=0?) R-->>U: Data from: network Note over R: 缓存条目因 TTL 过期<br/>立即被清除 ```  # 三、问题分析 ## 1. 直接原因 DNS 查询结果没有被缓存,或缓存后立即过期被清除。 ## 2. 根本原因(5 Whys 分析) ### A. 为什么缓存条目始终为 0? DNS 记录的 TTL(Time To Live)值非常短或为 0,导致缓存立即过期。 ### B. 为什么 TTL 会是 0? 上游 DNS 服务器(企业内网 DNS 或特定配置的公共 DNS)返回的记录 TTL 被设置为极短值。 ### C. 为什么上游 DNS 要设置短 TTL? - 企业 DNS 策略:便于快速切换 IP、负载均衡 - CDN 服务:动态调整流量分配 - 安全考虑:防止 DNS 缓存投毒攻击 ## 3. 深层反思 - Cache Hits 是累计值,表示历史上有过缓存命中 - Current Cache Size 是实时值,表示当前缓存中的条目数 - 两者不一致说明缓存机制正常,但条目因 TTL 过期被清除 # 四、解决方案 ## 1. 诊断方法 ### A. 检查 DNS 记录 TTL 使用 dig 命令查看具体域名的 TTL 值: ```bash dig google.com +noall +answer ``` 若 TTL 显示为 0 或极小值(1-5 秒),确认是上游 DNS 配置问题。 ### B. 连续查询对比 ```bash # 第一次查询 dig example.com +noall +answer # 等待几秒后再次查询 dig example.com +noall +answer ``` 观察 TTL 值变化,正常情况下第二次查询的 TTL 应该比第一次小。 ## 2. 可能的解决方案 ### A. 更换 DNS 服务器 若当前使用企业 DNS,可尝试切换到公共 DNS(如 8.8.8.8、1.1.1.1)测试: ```bash # 临时测试 resolvectl dns eth0 8.8.8.8 ``` ### B. 配置本地 DNS 缓存 部署 dnsmasq 或 unbound 作为本地缓存层,可配置最小 TTL 值: ``` # dnsmasq 配置示例 min-cache-ttl=300 ``` ### C. 联系网络管理员 若为企业环境,与网络管理员沟通 DNS TTL 策略。 ## 3. 预防措施 - 定期监控 DNS 缓存命中率 - 建立 DNS 性能基线指标 - 记录网络环境变更 # 五、经验总结 ## 1. 关键发现 - systemd-resolved 的 Cache Hits 是累计值,不代表当前缓存状态 - Current Cache Size 为 0 不一定是缓存功能故障,可能是 TTL 问题 - `resolvectl query` 的 Data from 字段可快速判断数据来源 ## 2. 排查思路 1. 先确认缓存功能是否启用(检查配置文件) 2. 再确认缓存是否工作(对比 Hits 和 Size) 3. 最后定位根因(检查 TTL 值) ## 3. 工具使用 - `dnscache -stats`:快速查看缓存统计 - `resolvectl statistics`:系统级详细统计 - `resolvectl query`:验证查询来源 - `dig +noall +answer`:检查 DNS 记录 TTL # 六、技术要点 ## 1. systemd-resolved 缓存机制 systemd-resolved 是现代 Linux 发行版的默认 DNS 解析器,提供本地 DNS 缓存功能。 ### A. 缓存行为 - 遵循 DNS 记录的 TTL 值 - TTL 过期后自动清除缓存条目 - 不会强制延长 TTL ### B. 配置选项 | 配置项 | 默认值 | 说明 | |--------|--------|------| | Cache | yes | 启用缓存 | | CacheFromLocalhost | no | 是否缓存本地查询 | | DNSStubListener | yes | 启用 127.0.0.53 监听 | ## 2. TTL 与缓存的关系 ```mermaid graph TD A[DNS 查询] --> B{本地缓存} B -->|命中且未过期| C[返回缓存结果] B -->|未命中或已过期| D[向上游查询] D --> E[获取结果和 TTL] E --> F{TTL > 0?} F -->|是| G[存入缓存] F -->|否| H[不缓存] G --> I[返回结果] H --> I ```  ## 3. 常见 TTL 设置场景 | 场景 | 典型 TTL | 原因 | |------|----------|------| | 静态网站 | 3600-86400 秒 | IP 稳定,可长期缓存 | | CDN 服务 | 60-300 秒 | 需要动态调整流量 | | 负载均衡 | 30-60 秒 | 快速故障转移 | | 企业内网 | 0-60 秒 | 便于管理和切换 | *** ## 参考资料 1. [systemd-resolved 官方文档](https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html) 2. [resolved.conf 配置说明](https://www.freedesktop.org/software/systemd/man/resolved.conf.html) 最后修改:2026 年 01 月 30 日 © 允许规范转载 赞 如果觉得我的文章对你有用,请随意赞赏