在Ruby中缓存DNS查询

时间:2012-05-15 08:10:38

标签: ruby caching dns

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

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

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

我正在运行Ubuntu 12.04和Ruby 1.9.3。

4 个答案:

答案 0 :(得分:1)

您可以使用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}")
来自此Gist

原始代码

答案 1 :(得分:1)

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

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

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

Gist

注意:使用Redis作为缓存。

答案 2 :(得分:0)

我刚刚看了一下rest-client代码,它只是使用Net :: HTTP,后者又使用了Socket。

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

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

答案 3 :(得分:0)

OS通常会提供一些dns名称缓存,但并不总是启用它。

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

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

但是,对于与SSL目标的连接,这可能效果不佳。证书验证通常取决于匹配主机名。

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