c-ares 是什么?
c-ares 是一个异步 DNS 解析库。 它适用于需要在不阻塞的情况下执行 DNS 查询或需要并行执行多个 DNS 查询的应用程序。
默认不开启,如需开启,需要在编译 Swoole 时增加 --enable-cares
参数
gethostbyname
在之前的版本中 Coroutine\System::gethostbyname
是基于同步的线程池模拟实现,底层自动进行协程调度,
依赖操作系统和 AIO 线程池,导致并发能力较弱,而启用 c-ares 之后会变成纯异步 IO 的。
启用 c-ares 之后,所有的网络客户端在解析域名时都会使用 c-ares ,包括 Redis、MySQL、HttpClient ,以及 PHP 的 Hook stream、sockets 之类
dnsLookup
函数原型:
Swoole\Coroutine\System::dnsLookup(string$domain, float$timeout = 5): string|false
与 Coroutine\System::gethostbyname
不同,Coroutine\System::dnsLookup
是基于 Co\Socket UDP 客户端自行实现的 DNS 协程客户端,
底层是异步 IO,而不是使用 libc 提供的 gethostbyname
函数。在开启 c-ares 之后也会被替换成 c-ares 实现。
此函数在 Swoole 版本 >= v4.4.3
时可用,底层会读取 /etc/resolve.conf
获取 DNS 服务器地址,之前版本中仅支持 AF_INET(IPv4)
域名解析,此版本中对于 IPv6 也增加了支持
对于 Coroutine\System::dnsLookup
增加了第三个参数,用于选择 IPv4 (AF_INET
) 还是 IPv6 (AF_INET6
),默认为 IPv4
Swoole\Coroutine\System::dnsLookup(string $domain, float $timeout = 5, int $type = AF_INET): string|false
示例代码
- IPv6
use Swoole\Coroutine\System; use function Swoole\Coroutine\run; run(function () { var_dump(System::dnsLookup('www.taobao.com', 3, AF_INET6)); });
strace 日志
启用 c-ares 之后会变成纯异步 IO,以下为 strace 日志
use Swoole\Coroutine\System; use function Swoole\Coroutine\run; run(function () { $ip = System::gethostbyname("www.taobao.com", AF_INET, 0.5); echo $ip; }); epoll_create(512) = 3 clock_gettime(CLOCK_MONOTONIC, {tv_sec=2244208, tv_nsec=658303392}) = 0 mmap(NULL, 2101248, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4173b8c000 clock_gettime(CLOCK_MONOTONIC, {tv_sec=2244208, tv_nsec=658417744}) = 0 open("/etc/resolv.conf", O_RDONLY) = 4 fstat(4, {st_mode=S_IFREG|0644, st_size=89, ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f41832b9000 read(4, "; generated by /usr/sbin/dhclien"..., 4096) = 89 read(4, "", 4096) = 0 close(4) = 0 munmap(0x7f41832b9000, 4096) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f41832b9000 read(4, "t\205\3006 \273`\271\375\377\273\376\261a\246VP\304Y-\4[\20619@\370\23N\1\223>"..., 4096) = 4096 close(4) = 0 munmap(0x7f41832b9000, 4096) = 0 open("/etc/hosts", O_RDONLY) = 4 fstat(4, {st_mode=S_IFREG|0644, st_size=242, ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f41832b9000 read(4, "127.0.0.1 VM-32-17-centos VM-32-"..., 4096) = 242 read(4, "", 4096) = 0 close(4) = 0 munmap(0x7f41832b9000, 4096) = 0 clock_gettime(CLOCK_MONOTONIC, {tv_sec=2244208, tv_nsec=659074426}) = 0 socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 4 fcntl(4, F_GETFL) = 0x2 (flags O_RDWR) fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0