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
fcntl(4, F_SETFD, FD_CLOEXEC) = 0
connect(4, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("183.60.82.98")}, 16) = 0
epoll_ctl(3, EPOLL_CTL_ADD, 4, {EPOLLIN, {u32=37374768, u64=37374768}}) = 0
sendto(4, "f\330\1\0\0\1\0\0\0\0\0\0\3www\5baidu\3com\0\0\1\0\1", 31, MSG_NOSIGNAL, NULL, 0) = 31
clock_gettime(CLOCK_MONOTONIC, {tv_sec=2244208, tv_nsec=659365294}) = 0
clock_gettime(CLOCK_MONOTONIC, {tv_sec=2244208, tv_nsec=659391969}) = 0
clock_gettime(CLOCK_MONOTONIC, {tv_sec=2244208, tv_nsec=659414437}) = 0
epoll_wait(3, [{EPOLLIN, {u32=37374768, u64=37374768}}], 4096, 500) = 1
clock_gettime(CLOCK_MONOTONIC, {tv_sec=2244208, tv_nsec=660754983}) = 0
recvfrom(4, "f\330\201\200\0\1\0\3\0\0\0\0\3www\5baidu\3com\0\0\1\0\1\300"..., 4097, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("183.60.82.98")}, [16]) = 90
epoll_ctl(3, EPOLL_CTL_DEL, 4, NULL) = 0
close(4) = 0
clock_gettime(CLOCK_MONOTONIC, {tv_sec=2244208, tv_nsec=660917518}) = 0
write(1, "110.242.68.4", 12110.242.68.4) = 12