DNS
使用 Bun 的 DNS 模块解析 DNS 记录
Bun 实现了自己的 dns 模块和 node:dns 模块。
import * as dns from "node:dns";
const addrs = await dns.promises.resolve4("bun.com", { ttl: true });
console.log(addrs);
// => [{ address: "172.67.161.226", ttl: 0 }, ...]
import { dns } from "bun";
dns.prefetch("bun.com", 443);
选择解析器后端
Bun.dns.lookup() 接受一个 backend 选项,用于选择解析器实现:
"c-ares":异步解析器 c-ares。它会直接读取/etc/resolv.conf,因此不会查询systemd-resolved等 NSS 模块。此后端是 Linux 上Bun.dns.lookup()的默认后端。"system":平台自带的解析器(macOS 上的非阻塞系统 API,以及其他平台上的线程池getaddrinfo)。此后端是 macOS、Windows 和 Android 上的默认后端。"getaddrinfo"(别名"libc"):在线程池中调用 POSIXgetaddrinfo(3)函数。
import { dns } from "bun";
const [{ address }] = await dns.lookup("example.com", { backend: "system" });
node:dns.lookup() 始终使用 "system" 后端,以匹配 Node.js,因为 Node.js 的文档说明其 dns.lookup() 会调用 getaddrinfo(3)。node:dns.resolve*() 函数使用 c-ares,与 Node.js 中的行为一致。
Bun 中的 DNS 缓存
Bun 会缓存 DNS 查找结果,从而加快与同一主机的重复连接。
缓存最多保存 256 个条目,每个条目的最长有效期为 30 秒。如果与某个主机的连接失败,Bun 会从缓存中移除该主机的条目。与同一主机的并发连接会共享一次 DNS 查找。
Bun 会在以下场景中自动使用此缓存:
bun installfetch()node:http(客户端)Bun.connectnode:netnode:tls
什么时候应该预获取 DNS 记录?
Web 浏览器提供了 <link rel="dns-prefetch">,可以在需要之前解析主机名。在 Bun 中,dns.prefetch 的作用相同:当你知道很快就会连接到某个主机,并希望避免首次 DNS 查找时,可以使用它。
import { dns } from "bun";
dns.prefetch("my.database-host.com", 5432);
数据库驱动是一个很好的例子:在应用程序启动时预获取数据库主机的 DNS 条目。等应用程序的其余部分加载完成时,查找可能已经完成。
dns.prefetch
dns.prefetch 会在需要之前解析主机名。
dns.prefetch(hostname: string, port?: number): void;
示例:
import { dns } from "bun";
dns.prefetch("bun.com", 443);
//
// ... 过一段时间 ...
await fetch("https://bun.sh");
dns.getCacheStats()
dns.getCacheStats() 将当前缓存统计信息作为对象返回,该对象包含以下属性:
{
cacheHitsCompleted: number; // 已完成的缓存命中次数
cacheHitsInflight: number; // 进行中的缓存命中次数
cacheMisses: number; // 缓存未命中次数
size: number; // DNS 缓存条目数
errors: number; // 连接失败次数
totalCount: number; // 总连接请求次数(包含缓存命中和未命中)
}
示例:
import { dns } from "bun";
const stats = dns.getCacheStats();
console.log(stats);
// => { cacheHitsCompleted: 0, cacheHitsInflight: 0, cacheMisses: 0, size: 0, errors: 0, totalCount: 0 }
配置 DNS 缓存 TTL
Bun 默认会将 DNS 条目缓存 30 秒。若要更改 TTL,请设置 $BUN_CONFIG_DNS_TIME_TO_LIVE_SECONDS 环境变量。例如,以下命令会将其设置为 5 秒:
BUN_CONFIG_DNS_TIME_TO_LIVE_SECONDS=5 bun run my-script.ts
为什么默认是 30 秒?
底层的系统 API(getaddrinfo)不会公开 DNS 条目的 TTL,因此 Bun 必须自行选择一个数值。我们选择 30 秒,是因为这个时长足以体现缓存的优势,同时又足够短,在 DNS 条目发生变化时不太可能造成问题。Amazon Web Services 建议 Java 虚拟机使用 5 秒,不过 JVM 的默认设置是无限期缓存。