6

我们使用 Ruby 中的 rest-client gem 来自动测试我们的 REST API。但是我注意到,在它发出的每一个请求中,它都会对主机名进行 DNS 查找。在本地环境中,如果使用“localhost”,测试会运行得很快,但如果使用正确的主机名,它们会花费 2.5 倍的时间,执行大量的 DNS 查找。

我相信这个问题与 rest-client 无关,而是与基本的 Ruby 网络有关。我试过要求'resolv'和'resolv-replace',但它们没有帮助。'dig' 报告 DNS 查询的 TTL 为 1 小时。

有没有办法让 Ruby 缓存 DNS 请求?我可以更改代码以明确使用 IP 地址,但这是解决问题的错误位置。

我正在运行 Ubuntu 12.04 和 Ruby 1.9.3。

4

4 回答 4

2

您可以使用 dnsruby gem 将名称解析为地址,然后在调用中使用该地址。

#! /usr/bin/env ruby

# Gets the IP address of a host.

require 'dnsruby'  # gem install dnsruby first, of course

def hostname_to_ip_addr(host_name)
  query = Dnsruby::Message.new(host_name)
  response = Dnsruby::Resolver.new.send_message(query)
  response.answer[1].address
end

host_name = 'cnn.com'
ip_addr = hostname_to_ip_addr(host_name)
puts("Host name: #{host_name}, IP address: #{ip_addr}")

此要点的原始代码

于 2014-12-15T01:51:45.197 回答
2

我遇到了这个问题,寻找 ruby​​ dns 缓存以及如何resolv.rb使用 TTL 来缓存 dns 请求。

发现 dns 记录的 TTL 有点隐藏在 api 中,resolv.rb但看起来有点像这样:

def get_ip(hostname)
  dns = Resolv.new
  redis = Redis.new # storing in redis
  ip = redis.get("ip:#{hostname}") 
  return ip unless ip.nil?
  begin
    resource = dns.getresource(hostname, Resolv::DNS::Resource::IN::A)
  rescue Resolv::ResolvError
    return false
  end
  # storing in redis for only as long as the TTL allows
  redis.setex("ip:#{hostname}", resource.address.ttl, resource.address.to_s)
  resource.address.to_s # IP address as string
end

要旨

注意:使用 Redis 作为缓存。

于 2018-02-12T16:04:50.843 回答
1

操作系统通常会提供一些 dns 名称缓存,但并不总是启用。

据我了解,ruby 使用 libc 来解析名称。所以这可能会缓存每个进程的响应。不过,我并不完全确定 libc。

您可以尝试的一种可能的解决方法是在您的 ruby​​ 程序中手动将主机名解析为 ip 地址,然后使用返回的 IP 地址重复对同一主机的请求。

不过,这可能不适用于与 SSL 目标的连接。证书验证通常取决于匹配主机名。

也许有一个不错的 ruby​​ 网络套接字 gem 不使用 Net::HTTP 并且会保留它自己的 DNS 缓存。

于 2014-04-03T22:17:55.983 回答
0

我刚刚查看了其余客户端代码,它只是使用 Net::HTTP,而后者又使用 Socket。

然后一切都消失在 Ruby 解释器实现中,这是我的知识有点薄弱的地方(并且行为可能会根据您是否使用 MRI、JRuby 等而改变)

我希望 DNS 解析最终会推迟到操作系统,所以也许您的问题归结为主机上的一些奇怪的解析器配置?

于 2012-08-30T21:11:21.400 回答