gpt4 book ai didi

ruby - 为什么 UDPSocket.send 在 Ruby 中总是调用 getaddrinfo?

转载 作者:数据小太阳 更新时间:2023-10-29 08:06:43 25 4
gpt4 key购买 nike

我刚刚解决了基础架构中的一个延迟问题,该问题是由于此处的代码片段在每次运行代码时触发了对 getaddrinfo 的调用而触发的:

sock = UDPSocket.open
sock.send("#{key}|#{value}", 0,
GRAPHITE_SERVER,
STATSD_PORT)
sock.close

因为我们使用 statsd and graphite对于大容量事件和统计数据监控,我们在每次 API 调用时有效地触发了大量调用 getaddrinfo,并且每分钟可能触发数万次。

我修改了这段代码以使用我们的 Graphite 服务器的内部 IP 地址,而不是 DNS 名称,并且能够解决延迟问题(大概是因为内部 AWS VPC DNS 服务器没有配备来处理如此高的容量的请求)。

既然我的问题已经解决,我很想知道为什么 Ruby 中的 UDP 实现没有使用缓存的 IP 地址值(大概基于域名条目的 TTL)。 Here is the relevant line以及完整的功能,您可以看到对 rsock_addrinfo 的调用就在最后:

static VALUE
udp_send(int argc, VALUE *argv, VALUE sock)
{
VALUE flags, host, port;
struct udp_send_arg arg;
VALUE ret;

if (argc == 2 || argc == 3) {
return rsock_bsock_send(argc, argv, sock);
}
rb_scan_args(argc, argv, "4", &arg.sarg.mesg, &flags, &host, &port);

StringValue(arg.sarg.mesg);
GetOpenFile(sock, arg.fptr);
arg.sarg.fd = arg.fptr->fd;
arg.sarg.flags = NUM2INT(flags);
arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0);
ret = rb_ensure(udp_send_internal, (VALUE)&arg,
rsock_freeaddrinfo, (VALUE)arg.res);
if (!ret) rsock_sys_fail_host_port("sendto(2)", host, port);
return ret;
}

我认为这个决定是有意为之的,并且很想了解更多原因。

最佳答案

getaddrinfo 不返回有关 TTL 的数据...因为实际上它可能根本没有,因为解析不一定是通过 DNS 完成的(可能是 hosts 文件,LDAP 等。参见 /etc/nsswitch.conf)

从它的手册这里是返回的结构:

int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res);

struct addrinfo {
int ai_flags; /* input flags */
int ai_family; /* protocol family for socket */
int ai_socktype; /* socket type */
int ai_protocol; /* protocol for socket */
socklen_t ai_addrlen; /* length of socket-address */
struct sockaddr *ai_addr; /* socket-address for socket */
char *ai_canonname; /* canonical name for service location */
struct addrinfo *ai_next; /* pointer to next in list */
};

After a successful call to getaddrinfo(), *res is a pointer to a linked list of one or more addrinfo structures.

因此,是否进行缓存取决于 getaddrinfo“背后”的东西,因为 getaddrinfo 可能已经使用 DNS 检索数据,也可能没有。

一些特定的 DNS API,如 getdnsapi 将返回给调用者一些关于 TTL 的信息,参见 https://getdnsapi.net/documentation/spec/和示例 6.2

6·2 Get IPv4 and IPv6 Addresses for a Domain Name

This example is similar to the previous one, except that it retrieves more information than just the addresses, so it traverses the replies_tree. In this case, it gets both the addresses and their TTLs.

在任何地方都没有任何缓存层,因为 UDP 是无状态的,任何新的发送 都必须以某种方式或形式触发解析。

你说:

"modified this code to use the internal IP address, not the DNS name"

您应该改为安装本地(在盒子上)递归缓存名称服务器,例如 unbound。您所有的本地应用程序都将受益于它,以及更快的 DNS 解析(取决于 /etc/nsswitch.conf/etc/resolv.conf/etc/hosts 也已设置)。

对于@Casper 暗示的相关错误报告,它的核心似乎更多是关于 IPv6 与 IPv4 的问题,可以通过调整 /etc/gai.conf 或等效或做更多的事情来解决围绕打开连接进行巧妙的编程,使用所谓的“快乐眼球算法”,您尝试同时解析 AAAAA 这意味着两个并行的 DNS 查询(因为你不能按照协议(protocol)将它们组合成一个)并尝试使用最快的返回,如果你想在现代阵营中稍微偏爱 AAAA 所以你会开火 A 一个仅在 AAAA 之后的给定毫秒数,以捕获您根本没有收到 AAAA 回复或否定回复的情况.参见 RFC6555了解详情。

关于ruby - 为什么 UDPSocket.send 在 Ruby 中总是调用 getaddrinfo?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51937235/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com