转:原文:http://hambut.com/2016/09/09/how-to-resolve-the-domain-name-in-openresty/?utm_source=tuicool&utm_medium=referral

为什么我们的域名不能被解析

最近经常有朋友在使用一个域名地址时发现无法被正确解析

比如在使用Mysql实例时某些云会给一个私有的域名搭配自有的nameserver使用

  1. 1
    2
    3
    4
    5
    6
    7
    8
  1. local client = mysql:new()
    client:connect({
    host = "rdsmxxxxxx.mysql.rds.xxxx.com",
    port = 3306,
    database = "test",
    user = "test",
    password = "123456"
    })

以上代码在直接使用时往往会报一个无法解析的错误。那么怎么在openresty中使用域名呢

搭配 resolver 指令

我们可以直接在 nginx 的配置文件中使用 resolver 指令直接设置使用的 nameserver 地址。

官方文档中是这么描述的

  1. 1
  1. Syntax: resolver address ... [valid=time] [ipv6=on|off];
  2. Default:
  3. Context: http, server, location

一个简单的例子

  1. 1
  1. resolver 8.8.8.8 114.114.114.114 valid=3600s;

不过这样的问题在于nameserver被写死在配置文件中,如果使用场景比较复杂或有内部dns服务时维护比较麻烦。

进阶玩法

我们的代码常常运行在各种云上,为了减少维护成本,我采用了动态读取本机/etc/resolv.conf的方法来做。

废话不说,让我们一睹为快。

  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
  1. local pcall = pcall
    local io_open = io.open
    local ngx_re_gmatch = ngx.re.gmatch
  2.  
  3. local ok, new_tab = pcall(require, "table.new")
  4.  
  5. if not ok then
    new_tab = function (narr, nrec) return {} end
    end
  6.  
  7. local _dns_servers = new_tab(5, 0)
  8.  
  9. local _read_file_data = function(path)
    local f, err = io_open(path, 'r')
  10.  
  11. if not f or err then
    return nil, err
    end
  12.  
  13. local data = f:read('*all')
    f:close()
    return data, nil
    end
  14.  
  15. local _read_dns_servers_from_resolv_file = function()
    local text = _read_file_data('/etc/resolv.conf')
  16.  
  17. local captures, it, err
    it, err = ngx_re_gmatch(text, [[^nameserver\s+(\d+?\.\d+?\.\d+?\.\d+$)]], "jomi")
  18.  
  19. for captures, err in it do
    if not err then
    _dns_servers[#_dns_servers + 1] = captures[1]
    end
    end
    end
  20.  
  21. _read_dns_servers_from_resolv_file()

通过上述代码我们成功动态拿到了一组nameserver的地址,下面就可以通过resty.dns.resolver大杀四方了

  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
  1. local require = require
    local ngx_re_find = ngx.re.find
    local lrucache = require "resty.lrucache"
    local resolver = require "resty.dns.resolver"
    local cache_storage = lrucache.new(200)
  2.  
  3. local _is_addr = function(hostname)
    return ngx_re_find(hostname, [[\d+?\.\d+?\.\d+?\.\d+$]], "jo")
    end
  4.  
  5. local _get_addr = function(hostname)
    if _is_addr(hostname) then
    return hostname, hostname
    end
  6.  
  7. local addr = cache_storage:get(hostname)
  8.  
  9. if addr then
    return addr, hostname
    end
  10.  
  11. local r, err = resolver:new({
    nameservers = _dns_servers,
    retrans = 5, -- 5 retransmissions on receive timeout
    timeout = 2000, -- 2 sec
    })
  12.  
  13. if not r then
    return nil, hostname
    end
  14.  
  15. local answers, err = r:query(hostname, {qtype = r.TYPE_A})
  16.  
  17. if not answers or answers.errcode then
    return nil, hostname
    end
  18.  
  19. for i, ans in ipairs(answers) do
    if ans.address then
    cache_storage:set(hostname, ans.address, 300)
    return ans.address, hostname
    end
    end
  20.  
  21. return nil, hostname
    end
  22.  
  23. ngx.say(_get_addr("www.baidu.com"))
    ngx.say(_get_addr("192.168.0.1"))

我这边把解析的结果放入了lrucache缓存了5分钟,你们同样可以把结果放入shared中来减少worker查询次数。

高阶玩法

现在我们已经实现了自缓存体系的dns查询,如果搭配resty.http就会达到更好的效果。

一个简单的例子是,通过解析uri得到hostnameportpath,把hostname扔给自缓存dns获取结果

发起request请求,addr + port connect 之,设置headerhosthostname, path等值来实现ip直接访问等高阶用法。

这里就不过多的阐述了。

最终的演示例子如下

  1. 1
    2
    3
    4
    5
    6
    7
    8
  1. local client = mysql:new()
    client:connect({
    host = _get_addr(conf.mysql_hostname),
    port = 3306,
    database = "test",
    user = "test",
    password = "123456"
    })

如何使用 /etc/hosts 自定义域名

还有些同学可能会在hosts文件中自定义域名和ip,这时候resolve是无法正常解析的。

这个时候可以借助dnsmasq这个服务来缓存我们的dns结果,而且hosts文件中的定义可以被该服务识别。

需要在nginx的配置文件中,设置resolverdnsmasq服务的监听地址即可。

如何在openresty里解析域名的更多相关文章

  1. 启动phpstyle Apache的80端口被win7的System PID=4的进程占用的解决方法 以及 如何在phpStyle里发布程序

    学习前端是,用到Ajax,php语言,操作mysql数据库,浏览器无法解析php代码(把源码输出):原因,我之前用的是tomcat服务器写jsp,servlet,php用的是apache服务器,没有配 ...

  2. 阿里云 云解析使用方法/在阿里云ESC服务器解析域名并绑定服务器IP后上传文件通过域名访问步骤教程

    第一步:登录阿里云官网,获取服务器ECS的指定公网IP地址. 1.输入阿里云官网账号进入首页,如下图: 2.点击进入"管理控制台",如下图: 3.点击"云服务器ECS&q ...

  3. python解析域名

    #coding:utf-8 import socket def URL2IP(): for oneurl in urllist.readlines(): url=str(oneurl.strip()) ...

  4. Linux下解析域名命令-dig 命令使用详解

    Linux下解析域名除了使用nslookup之外,开可以使用dig命令来解析域名,dig命令可以得到更多的域名信息.dig 命令主要用来从 DNS 域名服务器查询主机地址信息.dig的全称是 (dom ...

  5. DNS解析域名的过程

    一.DNS解析域名的过程 1.大的过程可分为三步: (1).在缓存中查找是否之前解析过 (2).在windows系统的host文件中查找 (3).请求DNS服务器 2.小的过程可分为十步: (1).浏 ...

  6. 使用adns库解析域名

    1. adns.adns-python库简介 adns库是一个可进行异步非阻塞解析域名的库,主要使用C语言编写,在linux平台下运行.使用adns库进行域名解析效率非常,著名的开源网络爬虫larbi ...

  7. linux服务器wget无法成功解析域名及程序获取外网数据不稳定问题

    1.问题描述: 1.1 最近发现通过linux服务器wget下载远程文件经常提示无法解析域名问题,要重复多次才能成功,成功率比较低. 1.2 PHP用file_get_contents()函数获取淘宝 ...

  8. 如何在BIOS里设置定时关机?

    如何在BIOS里设置定时关机? 通过CMOS设置实现定时开机的设置过程如下: 首先进入"CMOS SETUP"程序(大多数主板是在计算机启动时按DEL键进入): 然后将光条移到&q ...

  9. SpringBoot之解决云服务器VPS在所处云端集群的内网不能解析域名的问题:java.net.UnknownHostException:abc.cn: Temporary failure in name resolution

    一.起因与原因分析过程 前端小伙伴儿告诉我,说服务器崩了. 请求数据接口,接口有响应,但报的json提示指向:数据库异常错误. 遂登陆云主机查看日志,核心记录显示如下: 2018-11-09 22:1 ...

随机推荐

  1. 前端之JavaScript基础

    前端之JavaScript基础 本节内容 JS概述 JS基础语法 JS循环控制 ECMA对象 BOM对象 DOM对象 1. JS概述 1.1. javascript历史 1992年Nombas开发出C ...

  2. xml解析

    config.xml <?xml version="1.0" encoding="UTF-8"?> <prize> <gift&g ...

  3. 【6年开源路】FineUI家族今日全部更新(FineUI + FineUI3to4 + FineUI.Design + AppBox)!

    刚才询问博客园团队: [6年开源路]三石今日送福利,AppBox4.0源码免费拿!FineUI家族今日全部更新(FineUI + FineUI3to4 + FineUI.Design + AppBox ...

  4. JS组件系列——Bootstrap组件福利篇:几款好用的组件推荐(二)

    前言:上篇 JS组件系列——Bootstrap组件福利篇:几款好用的组件推荐 分享了几个项目中比较常用的组件,引起了许多园友的关注.这篇还是继续,因为博主觉得还有几个非常简单.实用的组件,实在不愿自己 ...

  5. .NET跨平台之旅:在Linux上以本地机器码(native)运行ASP.NET Core站点

    在将“.NET跨平台之旅”示例站点 about.cnblogs.com 从 ASP.NET 5 RC1 升级至 ASP.NET Core 1.0 (博文链接)之后,我们有一个难以抗拒的冲动 —— 体验 ...

  6. go interface

    //所有的结构体 都实现了空接口 //接口类型转换 结构体变量 = 接口名(实现接口的结构体变量) 只能高级转为低级 就是转前的接口中方法在转后接口中都有实现 package main import ...

  7. go channel

    channel 是go语言中不同goroutine之间通信一种方法 //定义一个channel c := make(chan bool) //向channel中写入 c <- true //读取 ...

  8. async & await 的前世今生

    async 和 await 出现在C# 5.0之后,给并行编程带来了不少的方便,特别是当在MVC中的Action也变成async之后,有点开始什么都是async的味道了.但是这也给我们编程埋下了一些隐 ...

  9. Java连接远程Redis

    redis-server &  //后台启动redis redis-cli //使用redis   打开redis.conf文件在NETWORK部分有说明   /usr/local/src   ...

  10. JavaScript函数表达式、闭包、模仿块级作用域、私有变量

    函数表达式是一种非常有用的技术,使用函数表达式可以无需对函数命名,从而实现动态编程.匿名函数,是一种强大的方式,一下总结了函数表达式的特点: 1.函数表达式不同于函数声明,函数声明要求有名字,但函数表 ...