乐趣区

关于php:Swoole-v47-版本预览之支持-cares

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

退出移动版